through amazonian eyes: the human ecology of amazonian populations

through amazonian eyes: the human ecology of amazonian populations </h2> <div class="bibliography-actions d-flex align-items-center"> </div> </div> </div> <div class="card-body p-0"> <div class="bibliography-meta py-2 px-3 bg-light border-bottom"> <div class="row align-items-center"> <div class="col-md-9"> <div class="bibliography-authors mb-1"> ;Walter Neves </div> <div class="bibliography-source"> <span class="journal-name">iberian conference on information systems and technologies, cisti</span> <span class="year-badge">1995</span> <span class="volume-badge">Vol. 11</span> <span class="pages-badge">pp. 150-152</span> </div> </div> <div class="col-md-3 text-md-end"> <div class="bibliography-stats"> <div class="views-count" title="Number of views"> <i class="fas fa-eye"></i> <span>156</span> </div> <div class="ref-key" title="Reference Key"> <i class="fas fa-key"></i> <span>neves1995cadernos<title</span> </div> </div> </div> </div> </div> <!-- Abstract Section --> <!-- Keywords Section --> <div class="bibliography-keywords px-4 pb-4"> <h4 class="section-title"> <i class="fas fa-tags me-2"></i> Keywords </h4> <div class="keywords-list"> <a href="https://scimatic.org/keyword_connections/125516" class="keyword-tag"> medicinepublic aspects of medicine </a> </div> </div> <!-- Citation and Links Section --> <div class="bibliography-details p-4 bg-light"> <div class="row"> <!-- DOI and URL Links --> <div class="col-md-6 mb-3 mb-md-0"> <h4 class="section-title"> <i class="fas fa-link me-2"></i> Access </h4> <div class="resource-links"> <div class="resource-link"> <div class="link-label">DOI:</div> <a href="https://doi.org/10.1590/S0102-311X1995000100023" target="_blank" class="external-link"> 10.1590/S0102-311X1995000100023 <i class="fas fa-external-link-alt ms-1"></i> </a> </div> <div class="resource-link"> <div class="link-label">URL:</div> <a href="http://www.scielo.br/scielo.php?script=sci_arttext&pid=S0102-311X1995000100023" target="_blank" class="external-link"> http://www.scielo.br/scielo.php?script=sci_arttext... <i class="fas fa-external-link-alt ms-1"></i> </a> </div> </div> </div> <!-- Citation Info --> <div class="col-md-6"> <h4 class="section-title"> <i class="fas fa-quote-right me-2"></i> Citation </h4> <div class="citation-info"> <div class="citation-field"> <span class="field-label">ID:</span> <span class="field-value">128755</span> </div> <div class="citation-field"> <span class="field-label">Ref Key:</span> <span class="field-value">neves1995cadernos<title</span> <div class="ref-key-info"> Use this key to autocite in <a href="https://scimatic.org" target="_blank">SciMatic</a> or <a href="https://thesismanager.com" target="_blank">Thesis Manager</a> </div> </div> </div> </div> </div> </div> <!-- Raw Reference --> </div> </div> <!-- References Section --> <div class="card border-0 shadow-sm rounded-lg mb-4"> <div class="card-header bg-gradient-secondary text-white py-3"> <h4 class="mb-0"> <i class="fas fa-book me-2"></i> References </h4> </div> <div class="card-body"> <div class="card-footer"> <div> <h4> References </h4> </div> No Bibliography </div> </div> </div> <!-- Citations Section --> </div> <!-- Sidebar Column --> <div class="col-lg-4"> <!-- Blockchain Card --> <div class="card border-0 shadow-sm rounded-lg mb-4"> <div class="card-header bg-gradient-blockchain text-white py-3"> <h4 class="mb-3 text-center"> <i class="fas fa-link me-2"></i> Blockchain Verification </h4> <!-- Balance Display (centered) --> <div id="headerBalanceBadge" class="text-center mb-3" style="display: none;"> <span class="badge bg-success fs-6"> <i class="fas fa-coins me-1"></i> <span id="headerBalanceValue">0</span> tokens </span> </div> <!-- Buttons (centered) --> <div class="d-flex flex-wrap gap-2 justify-content-center"> <button class="btn btn-light btn-sm" onclick="checkTokenInfo()"> <i class="fas fa-check-circle me-1"></i> Verify </button> <button class="btn btn-warning btn-sm" id="addToMetaMaskBtn" style="display: none;" onclick="addNFTToMetaMask()"> <i class="fas fa-wallet me-1"></i> MetaMask </button> <button id="sendTokensBtn" class="btn btn-info btn-sm" style="display: none;" onclick="openSendTokensModal()"> <i class="fas fa-paper-plane me-1"></i> Send </button> </div> </div> <div class="card-body"> <span> Account: <button class="enableEthereumButton" id="enableEthereumButton">Connect Metamask</button> <a style="display:none" class="addSCIButton" id="addSCIButton"> <img onclick="addTokenFunction_1()" src="https://scimatic.org/storage/web/metamask1.png" alt="metamask" width="30em"> </a> </span> <small><span class="showAccount"></span></small> <script> const ethereumButton = document.querySelector('.enableEthereumButton'); const addSCIButton = document.querySelector('.addSCIButton'); const showAccount = document.querySelector('.showAccount'); document.getElementById('enableEthereumButton').innerText = "Connect Metamask"; function reloadPage() { window.location.reload(); } if (typeof window.ethereum !== 'undefined') { console.log('MetaMask is installed!'); addSCIButton.style.display = "inline"; const isMetaMaskConnected = async () => { const accounts = await ethereum.request({ method: 'eth_requestAccounts' }); console.log('Connection checking....') return accounts.length > 0; } isMetaMaskConnected().then((connected) => { if (connected) { // Get accounts getAccount(); } else { // Metamask is not connected console.log('MetaMask is not connected!'); ethereumButton.innerHTML = "Connect Metamask"; } }); addSCIButton.addEventListener('click', () => { const chainId = '0x1e1'; // Hexadecimal representation of the chain id (481) const rpcUrl = 'https://rpc.scimatic.net'; const logoUrl = 'https://scimatic.org/storage/web/logo.png'; // URL to the SciChain logo try { ethereum.request({ method: 'wallet_addEthereumChain', params: [ { chainId, chainName: 'SciChain', rpcUrls: [rpcUrl], iconUrls: [logoUrl], // Add the logo URL here }, ], }).then(() => { console.log('SciChain added to MetaMask!'); }); } catch (error) { console.log(error); } }); ethereumButton.addEventListener('click', () => { // Get accounts getAccount(); }); async function getAccount() { const accounts = await ethereum.request({ method: 'eth_requestAccounts' }); const account = accounts[0]; ethereumButton.innerHTML = account.substring(0, 10) + '...'; ethereumButton.classList.add('btn'); ethereumButton.classList.add('btn-sm'); ethereumButton.classList.add("btn-info"); console.log('MetaMask is connected!'); } // Refresh the page when the MetaMask account changes window.ethereum.on('accountsChanged', function (accounts) { console.log('Account changed'); showAccount.innerHTML = ""; ethereumButton.innerHTML = "Connect Metamask"; ethereumButton.classList.remove('btn'); ethereumButton.classList.remove('btn-sm'); ethereumButton.classList.remove("btn-success"); reloadPage(); }); // Refresh the page when the MetaMask network changes window.ethereum.on('chainChanged', function (chainId) { console.log('Network changed'); showAccount.innerHTML = ""; ethereumButton.innerHTML = "Connect Metamask"; ethereumButton.classList.remove('btn'); ethereumButton.classList.remove('btn-sm'); ethereumButton.classList.remove("btn-success"); reloadPage(); }); } else { document.getElementById('enableEthereumButton').innerText = "Install Metamask"; ethereumButton.classList.add('btn'); ethereumButton.classList.add('btn-sm'); ethereumButton.classList.add("btn-warning"); console.log('MetaMask is not installed!'); } window.ethereum.on('accountsChanged', function (accounts) { console.log('Account changed'); showAccount.innerHTML = ""; ethereumButton.innerHTML = "Connect Metamask"; ethereumButton.classList.remove('btn'); ethereumButton.classList.remove('btn-sm'); ethereumButton.classList.remove("btn-success"); }); </script> <div class="blockchain-info"> <div class="info-row"> <div class="info-label">NFT Contract Address:</div> <div class="info-value token-address">0x95644003c57E6F55A65596E3D9Eac6813e3566dA</div> </div> <div class="info-row"> <div class="info-label">Article ID:</div> <div class="info-value">128755</div> </div> <div class="info-row"> <div class="info-label">Unique Identifier:</div> <div class="info-value hash-value">10.1590/S0102-311X1995000100023</div> </div> <div class="info-row"> <div class="info-label">Network:</div> <div class="info-value">Scimatic Chain (ID: 481)</div> </div> <div class="info-row" id="tokenIdRow" style="display: none;"> <div class="info-label">Token ID:</div> <div class="info-value" id="tokenIdValue"></div> </div> </div> <div id="spinner" class="text-center mt-3 d-none"> <div class="spinner-grow text-primary" role="status"> <span class="sr-only">Loading...</span> </div> </div> <div id="result" class="mt-4"> <h5 class="checklist-title">Blockchain Readiness Checklist</h5> <div class="checklist"> <div class="checklist-item completed"> <i class="fas fa-check-circle"></i> <span>Authors</span> </div> <div class="checklist-item missing"> <i class="fas fa-times-circle"></i> <span>Abstract</span> </div> <div class="checklist-item completed"> <i class="fas fa-check-circle"></i> <span>Journal Name</span> </div> <div class="checklist-item completed"> <i class="fas fa-check-circle"></i> <span>Year</span> </div> <div class="checklist-item completed"> <i class="fas fa-check-circle"></i> <span>Title</span> </div> </div> <div class="checklist-score"> <div class="progress"> <div class="progress-bar bg-warning" role="progressbar" style="width: 80%" aria-valuenow="4" aria-valuemin="0" aria-valuemax="5"> 4/5 </div> </div> </div> </div> <!-- Blockchain Actions Section --> <div class="blockchain-actions mt-4"> <div class="incomplete-checklist alert alert-warning d-flex align-items-center"> <i class="fas fa-exclamation-triangle me-3 fa-2x"></i> <div> <strong>Blockchain Upload Locked</strong> <p class="mb-0">Complete all 5 checklist items to tokenize your article</p> </div> </div> </div> </div> <!-- Updated Cost Info Section --> <div class="card-footer bg-light p-3"> <div class="cost-info d-flex align-items-center justify-content-between"> <div class="d-flex align-items-center"> <i class="fas fa-gas-pump me-2 text-primary"></i> <span class="text-muted"> Gas fees required in <strong class="text-dark ms-1">SCI Coins</strong> </span> </div> <a href="https://scimatic.net/en/sale/0" class="btn btn-sm btn-outline-success d-flex align-items-center"> <i class="fas fa-shopping-cart me-1"></i> Buy SCI </a> </div> </div> </div> <!-- Saymatik Wallet Card --> <div class="card border-0 shadow-sm rounded-lg"> <div class="card-header bg-light"> <h4 class="mb-0"> <i class="fas fa-wallet me-2"></i> Saymatik Web3.0 Wallet </h4> </div> <div class="card-body p-0"> <!-- Updated Wallet Download Section --> <div class="saymatik-app p-4 text-center"> <div class="row"> <div class="col-6"> <div class="platform-section"> <div class="platform-icon bg-android mb-3"> <i class="fab fa-android"></i> </div> <a href="https://play.google.com/store/apps/details?id=com.scimatic.saymatik" class="btn btn-outline-success btn-sm d-flex align-items-center justify-content-center"> <i class="fab fa-google-play me-2"></i> Google Play </a> </div> </div> <div class="col-6"> <div class="platform-section"> <div class="platform-icon bg-ios mb-3"> <i class="fab fa-apple"></i> </div> <a href="https://apps.apple.com/tr/app/saymatik-web3-0-wallet/id6444104653" class="btn btn-outline-dark btn-sm d-flex align-items-center justify-content-center"> <i class="fab fa-app-store-ios me-2"></i> App Store </a> </div> </div> </div> </div> </div> </div> </div> </div> </div> <!-- Include Modals --> <!-- Load QR Scanner Library from CDN --> <script src="https://unpkg.com/html5-qrcode@2.3.8/html5-qrcode.min.js"></script> <!-- Send Tokens Modal --> <div class="modal fade" id="sendTokensModal" tabindex="-1" aria-labelledby="sendTokensModalLabel" aria-hidden="true"> <div class="modal-dialog modal-dialog-centered"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="sendTokensModalLabel"> <i class="fas fa-paper-plane me-2"></i>Send Article Tokens </h5> <button type="button" class="btn-close" onclick="closeSendTokensModal()" aria-label="Close"></button> </div> <div class="modal-body"> <div class="alert alert-info d-flex align-items-center mb-3" role="alert"> <i class="fas fa-info-circle me-2"></i> <div> <strong>Token ID:</strong> <span id="modalTokenId"></span><br> <strong>Your Balance:</strong> <span id="modalTokenBalance">Loading...</span> tokens </div> </div> <form id="sendTokensForm"> <div class="mb-3"> <label for="recipientAddress" class="form-label">Recipient Address</label> <div class="input-group"> <input type="text" class="form-control" id="recipientAddress" placeholder="0x..." required pattern="^0x[a-fA-F0-9]{40}$" title="Please enter a valid Ethereum address"> <button class="btn btn-outline-secondary" type="button" onclick="openQRScanner()" title="Scan QR Code"> <i class="fas fa-qrcode"></i> </button> </div> <div class="form-text">Enter the wallet address or scan QR code</div> </div> <div class="mb-3"> <label for="tokenAmount" class="form-label">Amount</label> <input type="number" class="form-control" id="tokenAmount" placeholder="Enter amount" required min="1" step="1"> <div class="form-text">Number of tokens to send</div> </div> <div class="d-grid gap-2"> <button type="submit" class="btn btn-success" id="confirmSendBtn"> <i class="fas fa-check-circle me-2"></i>Send Tokens </button> <button type="button" class="btn btn-secondary" onclick="closeSendTokensModal()"> Cancel </button> </div> </form> <div id="sendTokensSpinner" class="text-center mt-3 d-none"> <div class="spinner-border text-primary" role="status"> <span class="visually-hidden">Processing...</span> </div> <p class="mt-2">Sending tokens...</p> </div> </div> </div> </div> </div> <!-- QR Scanner Modal --> <div class="modal fade" id="qrScannerModal" tabindex="-1" aria-hidden="true"> <div class="modal-dialog modal-dialog-centered"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title"> <i class="fas fa-camera me-2"></i>Scan QR Code </h5> <button type="button" class="btn-close" onclick="closeQRScanner()" aria-label="Close"></button> </div> <div class="modal-body text-center"> <div id="qrReaderDiv" style="width: 100%;"></div> <div id="qrReaderFallback" class="d-none"> <p class="text-muted">QR Scanner requires camera access.</p> <input type="file" id="qrFileInput" accept="image/*" onchange="handleQRFile(event)" class="form-control mb-3"> <p class="text-muted">Or manually enter the address</p> </div> <div id="qrResult" class="mt-3 d-none"> <div class="alert alert-success"> <strong>Address detected:</strong> <div id="detectedAddress" class="font-monospace small"></div> </div> </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" onclick="closeQRScanner()">Cancel</button> <button type="button" class="btn btn-primary d-none" id="useAddressBtn" onclick="useScannedAddress()"> Use This Address </button> </div> </div> </div> </div> <!-- Modal Styles --> <style> #sendTokensModal .modal-content, #qrScannerModal .modal-content { border-radius: 12px; border: none; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2); } #sendTokensModal .modal-header { background: linear-gradient(135deg, #4834d4, #3721b0); color: white; border-radius: 12px 12px 0 0; border: none; } #qrScannerModal .modal-header { background: linear-gradient(135deg, #0C356A, #1a53a1); color: white; border-radius: 12px 12px 0 0; border: none; } #sendTokensModal .btn-close, #qrScannerModal .btn-close { filter: brightness(0) invert(1); } #sendTokensModal .form-control { border-radius: 8px; border: 2px solid #e2e8f0; padding: 0.75rem; transition: all 0.3s ease; } #sendTokensModal .form-control:focus { border-color: #4834d4; box-shadow: 0 0 0 0.2rem rgba(72, 52, 212, 0.25); } #sendTokensModal .btn, #qrScannerModal .btn { border-radius: 8px; padding: 0.75rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; transition: all 0.3s ease; } #sendTokensModal .btn:hover, #qrScannerModal .btn:hover { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); } #sendTokensBtn { margin-left: 10px; border-radius: 8px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; } /* QR Scanner Specific Styles */ #qrReaderDiv { margin: 0 auto; max-width: 100%; } #qrReaderDiv video { border-radius: 8px; } #qr-shaded-region { border-radius: 8px; } /* Input group styling */ .input-group .btn-outline-secondary { border-color: #e2e8f0; border-left: none; transition: all 0.3s ease; } .input-group .btn-outline-secondary:hover { background-color: #4834d4; color: white; border-color: #4834d4; } .input-group .form-control { border-right: none; } .input-group .form-control:focus + .btn-outline-secondary { border-color: #4834d4; } /* QR result styling */ #detectedAddress { word-break: break-all; background-color: #f8f9fa; padding: 0.5rem; border-radius: 4px; margin-top: 0.5rem; } /* Balance display styles */ #userBalanceRow .info-value { font-weight: 600; font-size: 1.1rem; } #currentAccountRow { background-color: rgba(72, 52, 212, 0.05); padding: 0.75rem; border-radius: 8px; margin-bottom: 0.5rem; } .balance-badge { display: inline-block; background: linear-gradient(135deg, #20bf6b, #0fb9b1); color: white; padding: 0.25rem 0.75rem; border-radius: 20px; font-size: 0.85rem; font-weight: 600; margin-left: 0.5rem; } .account-badge { display: inline-block; background-color: #4834d4; color: white; padding: 0.25rem 0.75rem; border-radius: 20px; font-size: 0.85rem; font-weight: 500; } </style> <!-- Include Bibliography Modal --> <!-- Add Bibliography Modal --> <div class="modal fade" id="add_bibliography_modal" tabindex="-1" aria-labelledby="bibliographyModalLabel" aria-hidden="true"> <div class="modal-dialog modal-lg" role="document"> <div class="modal-content border-0" style="border-radius:12px;overflow:hidden"> <div class="modal-header" style="background:var(--sc-primary);color:#fff;border-bottom:none"> <h5 class="modal-title" id="bibliographyModalLabel" style="font-weight:600"> <i class="fas fa-book me-2"></i> Add Bibliography </h5> <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body"> <div class="container-fluid"> <ul class="nav nav-tabs" id="bibliographyTab" role="tablist"> <li class="nav-item" role="presentation"> <button class="nav-link active" id="add_biblio_url-tab" data-bs-toggle="tab" data-bs-target="#add_biblio_url" type="button" role="tab" aria-controls="add_biblio_url" aria-selected="true"> <i class="fas fa-link me-1"></i> URL </button> </li> <li class="nav-item" role="presentation"> <button class="nav-link" id="add_biblio_refkey-tab" data-bs-toggle="tab" data-bs-target="#add_biblio_refkey" type="button" role="tab" aria-controls="add_biblio_refkey" aria-selected="false"> <i class="fas fa-key me-1"></i> Ref-Key </button> </li> <li class="nav-item" role="presentation"> <button class="nav-link" id="add_biblio_manual-tab" data-bs-toggle="tab" data-bs-target="#add_biblio_manual" type="button" role="tab" aria-controls="add_biblio_manual" aria-selected="false"> <i class="fas fa-edit me-1"></i> Manuel </button> </li> <li class="nav-item" role="presentation"> <button class="nav-link" id="add_biblio_title-tab" data-bs-toggle="tab" data-bs-target="#add_biblio_title" type="button" role="tab" aria-controls="add_biblio_title" aria-selected="false"> <i class="fas fa-heading me-1"></i> Reference Title </button> </li> <li class="nav-item" role="presentation"> <button class="nav-link" id="add_biblio_raw-tab" data-bs-toggle="tab" data-bs-target="#add_biblio_raw" type="button" role="tab" aria-controls="add_biblio_raw" aria-selected="false"> <i class="fas fa-file-alt me-1"></i> Raw Reference </button> </li> </ul> <div class="tab-content py-3" id="bibliographyTabContent"> <!-- URL Tab --> <div class="tab-pane fade show active" id="add_biblio_url" role="tabpanel" aria-labelledby="add_biblio_url-tab"> <form id="url-form" class="bibliography-form"> <div class="mb-3"> <p class="text-muted"> Paste here the url of a reference. Fınd that article in gooogle or any search engine. If the reference has a separate page and you think it has the meta data, copy the link (url) and paste here. The reference will automatically add to your article. If not, then try to add manually. </p> <input type="url" name="url" id="url" class="form-control" required placeholder="Paste URL of the reference"> </div> <input type="hidden" name="manuscript_id" id="manuscript_id" value="128755"> <input type="hidden" name="type" id="type" value="ajax"> <button type="submit" class="btn btn-primary submit-url"> <i class="fas fa-paper-plane me-1"></i> Send </button> </form> </div> <!-- Ref-Key Tab --> <div class="tab-pane fade" id="add_biblio_refkey" role="tabpanel" aria-labelledby="add_biblio_refkey-tab"> <form id="refkey-form" class="bibliography-form"> <div class="mb-3"> <p class="text-muted"> Paste here the reference key. If you have added an article/reference in your library from scimatic.org or journament.com or manually, it must have reference key. </p> <input type="text" name="refkey" id="refkey" class="form-control" required placeholder="e.g. ghazi2019inequalityabstract"> </div> <input type="hidden" name="manuscript_id" value="128755"> <button type="submit" class="btn btn-primary submit-refkey"> <i class="fas fa-paper-plane me-1"></i> Send </button> </form> </div> <!-- Manual Tab --> <div class="tab-pane fade" id="add_biblio_manual" role="tabpanel" aria-labelledby="add_biblio_manual-tab"> <div class="text-center py-4"> <i class="fas fa-tools fa-3x mb-3 text-muted"></i> <p>Coming soon</p> </div> </div> <!-- Title Tab --> <div class="tab-pane fade" id="add_biblio_title" role="tabpanel" aria-labelledby="add_biblio_title-tab"> <div id="submit_title_div"> <form id="title-form" class="bibliography-form"> <div class="mb-3"> <p class="text-muted"> Enter your search term or the title of the manuscript. Select from the results to include the references </p> <input type="text" name="bibliography" id="bibliography" class="form-control" required placeholder=" Reference Title"> </div> <input type="hidden" name="manuscript_id" value="128755"> <input type="hidden" name="type" value="ajax"> <button type="submit" class="btn btn-primary submit-title"> <i class="fas fa-search me-1"></i> Send </button> </form> </div> <div class="card bibs-results mt-3" style="display: none"> <div class="card-header"> Select and click Save. Selected resutls will be added to your library. </div> <div id="search_term" class="p-2 bg-light"></div> <div class="card-body"> <form id="bibs-form" class="bibliography-form"> <div id="title_references" class="mb-3"></div> <input type="hidden" name="manuscript_id" value="128755"> <input type="hidden" name="type" value="ajax"> <button type="submit" class="btn btn-primary submit-bibs"> <i class="fas fa-save me-1"></i> Save </button> </form> </div> </div> </div> <!-- Raw Reference Tab --> <div class="tab-pane fade" id="add_biblio_raw" role="tabpanel" aria-labelledby="add_biblio_raw-tab"> <form id="raw-form" class="bibliography-form"> <div class="mb-3"> <label for="ref_key" class="form-label fw-semibold">Reference Key: lastname+year+titlefirstword+journalfirstword</label> <input type="text" name="ref_key" id="ref_key" class="form-control" required placeholder="e.g. smith2020synthesisjournal"> </div> <div class="mb-3"> <label for="bib_type" class="form-label fw-semibold">Article Type (Article, Book, Proceedings etc.)</label> <select name="bib_type" id="bib_type" class="form-select"> <option value="1">Research Article</option> <option value="2">Book</option> <option value="3">Conference Proceeding</option> <option value="4">Miscellaneous</option> </select> </div> <div class="mb-3"> <p class="text-muted"> Add a reference in a raw form. Our automatic system will correct it later. </p> <textarea name="raw_ref" id="raw_ref" class="form-control" rows="4" required placeholder="Paste the full reference text here"></textarea> </div> <input type="hidden" name="manuscript_id" value="128755"> <input type="hidden" name="type" value="ajax"> <button type="submit" class="btn btn-primary submit-rawref"> <i class="fas fa-paper-plane me-1"></i> Send </button> </form> </div> </div> </div> </div> </div> </div> </div> <script> $(document).ready(function(){ var CSRF_TOKEN = $('meta[name="csrf-token"]').attr('content'); var manuscriptId = null; if (manuscriptId === null) { var urlPath = window.location.pathname; var matches = urlPath.match(/\/manuscripts\/(\d+)/); if (matches && matches.length > 1) { manuscriptId = matches[1]; } } // Helper: build a ref item for the right panel function buildRefItem(refkey) { return '<div class="me-res" onclick="meInsert(\'ref\', \'' + refkey + '\')">' + '<div class="me-res-icon ref"><i class="fas fa-quote-right"></i></div>' + '<div class="me-res-info"><div class="me-res-name">' + refkey + '</div>' + '<div class="me-res-hint">Click to cite</div></div></div>'; } // Helper: notify (uses global meToast from editor, falls back to alert) function notify(msg, type) { if (typeof window.meToast === 'function') { window.meToast(msg, type); } } // Reset forms when modal opens $('#add_bibliography_modal').on('shown.bs.modal', function () { $('#submit_title_div').show(); $('#title_references').empty(); $('.bibs-results').hide(); $('.bibliography-form').trigger('reset'); }); // URL form $('.submit-url').click(function(event){ event.preventDefault(); $.ajax({ type: 'POST', url: "https://scimatic.org/get_citation", data: { url: $('#url').val(), manuscript_id: manuscriptId, type: 'ajax', _token: CSRF_TOKEN }, beforeSend: function() { $('.submit-url').prop('disabled', true).html('<i class="fas fa-spinner fa-spin"></i> Processing...'); }, success: function(msg) { $('#add_bibliography_modal').modal('hide'); $('#meRefList').append(buildRefItem(msg.refkey)); notify('Reference added successfully', 'success'); }, error: function() { $('#add_bibliography_modal').modal('hide'); notify('Error adding reference', 'error'); }, complete: function() { $('.submit-url').prop('disabled', false).html('<i class="fas fa-paper-plane me-1"></i> Send'); } }); }); // Ref-key form $('.submit-refkey').click(function(event){ event.preventDefault(); $.ajax({ type: 'POST', url: "https://scimatic.org/get_citation_refkey", data: { refkey: $('#refkey').val(), manuscript_id: manuscriptId, _token: CSRF_TOKEN }, beforeSend: function() { $('.submit-refkey').prop('disabled', true).html('<i class="fas fa-spinner fa-spin"></i> Processing...'); }, success: function(msg) { $('#add_bibliography_modal').modal('hide'); $('#meRefList').append(buildRefItem(msg.refkey)); notify('Reference added successfully', 'success'); }, error: function() { $('#add_bibliography_modal').modal('hide'); notify('Error adding reference', 'error'); }, complete: function() { $('.submit-refkey').prop('disabled', false).html('<i class="fas fa-paper-plane me-1"></i> Send'); } }); }); // Title search form $('.submit-title').click(function(event){ event.preventDefault(); $.ajax({ type: 'POST', url: "https://scimatic.org/literature_survey", data: { bibliography: $('#bibliography').val(), manuscript_id: manuscriptId, type: 'ajax', _token: CSRF_TOKEN }, beforeSend: function() { $('.submit-title').prop('disabled', true).html('<i class="fas fa-spinner fa-spin"></i> Searching...'); }, success: function(msg) { $('#submit_title_div').hide(); $('.bibs-results').show(); $('#search_term').html('<p class="mb-0"><strong>Search term:</strong> ' + msg.search_term + '</p>'); var data = jQuery.parseJSON(msg.references); $('#title_references').empty(); $.each(data, function(key, item){ var input = '<div class="form-check mb-2">' + '<input class="form-check-input" id="bib-' + item.id + '" name="bibs[]" type="checkbox" value="' + item.id + '">' + '<label class="form-check-label" for="bib-' + item.id + '">' + item.title + '</label></div>'; $('#title_references').append(input); }); }, error: function() { notify('Error searching for references', 'error'); }, complete: function() { $('.submit-title').prop('disabled', false).html('<i class="fas fa-search me-1"></i> Send'); } }); }); // Save selected bibliography items $('.submit-bibs').click(function(event){ event.preventDefault(); var biblios = []; $.each($("input[name='bibs[]']:checked"), function(){ biblios.push($(this).val()); }); if (biblios.length === 0) { notify('Please select at least one reference', 'warning'); return; } $.ajax({ type: 'POST', url: "https://scimatic.org/manuscript_bibs", data: { bibs: biblios.join(';'), manuscript_id: manuscriptId, _token: CSRF_TOKEN }, beforeSend: function() { $('.submit-bibs').prop('disabled', true).html('<i class="fas fa-spinner fa-spin"></i> Saving...'); }, success: function(msg) { $('#add_bibliography_modal').modal('hide'); var data = jQuery.parseJSON(msg.bibs); $.each(data, function(key, item){ $('#meRefList').append(buildRefItem(item)); }); notify('References added successfully', 'success'); }, error: function() { notify('Error adding references', 'error'); }, complete: function() { $('.submit-bibs').prop('disabled', false).html('<i class="fas fa-save me-1"></i> Save'); $('#submit_title_div').show(); $('.bibs-results').hide(); } }); }); // Raw reference form $('.submit-rawref').click(function(event){ event.preventDefault(); $.ajax({ type: 'POST', url: "https://scimatic.org/add_raw_biblio", data: { ref_key: $('#ref_key').val(), raw_ref: $('#raw_ref').val(), manuscript_id: manuscriptId, type: 'ajax', bib_type: $('#bib_type').val(), _token: CSRF_TOKEN }, beforeSend: function() { $('.submit-rawref').prop('disabled', true).html('<i class="fas fa-spinner fa-spin"></i> Processing...'); }, success: function(msg) { $('#add_bibliography_modal').modal('hide'); $('#meRefList').append(buildRefItem(msg.refkey)); notify('Reference added successfully', 'success'); }, error: function() { $('#add_bibliography_modal').modal('hide'); notify('Error adding reference', 'error'); }, complete: function() { $('.submit-rawref').prop('disabled', false).html('<i class="fas fa-paper-plane me-1"></i> Send'); } }); }); }); </script> <style> /* Bibliography Modal — scoped styles */ #add_bibliography_modal .nav-tabs { border-bottom: 1px solid var(--sc-border) } #add_bibliography_modal .nav-tabs .nav-link { border: none; color: var(--sc-text-muted); padding: .75rem 1rem; border-bottom: 3px solid transparent; transition: all .2s } #add_bibliography_modal .nav-tabs .nav-link:hover { color: var(--sc-text); background: #f8fafc } #add_bibliography_modal .nav-tabs .nav-link.active { color: var(--sc-primary); background: transparent; border-bottom-color: var(--sc-primary) } #add_bibliography_modal .form-control, #add_bibliography_modal .form-select { border: 1px solid var(--sc-border); border-radius: 6px; padding: .75rem; transition: all .2s } #add_bibliography_modal .form-control:focus, #add_bibliography_modal .form-select:focus { border-color: var(--sc-primary); box-shadow: 0 0 0 3px rgba(72,52,212,.1) } #add_bibliography_modal .btn-primary { background: var(--sc-primary); border-color: var(--sc-primary) } #add_bibliography_modal .btn-primary:hover { background: var(--sc-primary-dark); border-color: var(--sc-primary-dark) } #add_bibliography_modal .form-check-input:checked { background-color: var(--sc-primary); border-color: var(--sc-primary) } #add_bibliography_modal .card { border-radius: 8px; border: 1px solid var(--sc-border) } #add_bibliography_modal .card-header { background: #f8fafc; border-bottom: 1px solid var(--sc-border); font-weight: 600 } #add_bibliography_modal #title_references { max-height: 300px; overflow-y: auto } #add_bibliography_modal .tab-content > .tab-pane { display: none } #add_bibliography_modal .tab-content > .tab-pane.active { display: block } #add_bibliography_modal .tab-content > .tab-pane.show { display: block } </style> <!-- Include Styles --> <style> /* Global Variables */ :root { --primary-color: #4834d4; --primary-dark: #3721b0; --primary-light: #eef2ff; --secondary-color: #2ec4b6; --success-color: #2ecc71; --warning-color: #f39c12; --danger-color: #e74c3c; --blockchain-color: #0C356A; --text-dark: #2d3748; --text-medium: #4a5568; --text-light: #718096; --border-color: #e2e8f0; --card-shadow: 0 4px 6px rgba(0, 0, 0, 0.04), 0 1px 3px rgba(0, 0, 0, 0.08); --transition: all 0.25s ease; } /* Card Styles */ .card { box-shadow: var(--card-shadow); transition: var(--transition); border-radius: 12px; overflow: hidden; } .card-header { border-bottom: none; font-weight: 600; } .bg-gradient-primary { background: linear-gradient(135deg, var(--primary-color), var(--primary-dark)); } .bg-gradient-secondary { background: linear-gradient(135deg, #4a5568, #2d3748); } .bg-gradient-success { background: linear-gradient(135deg, #20bf6b, #0fb9b1); } .bg-gradient-blockchain { background: linear-gradient(135deg, var(--blockchain-color), #1a53a1); } /* Bibliography Header */ .bibliography-title { font-weight: 700; font-size: 1.5rem; color: white; line-height: 1.4; } .bibliography-actions { margin-left: 1rem; } .bibliography-actions .btn { text-transform: uppercase; font-weight: 600; letter-spacing: 0.5px; transition: all 0.3s ease; } .bibliography-actions .btn:hover { transform: translateY(-2px); box-shadow: 0 4px 6px rgba(0,0,0,0.1); } .bibliography-actions .btn i { margin-right: 0.3rem; } /* Bibliography Meta */ .bibliography-meta { padding: 0.75rem 1rem; color: var(--text-medium); } .bibliography-authors { font-weight: 600; color: var(--text-dark); font-size: 1.1rem; } .bibliography-source { display: flex; flex-wrap: wrap; align-items: center; gap: 0.75rem; margin-top: 0.25rem; } .journal-name { font-style: italic; } .year-badge, .volume-badge, .pages-badge { display: inline-block; padding: 0.2rem 0.5rem; background-color: var(--primary-light); color: var(--primary-color); border-radius: 4px; font-size: 0.85rem; font-weight: 500; } .bibliography-stats { display: flex; flex-direction: column; align-items: flex-end; gap: 0.5rem; } .views-count, .ref-key { display: flex; align-items: center; gap: 0.5rem; color: var(--text-medium); font-size: 0.9rem; } .views-count i, .ref-key i { color: var(--primary-color); } /* Section Styling */ .section-title { color: var(--text-dark); font-size: 1.2rem; font-weight: 600; margin-bottom: 1rem; display: flex; align-items: center; } .section-title i { color: var(--primary-color); } .bibliography-abstract, .bibliography-keywords, .raw-reference { border-bottom: 1px solid var(--border-color); } .abstract-content { color: var(--text-medium); line-height: 1.7; text-align: justify; } /* Keywords */ .keywords-list { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 0.5rem; } .keyword-tag { display: inline-block; padding: 0.35rem 0.75rem; background-color: var(--primary-light); color: var(--primary-color); border-radius: 50px; font-size: 0.85rem; text-decoration: none; transition: var(--transition); } .keyword-tag:hover { background-color: var(--primary-color); color: white; transform: translateY(-2px); text-decoration: none; } /* Citation and Links */ .resource-links { display: flex; flex-direction: column; gap: 0.75rem; } .resource-link { display: flex; flex-direction: column; } .link-label { font-weight: 600; color: var(--text-dark); font-size: 0.9rem; margin-bottom: 0.25rem; } .external-link { color: var(--primary-color); text-decoration: none; transition: var(--transition); display: inline-block; word-break: break-all; } .external-link:hover { color: var(--primary-dark); text-decoration: underline; } .missing-resource { color: var(--danger-color); font-size: 0.9rem; } .citation-info { display: flex; flex-direction: column; gap: 0.75rem; } .citation-field { display: flex; flex-direction: column; } .field-label { font-weight: 600; color: var(--text-dark); font-size: 0.9rem; margin-bottom: 0.25rem; } .field-value { display: inline-block; background-color: var(--primary-light); color: var(--primary-color); padding: 0.35rem 0.75rem; border-radius: 4px; font-family: monospace; font-size: 0.9rem; } .ref-key-info { color: var(--text-light); font-size: 0.85rem; margin-top: 0.5rem; } .ref-key-info a { color: var(--primary-color); text-decoration: none; transition: var(--transition); } .ref-key-info a:hover { color: var(--primary-dark); text-decoration: underline; } /* Raw Reference */ .raw-content { padding: 1rem; background-color: #f8fafc; border-radius: 6px; font-family: monospace; font-size: 0.9rem; color: var(--text-medium); white-space: pre-wrap; word-break: break-all; } .copy-btn { transition: var(--transition); } .copy-btn:hover { transform: translateY(-2px); } /* Blockchain Section */ .blockchain-info { background-color: #f8fafc; border-radius: 8px; padding: 1rem; margin-bottom: 1rem; } .info-row { display: flex; flex-direction: column; margin-bottom: 0.75rem; } .info-row:last-child { margin-bottom: 0; } .info-label { font-weight: 600; color: var(--text-dark); font-size: 0.9rem; margin-bottom: 0.25rem; } .info-value { font-family: monospace; word-break: break-all; font-size: 0.9rem; } .token-address, .hash-value { color: var(--blockchain-color); } .checklist-title { font-weight: 600; color: var(--text-dark); margin-bottom: 1rem; font-size: 1.1rem; } .checklist { display: flex; flex-direction: column; gap: 0.75rem; margin-bottom: 1.25rem; } .checklist-item { display: flex; align-items: center; gap: 0.75rem; padding: 0.75rem; border-radius: 6px; transition: var(--transition); } .checklist-item.completed { background-color: rgba(46, 204, 113, 0.1); } .checklist-item.missing { background-color: rgba(231, 76, 60, 0.1); } .checklist-item.completed i { color: var(--success-color); } .checklist-item.missing i { color: var(--danger-color); } .checklist-score { margin-top: 1rem; } .progress { height: 0.75rem; border-radius: 50px; background-color: #f1f5f9; } .progress-bar { border-radius: 50px; text-align: center; font-size: 0.75rem; font-weight: 600; color: white; } /* Blockchain Actions */ .btn-gradient-primary { background: linear-gradient(135deg, var(--primary-color), var(--primary-dark)); color: white; position: relative; overflow: hidden; transition: var(--transition); border: none; box-shadow: 0 4px 6px rgba(0,0,0,0.1); } .btn-gradient-primary:hover { transform: translateY(-3px); box-shadow: 0 6px 10px rgba(0,0,0,0.15); } .btn-gradient-primary .badge { position: absolute; top: -8px; right: -8px; font-size: 0.7rem; padding: 0.25rem 0.5rem; border-radius: 50px; } .incomplete-checklist { background-color: #fff3cd; border-left: 4px solid #ffc107; padding: 1rem; border-radius: 0.25rem; } .incomplete-checklist i { color: #ffc107; } .action-info, .qr-info { color: var(--text-light); font-size: 0.85rem; font-style: italic; } .qr-code img { border: 1px solid var(--border-color); border-radius: 8px; padding: 0.5rem; background-color: white; cursor: pointer; transition: var(--transition); } .qr-code img:hover { transform: scale(1.05); } /* Cost Info */ .cost-info { font-size: 0.9rem; padding: 0.5rem 1rem; color: var(--text-medium); display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 0.5rem; } .cost-info i { font-size: 1.2rem; } .cost-info .btn { font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; border-width: 2px; } .cost-info .btn i { font-size: 1rem; margin-right: 0.3rem; } /* Saymatik Wallet */ .saymatik-app { padding: 1.5rem; } .platform-section { display: flex; flex-direction: column; align-items: center; } .platform-icon { width: 80px; height: 80px; border-radius: 20px; display: flex; align-items: center; justify-content: center; margin: 0 auto 1rem; box-shadow: 0 4px 6px rgba(0,0,0,0.1); transition: transform 0.3s ease; } .platform-icon:hover { transform: scale(1.05); } .platform-icon i { font-size: 3rem; color: white; } .bg-android { background: linear-gradient(135deg, #78c257, #45a048); } .bg-ios { background: linear-gradient(135deg, #333, #666); } .platform-section .btn { font-weight: 600; text-transform: uppercase; letter-spacing: 0.5px; padding: 0.5rem 1rem; border-width: 2px; } .platform-section .btn i { font-size: 1.2rem; } /* Gap utility for flexbox (if Bootstrap 4) */ .gap-2 { gap: 0.5rem; } /* Responsive adjustments for header */ @media (max-width: 576px) { .bg-gradient-blockchain h4 { font-size: 1.1rem; } .bg-gradient-blockchain .btn-group-sm .btn { padding: 0.25rem 0.5rem; font-size: 0.875rem; } #headerBalanceBadge { font-size: 0.875rem; } } /* Button hover effects */ .bg-gradient-blockchain .btn { transition: all 0.2s ease; } .bg-gradient-blockchain .btn:hover { transform: translateY(-1px); box-shadow: 0 2px 4px rgba(0,0,0,0.2); } /* Balance badge animation */ #headerBalanceBadge { animation: fadeIn 0.3s ease-in; } @keyframes fadeIn { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: translateY(0); } } /* Ensure proper spacing in button group */ .btn-group-sm > .btn { margin: 0 !important; } /* Responsive Adjustments */ @media (max-width: 991.98px) { .bibliography-title { font-size: 1.3rem; } .bibliography-actions { margin-left: 0; margin-top: 1rem; } .field-value, .raw-content { font-size: 0.85rem; } .section-title { font-size: 1.1rem; } } @media (max-width: 767.98px) { .bibliography-stats { margin-top: 1rem; flex-direction: row; justify-content: flex-start; gap: 1.5rem; } .bibliography-meta .col-md-3 { text-align: left !important; } .platform-section { margin-bottom: 1.5rem; } } @media (max-width: 575.98px) { .bibliography-source { flex-direction: column; align-items: flex-start; gap: 0.5rem; } .card-header { padding: 1rem; } .bibliography-abstract, .bibliography-keywords, .bibliography-details, .raw-reference { padding: 1rem !important; } .section-title { font-size: 1rem; } .action-row { flex-direction: column; } .bibliography-actions { flex-direction: column; align-items: stretch; } .bibliography-actions .btn { margin-bottom: 0.5rem; margin-right: 0 !important; } } </style> <!-- Include Scripts --> <script src="https://cdn.jsdelivr.net/npm/web3@latest/dist/web3.min.js"></script> <script> // Updated contract address and ABI for the new contract const contractAddress = "0xC17994a40d9459dfEA21207dB34eCaf2a1c96804"; const CONTRACT_ABI = [ { "inputs": [ { "internalType": "string", "name": "uri_", "type": "string" } ], "stateMutability": "nonpayable", "type": "constructor" }, { "inputs": [ { "internalType": "address", "name": "sender", "type": "address" }, { "internalType": "uint256", "name": "balance", "type": "uint256" }, { "internalType": "uint256", "name": "needed", "type": "uint256" }, { "internalType": "uint256", "name": "tokenId", "type": "uint256" } ], "name": "ERC1155InsufficientBalance", "type": "error" }, { "inputs": [ { "internalType": "address", "name": "approver", "type": "address" } ], "name": "ERC1155InvalidApprover", "type": "error" }, { "inputs": [ { "internalType": "uint256", "name": "idsLength", "type": "uint256" }, { "internalType": "uint256", "name": "valuesLength", "type": "uint256" } ], "name": "ERC1155InvalidArrayLength", "type": "error" }, { "inputs": [ { "internalType": "address", "name": "operator", "type": "address" } ], "name": "ERC1155InvalidOperator", "type": "error" }, { "inputs": [ { "internalType": "address", "name": "receiver", "type": "address" } ], "name": "ERC1155InvalidReceiver", "type": "error" }, { "inputs": [ { "internalType": "address", "name": "sender", "type": "address" } ], "name": "ERC1155InvalidSender", "type": "error" }, { "inputs": [ { "internalType": "address", "name": "operator", "type": "address" }, { "internalType": "address", "name": "owner", "type": "address" } ], "name": "ERC1155MissingApprovalForAll", "type": "error" }, { "inputs": [], "name": "EnforcedPause", "type": "error" }, { "inputs": [], "name": "ExpectedPause", "type": "error" }, { "inputs": [ { "internalType": "address", "name": "owner", "type": "address" } ], "name": "OwnableInvalidOwner", "type": "error" }, { "inputs": [ { "internalType": "address", "name": "account", "type": "address" } ], "name": "OwnableUnauthorizedAccount", "type": "error" }, { "anonymous": false, "inputs": [ { "indexed": true, "internalType": "address", "name": "account", "type": "address" }, { "indexed": true, "internalType": "address", "name": "operator", "type": "address" }, { "indexed": false, "internalType": "bool", "name": "approved", "type": "bool" } ], "name": "ApprovalForAll", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "internalType": "uint256", "name": "tokenId", "type": "uint256" }, { "indexed": false, "internalType": "string", "name": "doi", "type": "string" }, { "indexed": true, "internalType": "address", "name": "creator", "type": "address" }, { "indexed": false, "internalType": "uint256", "name": "supply", "type": "uint256" } ], "name": "ArticleMinted", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": true, "internalType": "uint256", "name": "tokenId", "type": "uint256" }, { "indexed": false, "internalType": "string", "name": "ipfsHash", "type": "string" } ], "name": "MetadataUpdated", "type": "event" }, { "inputs": [ { "internalType": "address", "name": "to", "type": "address" }, { "internalType": "string", "name": "doi", "type": "string" }, { "internalType": "uint256", "name": "amount", "type": "uint256" }, { "internalType": "uint256", "name": "articleId", "type": "uint256" } ], "name": "mintArticle", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "nonpayable", "type": "function" }, { "anonymous": false, "inputs": [ { "indexed": true, "internalType": "address", "name": "previousOwner", "type": "address" }, { "indexed": true, "internalType": "address", "name": "newOwner", "type": "address" } ], "name": "OwnershipTransferred", "type": "event" }, { "inputs": [], "name": "pause", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "anonymous": false, "inputs": [ { "indexed": false, "internalType": "address", "name": "account", "type": "address" } ], "name": "Paused", "type": "event" }, { "inputs": [], "name": "renounceOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "from", "type": "address" }, { "internalType": "address", "name": "to", "type": "address" }, { "internalType": "uint256[]", "name": "ids", "type": "uint256[]" }, { "internalType": "uint256[]", "name": "values", "type": "uint256[]" }, { "internalType": "bytes", "name": "data", "type": "bytes" } ], "name": "safeBatchTransferFrom", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "from", "type": "address" }, { "internalType": "address", "name": "to", "type": "address" }, { "internalType": "uint256", "name": "id", "type": "uint256" }, { "internalType": "uint256", "name": "value", "type": "uint256" }, { "internalType": "bytes", "name": "data", "type": "bytes" } ], "name": "safeTransferFrom", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "operator", "type": "address" }, { "internalType": "bool", "name": "approved", "type": "bool" } ], "name": "setApprovalForAll", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "string", "name": "newuri", "type": "string" } ], "name": "setURI", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "to", "type": "address" }, { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, { "internalType": "uint256", "name": "amount", "type": "uint256" } ], "name": "transferArticle", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "anonymous": false, "inputs": [ { "indexed": true, "internalType": "address", "name": "operator", "type": "address" }, { "indexed": true, "internalType": "address", "name": "from", "type": "address" }, { "indexed": true, "internalType": "address", "name": "to", "type": "address" }, { "indexed": false, "internalType": "uint256[]", "name": "ids", "type": "uint256[]" }, { "indexed": false, "internalType": "uint256[]", "name": "values", "type": "uint256[]" } ], "name": "TransferBatch", "type": "event" }, { "inputs": [ { "internalType": "address", "name": "newOwner", "type": "address" } ], "name": "transferOwnership", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "anonymous": false, "inputs": [ { "indexed": true, "internalType": "address", "name": "operator", "type": "address" }, { "indexed": true, "internalType": "address", "name": "from", "type": "address" }, { "indexed": true, "internalType": "address", "name": "to", "type": "address" }, { "indexed": false, "internalType": "uint256", "name": "id", "type": "uint256" }, { "indexed": false, "internalType": "uint256", "name": "value", "type": "uint256" } ], "name": "TransferSingle", "type": "event" }, { "inputs": [], "name": "unpause", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "anonymous": false, "inputs": [ { "indexed": false, "internalType": "string", "name": "value", "type": "string" }, { "indexed": true, "internalType": "uint256", "name": "id", "type": "uint256" } ], "name": "URI", "type": "event" }, { "anonymous": false, "inputs": [ { "indexed": false, "internalType": "address", "name": "account", "type": "address" } ], "name": "Unpaused", "type": "event" }, { "inputs": [ { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, { "internalType": "string", "name": "title", "type": "string" }, { "internalType": "string", "name": "authors", "type": "string" }, { "internalType": "string", "name": "journal", "type": "string" }, { "internalType": "string", "name": "url", "type": "string" } ], "name": "updateArticleMetadata", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "uint256", "name": "tokenId", "type": "uint256" }, { "internalType": "string", "name": "abstractText", "type": "string" }, { "internalType": "string", "name": "volume", "type": "string" }, { "internalType": "string", "name": "pages", "type": "string" }, { "internalType": "string", "name": "ipfsHash", "type": "string" } ], "name": "updateArticleMetadataExt", "outputs": [], "stateMutability": "nonpayable", "type": "function" }, { "inputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "name": "articleMetadata", "outputs": [ { "internalType": "string", "name": "title", "type": "string" }, { "internalType": "string", "name": "authors", "type": "string" }, { "internalType": "string", "name": "journal", "type": "string" }, { "internalType": "string", "name": "doi", "type": "string" }, { "internalType": "string", "name": "url", "type": "string" }, { "internalType": "uint256", "name": "articleId", "type": "uint256" }, { "internalType": "address", "name": "creator", "type": "address" }, { "internalType": "uint256", "name": "dateCreated", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "name": "articleMetadataExt", "outputs": [ { "internalType": "string", "name": "abstractText", "type": "string" }, { "internalType": "string", "name": "volume", "type": "string" }, { "internalType": "string", "name": "pages", "type": "string" }, { "internalType": "string", "name": "ipfsHash", "type": "string" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "account", "type": "address" }, { "internalType": "uint256", "name": "id", "type": "uint256" } ], "name": "balanceOf", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "address[]", "name": "accounts", "type": "address[]" }, { "internalType": "uint256[]", "name": "ids", "type": "uint256[]" } ], "name": "balanceOfBatch", "outputs": [ { "internalType": "uint256[]", "name": "", "type": "uint256[]" } ], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "DEFAULT_SUPPLY", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "string", "name": "", "type": "string" } ], "name": "doiToTokenId", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "uint256", "name": "id", "type": "uint256" } ], "name": "exists", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "uint256", "name": "tokenId", "type": "uint256" } ], "name": "getFullMetadata", "outputs": [ { "components": [ { "internalType": "string", "name": "title", "type": "string" }, { "internalType": "string", "name": "authors", "type": "string" }, { "internalType": "string", "name": "journal", "type": "string" }, { "internalType": "string", "name": "doi", "type": "string" }, { "internalType": "string", "name": "url", "type": "string" }, { "internalType": "uint256", "name": "articleId", "type": "uint256" }, { "internalType": "address", "name": "creator", "type": "address" }, { "internalType": "uint256", "name": "dateCreated", "type": "uint256" } ], "internalType": "struct DeJournalNFT.ArticleMetadata", "name": "metadata", "type": "tuple" }, { "components": [ { "internalType": "string", "name": "abstractText", "type": "string" }, { "internalType": "string", "name": "volume", "type": "string" }, { "internalType": "string", "name": "pages", "type": "string" }, { "internalType": "string", "name": "ipfsHash", "type": "string" } ], "internalType": "struct DeJournalNFT.ArticleMetadataExt", "name": "metadataExt", "type": "tuple" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "string", "name": "doi", "type": "string" } ], "name": "getTokenIdByDOI", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "user", "type": "address" } ], "name": "getUserTokens", "outputs": [ { "internalType": "uint256[]", "name": "", "type": "uint256[]" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "account", "type": "address" }, { "internalType": "address", "name": "operator", "type": "address" } ], "name": "isApprovedForAll", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "owner", "outputs": [ { "internalType": "address", "name": "", "type": "address" } ], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "paused", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "bytes4", "name": "interfaceId", "type": "bytes4" } ], "name": "supportsInterface", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "name": "tokenExists", "outputs": [ { "internalType": "bool", "name": "", "type": "bool" } ], "stateMutability": "view", "type": "function" }, { "inputs": [], "name": "totalSupply", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "uint256", "name": "id", "type": "uint256" } ], "name": "totalSupply", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "uint256", "name": "tokenId", "type": "uint256" } ], "name": "uri", "outputs": [ { "internalType": "string", "name": "", "type": "string" } ], "stateMutability": "view", "type": "function" }, { "inputs": [ { "internalType": "address", "name": "", "type": "address" }, { "internalType": "uint256", "name": "", "type": "uint256" } ], "name": "userTokens", "outputs": [ { "internalType": "uint256", "name": "", "type": "uint256" } ], "stateMutability": "view", "type": "function" } ]; // MD5 function (keep your existing MD5 implementation) var MD5 = function(d){var r = M(V(Y(X(d),8*d.length)));return r.toLowerCase()};function M(d){for(var _,m="0123456789ABCDEF",f="",r=0;r<d.length;r++)_=d.charCodeAt(r),f+=m.charAt(_>>>4&15)+m.charAt(15&_);return f}function X(d){for(var _=Array(d.length>>2),m=0;m<_.length;m++)_[m]=0;for(m=0;m<8*d.length;m+=8)_[m>>5]|=(255&d.charCodeAt(m/8))<<m%32;return _}function V(d){for(var _="",m=0;m<32*d.length;m+=8)_+=String.fromCharCode(d[m>>5]>>>m%32&255);return _}function Y(d,_){d[_>>5]|=128<<_%32,d[14+(_+64>>>9<<4)]=_;for(var m=1732584193,f=-271733879,r=-1732584194,i=271733878,n=0;n<d.length;n+=16){var h=m,t=f,g=r,e=i;f=md5_ii(f=md5_ii(f=md5_ii(f=md5_ii(f=md5_hh(f=md5_hh(f=md5_hh(f=md5_hh(f=md5_gg(f=md5_gg(f=md5_gg(f=md5_gg(f=md5_ff(f=md5_ff(f=md5_ff(f=md5_ff(f,r=md5_ff(r,i=md5_ff(i,m=md5_ff(m,f,r,i,d[n+0],7,-680876936),f,r,d[n+1],12,-389564586),m,f,d[n+2],17,606105819),i,m,d[n+3],22,-1044525330),r=md5_ff(r,i=md5_ff(i,m=md5_ff(m,f,r,i,d[n+4],7,-176418897),f,r,d[n+5],12,1200080426),m,f,d[n+6],17,-1473231341),i,m,d[n+7],22,-45705983),r=md5_ff(r,i=md5_ff(i,m=md5_ff(m,f,r,i,d[n+8],7,1770035416),f,r,d[n+9],12,-1958414417),m,f,d[n+10],17,-42063),i,m,d[n+11],22,-1990404162),r=md5_ff(r,i=md5_ff(i,m=md5_ff(m,f,r,i,d[n+12],7,1804603682),f,r,d[n+13],12,-40341101),m,f,d[n+14],17,-1502002290),i,m,d[n+15],22,1236535329),r=md5_gg(r,i=md5_gg(i,m=md5_gg(m,f,r,i,d[n+1],5,-165796510),f,r,d[n+6],9,-1069501632),m,f,d[n+11],14,643717713),i,m,d[n+0],20,-373897302),r=md5_gg(r,i=md5_gg(i,m=md5_gg(m,f,r,i,d[n+5],5,-701558691),f,r,d[n+10],9,38016083),m,f,d[n+15],14,-660478335),i,m,d[n+4],20,-405537848),r=md5_gg(r,i=md5_gg(i,m=md5_gg(m,f,r,i,d[n+9],5,568446438),f,r,d[n+14],9,-1019803690),m,f,d[n+3],14,-187363961),i,m,d[n+8],20,1163531501),r=md5_gg(r,i=md5_gg(i,m=md5_gg(m,f,r,i,d[n+13],5,-1444681467),f,r,d[n+2],9,-51403784),m,f,d[n+7],14,1735328473),i,m,d[n+12],20,-1926607734),r=md5_hh(r,i=md5_hh(i,m=md5_hh(m,f,r,i,d[n+5],4,-378558),f,r,d[n+8],11,-2022574463),m,f,d[n+11],16,1839030562),i,m,d[n+14],23,-35309556),r=md5_hh(r,i=md5_hh(i,m=md5_hh(m,f,r,i,d[n+1],4,-1530992060),f,r,d[n+4],11,1272893353),m,f,d[n+7],16,-155497632),i,m,d[n+10],23,-1094730640),r=md5_hh(r,i=md5_hh(i,m=md5_hh(m,f,r,i,d[n+13],4,681279174),f,r,d[n+0],11,-358537222),m,f,d[n+3],16,-722521979),i,m,d[n+6],23,76029189),r=md5_hh(r,i=md5_hh(i,m=md5_hh(m,f,r,i,d[n+9],4,-640364487),f,r,d[n+12],11,-421815835),m,f,d[n+15],16,530742520),i,m,d[n+2],23,-995338651),r=md5_ii(r,i=md5_ii(i,m=md5_ii(m,f,r,i,d[n+0],6,-198630844),f,r,d[n+7],10,1126891415),m,f,d[n+14],15,-1416354905),i,m,d[n+5],21,-57434055),r=md5_ii(r,i=md5_ii(i,m=md5_ii(m,f,r,i,d[n+12],6,1700485571),f,r,d[n+3],10,-1894986606),m,f,d[n+10],15,-1051523),i,m,d[n+1],21,-2054922799),r=md5_ii(r,i=md5_ii(i,m=md5_ii(m,f,r,i,d[n+8],6,1873313359),f,r,d[n+15],10,-30611744),m,f,d[n+6],15,-1560198380),i,m,d[n+13],21,1309151649),r=md5_ii(r,i=md5_ii(i,m=md5_ii(m,f,r,i,d[n+4],6,-145523070),f,r,d[n+11],10,-1120210379),m,f,d[n+2],15,718787259),i,m,d[n+9],21,-343485551),m=safe_add(m,h),f=safe_add(f,t),r=safe_add(r,g),i=safe_add(i,e)}return Array(m,f,r,i)}function md5_cmn(d,_,m,f,r,i){return safe_add(bit_rol(safe_add(safe_add(_,d),safe_add(f,i)),r),m)}function md5_ff(d,_,m,f,r,i,n){return md5_cmn(_&m|~_&f,d,_,r,i,n)}function md5_gg(d,_,m,f,r,i,n){return md5_cmn(_&f|m&~f,d,_,r,i,n)}function md5_hh(d,_,m,f,r,i,n){return md5_cmn(_^m^f,d,_,r,i,n)}function md5_ii(d,_,m,f,r,i,n){return md5_cmn(m^(_|~f),d,_,r,i,n)}function safe_add(d,_){var m=(65535&d)+(65535&_);return(d>>16)+(_>>16)+(m>>16)<<16|65535&m}function bit_rol(d,_){return d<<_|d>>>32-_} const providerUrl = "https://rpc.scimatic.net"; // Updated RPC URL const sciChainChainId = '0x1e1'; // Scimatic chain ID (481 in hex) let web3; let contract; // Keep your existing PHP processing window.addEventListener('load', async () => { if (typeof window.ethereum !== 'undefined') { const ethereum = window.ethereum; // Event listeners for network/account changes ethereum.on('chainChanged', function() { location.reload(); }); ethereum.on('accountsChanged', function() { location.reload(); }); // Check if the current network is SciMatic Chain const currentNetworkId = await ethereum.request({ method: 'eth_chainId' }); if (currentNetworkId !== sciChainChainId) { try { // Request to switch to SciMatic Chain await ethereum.request({ method: 'wallet_switchEthereumChain', params: [{ chainId: sciChainChainId }], }); } catch (switchError) { // This error code indicates that the chain has not been added to MetaMask if (switchError.code === 4902) { try { await ethereum.request({ method: 'wallet_addEthereumChain', params: [{ chainId: sciChainChainId, chainName: 'Scimatic Network', nativeCurrency: { name: 'SciMatic Coin', symbol: 'SCI', decimals: 18, }, rpcUrls: [providerUrl], blockExplorerUrls: ['https://scimatic.net'], }], }); } catch (addError) { console.error('Error adding Scimatic network:', addError); } } } } // Request account access using modern method await ethereum.request({ method: 'eth_requestAccounts' }); web3 = new Web3(ethereum); contract = new web3.eth.Contract(CONTRACT_ABI, contractAddress); } else { console.error('MetaMask not available, using default provider'); web3 = new Web3(new Web3.providers.HttpProvider(providerUrl)); contract = new web3.eth.Contract(CONTRACT_ABI, contractAddress); } // Automatically check if article is already tokenized setTimeout(() => { checkTokenInfo(); }, 1000); }); // Ensure MetaMask is on the SciMatic network. If not, switch to it; // if the chain is not yet added, add it. The existing `chainChanged` // listener reloads the page automatically after a successful switch/add. async function ensureScimaticNetwork() { if (typeof window.ethereum === 'undefined') { showWarningAlert('MetaMask is not installed. Please install MetaMask to continue.'); return false; } try { const currentNetworkId = await window.ethereum.request({ method: 'eth_chainId' }); if (currentNetworkId === sciChainChainId) { return true; } try { await window.ethereum.request({ method: 'wallet_switchEthereumChain', params: [{ chainId: sciChainChainId }], }); // chainChanged listener will reload the page return false; } catch (switchError) { if (switchError.code === 4902) { try { await window.ethereum.request({ method: 'wallet_addEthereumChain', params: [{ chainId: sciChainChainId, chainName: 'Scimatic Network', nativeCurrency: { name: 'SciMatic Coin', symbol: 'SCI', decimals: 18, }, rpcUrls: [providerUrl], blockExplorerUrls: ['https://scimatic.net'], }], }); // chainChanged listener will reload the page return false; } catch (addError) { console.error('Error adding Scimatic network:', addError); showWarningAlert('Please add the Scimatic network to MetaMask to continue.'); return false; } } else if (switchError.code === 4001) { showWarningAlert('Please switch to the Scimatic network to continue.'); return false; } console.error('Error switching to Scimatic network:', switchError); showWarningAlert('Failed to switch to Scimatic network: ' + (switchError.message || 'Unknown error')); return false; } } catch (err) { console.error('ensureScimaticNetwork error:', err); return false; } } async function getUserAddressFromMetaMask() { if (!web3) { console.error('Web3 not available'); alert('Web3 not available'); return null; } try { const accounts = await web3.eth.getAccounts(); if (accounts.length > 0) { return accounts[0]; } else { console.error('No accounts found in MetaMask'); alert('No accounts found in MetaMask'); return null; } } catch (error) { console.error('Error fetching accounts:', error); return null; } } async function uploadButtonClick() { console.log('Upload button clicked!'); // Debug log uploadArticleToBlockchain( '128755', "7632bfe35b0b2a964563d8e79f221e6a", "through amazonian eyes: the human ecology of amazonian populations", "", ';Walter Neves', 'iberian conference on information systems and technologies, cisti', '11', '150-152', 'https://scimatic.org/biblio/128755' ); } // Updated function for the new contract structure async function uploadArticleToBlockchain( articleId, uniqueId, articleTitle, articleAbstract, authors, journal, volume, pages, url ) { if (!web3) { console.error('Web3 not available'); showWarningAlert('Web3 not available or Blockchain network under maintenance'); return; } // Force Scimatic network before minting (will switch/add and reload if needed) if (!(await ensureScimaticNetwork())) { return; } try { const userAddress = await getUserAddressFromMetaMask(); if (!userAddress) { alert('Failed to retrieve user address from MetaMask. Make sure MetaMask extension is installed in your Web Browser'); return; } console.log('User address:', userAddress); console.log('Article data:', { articleId, uniqueId, articleTitle: articleTitle.substring(0, 50) + '...', authors, journal, volume, pages, url }); // Show loading spinner const spinner = document.getElementById('spinner'); spinner.classList.remove('d-none'); // Check if article is already tokenized const existingTokenId = await contract.methods.getTokenIdByDOI(uniqueId).call(); console.log('Existing token ID check:', existingTokenId); if (existingTokenId > 0) { showWarningAlert('Article with this unique ID already exists on the blockchain. Token ID: ' + existingTokenId); spinner.classList.add('d-none'); return; } // Debug: Check if DOI is not empty if (!uniqueId || uniqueId.trim() === '') { showWarningAlert('DOI/Unique ID cannot be empty'); spinner.classList.add('d-none'); return; } // Debug: Log the parameters we're sending console.log('Minting with params:', { to: userAddress, doi: uniqueId, amount: 1000000, articleId: parseInt(articleId) }); // Step 1: Mint the article with basic info showInfoAlert('Minting NFT token...'); // Get gas price for legacy transaction const gasPrice = await web3.eth.getGasPrice(); // Estimate gas first to catch errors early let gasEstimate; try { gasEstimate = await contract.methods.mintArticle( userAddress, uniqueId, // Using hash as DOI 1000000, // 1 million tokens parseInt(articleId) // Make sure it's a number ).estimateGas({ from: userAddress }); console.log('Gas estimate:', gasEstimate); // Convert BigInt to Number for calculations gasEstimate = Number(gasEstimate); } catch (estimateError) { console.error('Gas estimation failed:', estimateError); showWarningAlert('Transaction will fail. Error: ' + estimateError.message); spinner.classList.add('d-none'); return; } const mintTx = await contract.methods.mintArticle( userAddress, uniqueId, // Using hash as DOI 1000000, // 1 million tokens parseInt(articleId) // Make sure it's a number ).send({ from: userAddress, gas: Math.floor(gasEstimate * 1.2), // Add 20% buffer gasPrice: gasPrice.toString() // Convert to string for legacy transaction }); // Get token ID from event let tokenId; if (mintTx.events && mintTx.events.ArticleMinted) { tokenId = mintTx.events.ArticleMinted.returnValues.tokenId; // Convert BigInt to string/number tokenId = tokenId.toString(); } else { // Fallback: get token ID by DOI tokenId = await contract.methods.getTokenIdByDOI(uniqueId).call(); tokenId = tokenId.toString(); } console.log('Token minted with ID:', tokenId); // Success! NFT was minted console.log('Article successfully tokenized!'); currentTokenId = tokenId; // Store globally showSuccessAlert(`✅ Article successfully tokenized! \n\nToken ID: ${tokenId}\nSupply: 1,000,000 tokens\nContract: ${contractAddress}\n\nThe article has been permanently recorded on the blockchain.`); // Show token ID in the info section const tokenIdRow = document.getElementById('tokenIdRow'); const tokenIdValue = document.getElementById('tokenIdValue'); if (tokenIdRow && tokenIdValue) { tokenIdRow.style.display = 'block'; tokenIdValue.textContent = tokenId; } // Show Add to MetaMask button const addToMetaMaskBtn = document.getElementById('addToMetaMaskBtn'); if (addToMetaMaskBtn) { addToMetaMaskBtn.style.display = 'inline-block'; } // Show token info section const tokenInfoSection = document.getElementById('tokenInfoSection'); const displayTokenId = document.getElementById('displayTokenId'); if (tokenInfoSection && displayTokenId) { tokenInfoSection.style.display = 'block'; displayTokenId.textContent = tokenId; } // Try to add token to MetaMask try { await addTokenToMetaMask(tokenId); } catch (error) { console.error('Error adding token to MetaMask:', error); } // Store token info for reference if (typeof(Storage) !== "undefined") { localStorage.setItem(`article_${articleId}_tokenId`, tokenId); localStorage.setItem(`article_${articleId}_txHash`, mintTx.transactionHash); } // Disable the upload button since it's already tokenized const uploadButton = document.getElementById('uploadButton'); if (uploadButton) { uploadButton.disabled = true; uploadButton.innerHTML = '<i class="fas fa-check-circle me-2"></i> Already Tokenized (Token ID: ' + tokenId + ')'; } // Hide spinner spinner.classList.add('d-none'); // Refresh the page after a short delay setTimeout(() => { location.reload(); }, 5000); } catch (error) { console.error('Error:', error); // Hide spinner const spinner = document.getElementById('spinner'); spinner.classList.add('d-none'); let errorMessage = 'Transaction failed. '; // Parse specific error messages if (error.message.includes('insufficient funds')) { errorMessage += 'Insufficient balance for gas fees.'; } else if (error.code === 4001) { errorMessage += 'Transaction cancelled by user.'; } else if (error.message.includes('DOI cannot be empty')) { errorMessage += 'The article unique ID (DOI) cannot be empty.'; } else if (error.message.includes('Article already tokenized')) { errorMessage += 'This article has already been tokenized.'; } else if (error.message.includes('Invalid amount')) { errorMessage += 'Invalid token amount specified.'; } else if (error.message.includes('User denied transaction')) { errorMessage += 'You rejected the transaction in MetaMask.'; } else { errorMessage += error.message || 'Please try again later.'; } showWarningAlert(errorMessage); } } // Add token to MetaMask - Updated for better compatibility async function addTokenToMetaMask(tokenId) { try { // First, let's check the user's balance of this token const userAddress = await getUserAddressFromMetaMask(); const balance = await contract.methods.balanceOf(userAddress, tokenId).call(); console.log(`User balance for token ${tokenId}:`, balance); // For ERC1155, we need to ensure the token URI is accessible const tokenURI = await contract.methods.uri(tokenId).call(); console.log('Token URI:', tokenURI); // Try adding as a custom token const wasAdded = await window.ethereum.request({ method: 'wallet_watchAsset', params: { type: 'ERC1155', options: { address: contractAddress, tokenId: tokenId.toString(), } } }); if (wasAdded) { console.log('Token added to MetaMask!'); } else { console.log('Token addition was cancelled'); } } catch (error) { console.error('Error adding token to MetaMask:', error); // Provide manual instructions as fallback showInfoAlert(`To view your NFT in MetaMask: Go to NFTs tab → Import NFT → Contract: ${contractAddress} → Token ID: ${tokenId}`); } } // Updated check function for the new contract async function checkTokenInfo() { if (!web3) { console.error('Web3 not available'); showWarningAlert('Web3 not available or Blockchain network under maintenance'); return; } const tokenId = document.getElementById('tokenId') ? parseInt(document.getElementById('tokenId').value) : 128755; try { // Show the spinner const spinner = document.getElementById('spinner'); spinner.classList.remove('d-none'); // First check if this article's unique ID has a token const uniqueId = "7632bfe35b0b2a964563d8e79f221e6a"; const tokenIdByDOI = await contract.methods.getTokenIdByDOI(uniqueId).call(); if (tokenIdByDOI && tokenIdByDOI > 0) { // Store the token ID globally currentTokenId = tokenIdByDOI.toString(); const result = document.getElementById('result'); result.innerHTML = ` <div class="alert alert-success"> <h5><i class="fas fa-check-circle me-2"></i>Article Successfully Tokenized!</h5> <p><b>Token ID:</b> ${tokenIdByDOI}</p> <p><b>DOI/Hash:</b> ${uniqueId}</p> <p><b>Supply:</b> 1,000,000 tokens</p> <p><b>Contract:</b> ${contractAddress}</p> <p class="mb-0"><small>This article has been permanently recorded on the Scimatic blockchain.</small></p> </div> `; // Show token ID in the info section const tokenIdRow = document.getElementById('tokenIdRow'); const tokenIdValue = document.getElementById('tokenIdValue'); if (tokenIdRow && tokenIdValue) { tokenIdRow.style.display = 'block'; tokenIdValue.textContent = tokenIdByDOI; } // Show Add to MetaMask button in header const addToMetaMaskBtn = document.getElementById('addToMetaMaskBtn'); if (addToMetaMaskBtn) { addToMetaMaskBtn.style.display = 'inline-block'; } // Show token info section (but hide the duplicate button there) const tokenInfoSection = document.getElementById('tokenInfoSection'); const displayTokenId = document.getElementById('displayTokenId'); if (tokenInfoSection && displayTokenId) { tokenInfoSection.style.display = 'block'; displayTokenId.textContent = tokenIdByDOI; // Hide the duplicate button inside token info section const duplicateBtn = tokenInfoSection.querySelector('.btn-warning'); if (duplicateBtn) { duplicateBtn.style.display = 'none'; } } // Disable the upload button const uploadButton = document.getElementById('uploadButton'); if (uploadButton) { uploadButton.disabled = true; uploadButton.innerHTML = '<i class="fas fa-check-circle me-2"></i> Already Tokenized'; } } else { const result = document.getElementById('result'); result.innerHTML = ''; showWarningAlert('Article not found on the blockchain. Click the button below to upload.'); // Enable the upload button const uploadButton = document.getElementById('uploadButton'); if (uploadButton) { uploadButton.disabled = false; } } } catch (error) { console.error('Error:', error); showWarningAlert('Network error occurred: ' + error.message); } finally { // Hide the spinner const spinner = document.getElementById('spinner'); spinner.classList.add('d-none'); } } // Alert functions function showWarningAlert(message) { showAlert('warning', message); } function showSuccessAlert(message) { showAlert('success', message); } function showInfoAlert(message) { showAlert('info', message); } function showAlert(type, message) { const alertDiv = document.createElement('div'); alertDiv.className = `alert alert-${type} alert-dismissible fade show mt-3`; alertDiv.innerHTML = ` ${message} <button type="button" class="close" data-dismiss="alert" aria-label="Close"> <span aria-hidden="true">×</span> </button> `; const result = document.getElementById('result'); result.innerHTML = ''; result.appendChild(alertDiv); } </script><script> // Global variables let currentUserBalance = 0; let selectedTokenId = null; let html5QrcodeScanner = null; let scannedAddress = null; // Wait for document ready before loading QR scanner document.addEventListener('DOMContentLoaded', function() { // Load QR Code Scanner library if (!document.getElementById('html5-qrcode-script')) { const script = document.createElement('script'); script.id = 'html5-qrcode-script'; script.src = 'https://unpkg.com/html5-qrcode@2.3.8/html5-qrcode.min.js'; script.onload = function() { console.log('QR Scanner library loaded successfully'); }; script.onerror = function() { console.error('Failed to load QR Scanner library'); }; document.head.appendChild(script); } }); // Function to open QR scanner function openQRScanner() { // Check if library is loaded if (typeof Html5Qrcode === 'undefined' || typeof Html5QrcodeScanner === 'undefined') { alert('QR Scanner is still loading. Please try again in a moment.'); console.log('Attempting to reload QR scanner library...'); // Try to load the library again const script = document.createElement('script'); script.src = 'https://unpkg.com/html5-qrcode@2.3.8/html5-qrcode.min.js'; script.onload = function() { console.log('QR Scanner library reloaded'); // Try opening again after reload setTimeout(() => openQRScanner(), 500); }; document.head.appendChild(script); return; } const qrScannerModal = document.getElementById('qrScannerModal'); if (!qrScannerModal) { console.error('QR Scanner modal not found'); return; } if (typeof $ !== 'undefined') { $('#qrScannerModal').modal('show'); } else { qrScannerModal.style.display = 'block'; qrScannerModal.classList.add('show'); document.body.classList.add('modal-open'); const backdrop = document.createElement('div'); backdrop.className = 'modal-backdrop fade show'; backdrop.id = 'qrModalBackdrop'; document.body.appendChild(backdrop); } // Reset previous results const qrResult = document.getElementById('qrResult'); const useAddressBtn = document.getElementById('useAddressBtn'); if (qrResult) qrResult.classList.add('d-none'); if (useAddressBtn) useAddressBtn.classList.add('d-none'); scannedAddress = null; // Clear the reader div const qrReaderDiv = document.getElementById('qrReaderDiv'); if (qrReaderDiv) { qrReaderDiv.innerHTML = ''; } // Start QR scanner with delay to ensure modal is fully shown setTimeout(() => startQRScanner(), 300); } // Function to close QR scanner function closeQRScanner() { // Stop scanner if running if (html5QrcodeScanner) { html5QrcodeScanner.clear(); html5QrcodeScanner = null; } if (typeof $ !== 'undefined') { $('#qrScannerModal').modal('hide'); } else { const qrScannerModal = document.getElementById('qrScannerModal'); if (qrScannerModal) { qrScannerModal.style.display = 'none'; qrScannerModal.classList.remove('show'); } document.body.classList.remove('modal-open'); const backdrop = document.getElementById('qrModalBackdrop'); if (backdrop) { backdrop.remove(); } } } // Start QR Scanner function startQRScanner() { // Double check if library is loaded if (typeof Html5QrcodeScanner === 'undefined') { console.error('Html5QrcodeScanner is not defined'); const qrReaderDiv = document.getElementById('qrReaderDiv'); if (qrReaderDiv) { qrReaderDiv.innerHTML = ` <div class="alert alert-warning"> <p>QR Scanner is loading...</p> <button class="btn btn-primary btn-sm" onclick="retryQRScanner()">Retry</button> </div> `; } return; } try { // Clear any existing scanner const qrReaderDiv = document.getElementById('qrReaderDiv'); if (!qrReaderDiv) { console.error('qrReaderDiv element not found'); return; } // Clear the div qrReaderDiv.innerHTML = ''; // Configure scanner with more options const config = { fps: 10, qrbox: { width: 250, height: 250 }, aspectRatio: 1.0, showTorchButtonIfSupported: true, experimentalFeatures: { useBarCodeDetectorIfSupported: false } }; // Create new scanner instance html5QrcodeScanner = new Html5QrcodeScanner("qrReaderDiv", config, false); html5QrcodeScanner.render( // Success callback (decodedText, decodedResult) => { console.log('QR Code detected:', decodedText); handleQRCodeResult(decodedText); }, // Error callback (error) => { // Only log if it's not a "QR code not found" error if (!error.includes('NotFoundException')) { console.log('QR scan error:', error); } } ); console.log('QR Scanner started successfully'); } catch (error) { console.error('Error starting QR scanner:', error); const qrReaderDiv = document.getElementById('qrReaderDiv'); if (qrReaderDiv) { qrReaderDiv.innerHTML = ` <div class="alert alert-danger"> <p>Error starting QR scanner: ${error.message}</p> <p>Please ensure camera permissions are granted.</p> <input type="file" id="qrFileInput" accept="image/*" onchange="handleQRFile(event)" class="form-control mt-2"> <p class="mt-2">Or upload a QR code image instead</p> </div> `; } } } // Retry function for QR scanner function retryQRScanner() { // Clear the div first const qrReaderDiv = document.getElementById('qrReaderDiv'); if (qrReaderDiv) { qrReaderDiv.innerHTML = '<p class="text-center">Loading scanner...</p>'; } // Check if library is loaded if (typeof Html5QrcodeScanner === 'undefined') { // Try loading the library again const existingScript = document.getElementById('html5-qrcode-script'); if (existingScript) { existingScript.remove(); } const script = document.createElement('script'); script.id = 'html5-qrcode-script'; script.src = 'https://unpkg.com/html5-qrcode@2.3.8/html5-qrcode.min.js'; script.onload = function() { console.log('QR Scanner library loaded on retry'); setTimeout(() => startQRScanner(), 500); }; script.onerror = function() { console.error('Failed to load QR Scanner library on retry'); if (qrReaderDiv) { qrReaderDiv.innerHTML = ` <div class="alert alert-danger"> <p>Failed to load QR scanner library.</p> <p>Please check your internet connection and try again.</p> <input type="file" id="qrFileInput" accept="image/*" onchange="handleQRFile(event)" class="form-control mt-2"> <p class="mt-2">Or upload a QR code image instead</p> </div> `; } }; document.head.appendChild(script); } else { // Library is loaded, just start the scanner startQRScanner(); } } // Handle QR code result function handleQRCodeResult(text) { // Stop scanning if (html5QrcodeScanner) { html5QrcodeScanner.clear(); } // Extract Ethereum address let address = text; // Handle ethereum: prefix if (text.startsWith('ethereum:')) { address = text.replace('ethereum:', '').split('?')[0]; } // Validate address if (/^0x[a-fA-F0-9]{40}$/.test(address)) { scannedAddress = address; const detectedAddress = document.getElementById('detectedAddress'); const qrResult = document.getElementById('qrResult'); const useAddressBtn = document.getElementById('useAddressBtn'); if (detectedAddress) detectedAddress.textContent = address; if (qrResult) qrResult.classList.remove('d-none'); if (useAddressBtn) useAddressBtn.classList.remove('d-none'); } else { alert('Invalid Ethereum address detected. Please scan a valid wallet QR code.'); // Restart scanner startQRScanner(); } } // Use scanned address function useScannedAddress() { if (scannedAddress) { const recipientAddress = document.getElementById('recipientAddress'); if (recipientAddress) { recipientAddress.value = scannedAddress; } closeQRScanner(); } } // Handle QR file upload (fallback) function handleQRFile(event) { const file = event.target.files[0]; if (!file) return; if (typeof Html5Qrcode === 'undefined') { alert('QR Scanner library not loaded. Please refresh the page.'); return; } const html5QrCode = new Html5Qrcode("qrReaderDiv"); html5QrCode.scanFile(file, true) .then(decodedText => { handleQRCodeResult(decodedText); }) .catch(err => { alert('No QR code found in the image.'); console.error('QR scan error:', err); }); } // Function to close send tokens modal function closeSendTokensModal() { if (typeof $ !== 'undefined') { $('#sendTokensModal').modal('hide'); } else { const sendTokensModal = document.getElementById('sendTokensModal'); if (sendTokensModal) { sendTokensModal.style.display = 'none'; sendTokensModal.classList.remove('show'); } document.body.classList.remove('modal-open'); const backdrop = document.getElementById('modalBackdrop'); if (backdrop) { backdrop.remove(); } } // Reset form const sendTokensForm = document.getElementById('sendTokensForm'); if (sendTokensForm) { sendTokensForm.reset(); } } // Function to open send tokens modal async function openSendTokensModal() { if (!currentTokenId) { alert('Please verify the article first to get the token ID.'); return; } selectedTokenId = currentTokenId.toString(); const modalTokenId = document.getElementById('modalTokenId'); if (modalTokenId) { modalTokenId.textContent = selectedTokenId; } // Check user's balance await checkUserBalance(selectedTokenId); // Show the modal if (typeof $ !== 'undefined') { $('#sendTokensModal').modal('show'); } else { const sendTokensModal = document.getElementById('sendTokensModal'); if (sendTokensModal) { sendTokensModal.style.display = 'block'; sendTokensModal.classList.add('show'); } document.body.classList.add('modal-open'); const backdrop = document.createElement('div'); backdrop.className = 'modal-backdrop fade show'; backdrop.id = 'modalBackdrop'; document.body.appendChild(backdrop); } } // Check user's balance for the token async function checkUserBalance(tokenId) { try { const userAddress = await getUserAddressFromMetaMask(); if (!userAddress) { const modalTokenBalance = document.getElementById('modalTokenBalance'); if (modalTokenBalance) { modalTokenBalance.textContent = '0'; } return; } const balance = await contract.methods.balanceOf(userAddress, tokenId.toString()).call(); currentUserBalance = parseInt(balance.toString()); const modalTokenBalance = document.getElementById('modalTokenBalance'); const tokenAmount = document.getElementById('tokenAmount'); const confirmSendBtn = document.getElementById('confirmSendBtn'); if (modalTokenBalance) { modalTokenBalance.textContent = currentUserBalance.toLocaleString(); } if (tokenAmount) { tokenAmount.max = currentUserBalance; } if (confirmSendBtn) { if (currentUserBalance === 0) { confirmSendBtn.disabled = true; alert('You do not own any tokens of this article.'); } else { confirmSendBtn.disabled = false; } } } catch (error) { console.error('Error checking balance:', error); const modalTokenBalance = document.getElementById('modalTokenBalance'); if (modalTokenBalance) { modalTokenBalance.textContent = 'Error'; } } } // Initialize send tokens form document.addEventListener('DOMContentLoaded', function() { const sendTokensForm = document.getElementById('sendTokensForm'); if (sendTokensForm) { sendTokensForm.addEventListener('submit', handleSendTokens); } }); // Handle send tokens form submission async function handleSendTokens(e) { e.preventDefault(); const recipientAddress = document.getElementById('recipientAddress').value; const amount = parseInt(document.getElementById('tokenAmount').value); // Validate inputs if (!web3.utils.isAddress(recipientAddress)) { alert('Invalid recipient address'); return; } if (amount <= 0 || amount > currentUserBalance) { alert('Invalid amount. Must be between 1 and ' + currentUserBalance); return; } // Confirm transaction const confirmMessage = `Are you sure you want to send ${amount} tokens to ${recipientAddress}?`; if (!confirm(confirmMessage)) { return; } // Show spinner const sendTokensForm = document.getElementById('sendTokensForm'); const sendTokensSpinner = document.getElementById('sendTokensSpinner'); if (sendTokensForm) sendTokensForm.style.display = 'none'; if (sendTokensSpinner) sendTokensSpinner.classList.remove('d-none'); try { const userAddress = await getUserAddressFromMetaMask(); // Check balance one more time const currentBalance = await contract.methods.balanceOf(userAddress, selectedTokenId).call(); if (parseInt(currentBalance) < amount) { throw new Error('Insufficient balance'); } // Get gas price for legacy transaction const gasPrice = await web3.eth.getGasPrice(); // Estimate gas let gasEstimate; try { gasEstimate = await contract.methods.safeTransferFrom( userAddress, recipientAddress, selectedTokenId, amount.toString(), '0x' ).estimateGas({ from: userAddress }); } catch (error) { console.error('Gas estimation failed:', error); gasEstimate = 200000; } // Send the tokens const tx = await contract.methods.safeTransferFrom( userAddress, recipientAddress, selectedTokenId, amount.toString(), '0x' ).send({ from: userAddress, gas: Math.floor(Number(gasEstimate) * 1.2), gasPrice: gasPrice.toString() }); console.log('Transaction successful:', tx); // Show success message alert(`Successfully sent ${amount} tokens to ${recipientAddress}\n\nTransaction Hash: ${tx.transactionHash}`); // Close modal closeSendTokensModal(); // Refresh the page setTimeout(() => { checkTokenInfo(); }, 2000); } catch (error) { console.error('Error sending tokens:', error); alert('Error sending tokens: ' + error.message); } finally { // Hide spinner and show form if (sendTokensSpinner) sendTokensSpinner.classList.add('d-none'); if (sendTokensForm) sendTokensForm.style.display = 'block'; } } // Update the checkTokenInfo function const originalCheckTokenInfo = checkTokenInfo; checkTokenInfo = async function() { await originalCheckTokenInfo(); // If token exists, check and display user's balance if (currentTokenId) { const userAddress = await getUserAddressFromMetaMask(); if (userAddress) { try { const balance = await contract.methods.balanceOf(userAddress, currentTokenId.toString()).call(); const userBalance = parseInt(balance.toString()); // Update balance displays updateBalanceDisplays(userBalance, userAddress); // Show/hide send button based on balance const sendTokensBtn = document.getElementById('sendTokensBtn'); if (sendTokensBtn) { sendTokensBtn.style.display = userBalance > 0 ? 'inline-block' : 'none'; } // Update header balance updateHeaderBalance(userBalance); } catch (error) { console.error('Error checking balance:', error); } } } }; // Update balance displays function updateBalanceDisplays(userBalance, userAddress) { // Create or update balance display in token info section const tokenInfoSection = document.getElementById('tokenInfoSection'); let balanceDisplay = document.getElementById('userTokenBalance'); if (!balanceDisplay && tokenInfoSection) { const balanceDiv = document.createElement('div'); balanceDiv.className = 'text-center mt-2'; balanceDiv.innerHTML = ` <small class="text-muted">Your Balance:</small> <strong id="userTokenBalance" class="ms-1 text-success">${userBalance.toLocaleString()} tokens</strong> `; tokenInfoSection.appendChild(balanceDiv); } else if (balanceDisplay) { balanceDisplay.textContent = userBalance.toLocaleString() + ' tokens'; } // Update blockchain info section const blockchainInfo = document.querySelector('.blockchain-info'); if (blockchainInfo) { // Add account display let accountRow = document.getElementById('currentAccountRow'); if (!accountRow) { const accountDiv = document.createElement('div'); accountDiv.className = 'info-row'; accountDiv.id = 'currentAccountRow'; accountDiv.innerHTML = ` <div class="info-label">Connected Account:</div> <div class="info-value" id="currentAccountDisplay">${userAddress.substring(0, 6)}...${userAddress.substring(38)}</div> `; blockchainInfo.insertBefore(accountDiv, blockchainInfo.firstChild); } // Add balance display let balanceRow = document.getElementById('userBalanceRow'); if (!balanceRow) { const balanceDiv = document.createElement('div'); balanceDiv.className = 'info-row'; balanceDiv.id = 'userBalanceRow'; balanceDiv.innerHTML = ` <div class="info-label">Your Token Balance:</div> <div class="info-value text-success">${userBalance.toLocaleString()} tokens</div> `; blockchainInfo.appendChild(balanceDiv); } else { const balanceValue = balanceRow.querySelector('.info-value'); if (balanceValue) { balanceValue.textContent = userBalance.toLocaleString() + ' tokens'; } } } } // Update header balance function updateHeaderBalance(userBalance) { const headerBalanceBadge = document.getElementById('headerBalanceBadge'); const headerBalanceValue = document.getElementById('headerBalanceValue'); if (headerBalanceBadge && headerBalanceValue) { if (userBalance > 0) { headerBalanceBadge.style.display = 'inline-flex'; headerBalanceValue.textContent = userBalance.toLocaleString(); } else { headerBalanceBadge.style.display = 'none'; } } } // Listen for account changes in MetaMask if (window.ethereum) { window.ethereum.on('accountsChanged', function(accounts) { checkTokenInfo(); }); } // Periodic balance updates setInterval(async () => { if (currentTokenId) { try { const userAddress = await getUserAddressFromMetaMask(); if (userAddress) { const balance = await contract.methods.balanceOf(userAddress, currentTokenId.toString()).call(); const userBalance = parseInt(balance.toString()); updateHeaderBalance(userBalance); } } catch (error) { console.error('Error auto-refreshing balance:', error); } } }, 10000); // Utility functions function copyToClipboard(button) { const text = button.getAttribute('data-clipboard-text'); const textarea = document.createElement('textarea'); textarea.value = text; document.body.appendChild(textarea); textarea.select(); document.execCommand('copy'); document.body.removeChild(textarea); // Change button text temporarily const originalText = button.innerHTML; button.innerHTML = '<i class="fas fa-check me-1"></i> Copied!'; button.classList.remove('btn-outline-primary'); button.classList.add('btn-success'); setTimeout(() => { button.innerHTML = originalText; button.classList.remove('btn-success'); button.classList.add('btn-outline-primary'); }, 2000); } function toggleImageSize() { const img = document.getElementById('expandable-image'); if (img.style.transform === 'scale(1.5)') { img.style.transform = 'scale(1)'; img.style.zIndex = '1'; } else { img.style.transform = 'scale(1.5)'; img.style.zIndex = '100'; } } // Initialize on DOM ready document.addEventListener('DOMContentLoaded', function() { // Smooth scrolling document.querySelectorAll('a[href^="#"]').forEach(anchor => { anchor.addEventListener('click', function(e) { e.preventDefault(); const target = document.querySelector(this.getAttribute('href')); if (target) { target.scrollIntoView({ behavior: 'smooth', block: 'start' }); } }); }); // Card hover effects const cards = document.querySelectorAll('.card'); cards.forEach(card => { card.addEventListener('mouseenter', function() { this.style.transform = 'translateY(-5px)'; this.style.boxShadow = '0 8px 16px rgba(0, 0, 0, 0.1), 0 2px 4px rgba(0, 0, 0, 0.08)'; }); card.addEventListener('mouseleave', function() { this.style.transform = 'translateY(0)'; this.style.boxShadow = 'var(--card-shadow)'; }); }); // Update currentTokenId if it exists on the page const tokenIdElement = document.getElementById('tokenIdValue'); if (tokenIdElement && tokenIdElement.textContent) { currentTokenId = tokenIdElement.textContent; } }); // MetaMask NFT functions async function addNFTToMetaMask() { if (!currentTokenId) { const tokenIdElement = document.getElementById('tokenIdValue'); if (tokenIdElement && tokenIdElement.textContent) { currentTokenId = tokenIdElement.textContent; } else { alert('Please verify the article first to get the token ID.'); return; } } if (typeof window.ethereum === 'undefined') { alert('Please install MetaMask to add this NFT to your wallet.'); return; } try { const accounts = await window.ethereum.request({ method: 'eth_requestAccounts' }); const userAddress = accounts[0]; if (typeof web3 === 'undefined' || !contract) { web3 = new Web3(window.ethereum); contract = new web3.eth.Contract(CONTRACT_ABI, '0x95644003c57E6F55A65596E3D9Eac6813e3566dA'); } const balance = await contract.methods.balanceOf(userAddress, currentTokenId).call(); console.log('User balance for token', currentTokenId, ':', balance); if (balance == 0) { const metadata = await contract.methods.articleMetadata(currentTokenId).call(); const creator = metadata.creator || metadata[6]; alert(`You do not own any of this NFT.\n\nToken ID: ${currentTokenId}\nYour Balance: 0\nCreator: ${creator}\n\nOnly the article uploader or token holders can add it to MetaMask.`); return; } const uri = await contract.methods.uri(currentTokenId).call(); console.log('Token URI:', uri); const manualInstructions = `Your NFT Balance: ${balance} tokens\n\nTo add to MetaMask manually:\n\n1. Open MetaMask\n2. Make sure you're on Scimatic Network\n3. Go to NFTs tab\n4. Click "Import NFT"\n5. Enter:\n • Address: 0x95644003c57E6F55A65596E3D9Eac6813e3566dA\n • Token ID: ${currentTokenId}`; try { const wasAdded = await window.ethereum.request({ method: 'wallet_watchAsset', params: { type: 'ERC1155', options: { address: '0x95644003c57E6F55A65596E3D9Eac6813e3566dA', tokenId: currentTokenId.toString() } } }); if (wasAdded) { alert('NFT added to MetaMask!\n\n' + manualInstructions); } else { alert('Automatic add cancelled.\n\n' + manualInstructions); } } catch (error) { console.error('Automatic add failed:', error); alert(manualInstructions); } } catch (error) { console.error('Error:', error); alert('Error: ' + error.message + '\n\nMake sure you are connected to Scimatic Network!'); } } // Debug function async function debugTokenOwnership() { if (typeof window.ethereum === 'undefined') { alert('Please install MetaMask first.'); return; } try { const accounts = await window.ethereum.request({ method: 'eth_requestAccounts' }); const userAddress = accounts[0]; const web3 = new Web3(window.ethereum); const contractAddress = '0x95644003c57E6F55A65596E3D9Eac6813e3566dA'; const tokenId = document.getElementById('tokenIdValue')?.textContent || prompt('Enter Token ID:'); if (!tokenId) { alert('No token ID provided'); return; } if (!contract || typeof contract === 'undefined') { contract = new web3.eth.Contract(CONTRACT_ABI, contractAddress); } try { const balance = await contract.methods.balanceOf(userAddress, tokenId).call(); const exists = await contract.methods.tokenExists(tokenId).call(); const totalSupply = await contract.methods.totalSupply(tokenId).call(); const metadata = await contract.methods.articleMetadata(tokenId).call(); const creator = metadata.creator || metadata[6]; const uri = await contract.methods.uri(tokenId).call(); alert(`Token Ownership Debug:\n\nContract: ${contractAddress}\nUser: ${userAddress}\nToken ID: ${tokenId}\nYour Balance: ${balance}\nTotal Supply: ${totalSupply}\nToken Exists: ${exists}\nCreator: ${creator}\nURI: ${uri}\n\n${balance > 0 ? '✅ You own ' + balance + ' tokens!' : '❌ You do not own any of this token.'}`); } catch (error) { console.error('Contract interaction error:', error); alert('Error checking token: ' + error.message); } } catch (error) { console.error('Debug error:', error); alert('Error: ' + error.message + '\n\nMake sure you are on Scimatic network!'); } } // Make currentTokenId globally accessible var currentTokenId = null; // Add debug button document.addEventListener('DOMContentLoaded', function() { const blockchainActions = document.querySelector('.blockchain-actions'); if (blockchainActions && !document.querySelector('.btn-info.debug-btn')) { const debugBtn = document.createElement('button'); debugBtn.className = 'btn btn-info btn-sm mt-2 w-100 debug-btn'; debugBtn.innerHTML = '<i class="fas fa-bug me-1"></i> Debug Token Ownership'; debugBtn.onclick = debugTokenOwnership; blockchainActions.appendChild(debugBtn); } }); </script> </main> </div> <footer class="sc-footer"> <div class="container" style="max-width:1200px"> <div class="row g-4"> <div class="col-lg-3 col-sm-6"> <div class="sc-footer-title">About</div> <ul class="sc-footer-links"> <li><a href="https://scimatic.org/scimatic"><i class="fas fa-info-circle"></i> About</a></li> <li><a href="https://scimatic.org/team"><i class="fas fa-users"></i> Team</a></li> <li><a href="https://scimatic.org/joinus"><i class="fas fa-handshake"></i> Join Us</a></li> <li><a href="https://scimatic.org/privacy_security"><i class="fas fa-shield-alt"></i> Privacy and Security</a></li> <li><a href="/delete-account.html"><i class="fas fa-user-minus"></i> Delete Account</a></li> <li><a href="https://scimatic.org/documentationshome"><i class="fas fa-book"></i> Documentations</a></li> </ul> </div> <div class="col-lg-3 col-sm-6"> <div class="sc-footer-title">Services</div> <ul class="sc-footer-links"> <li><a href="https://scimatic.org/theses"><i class="fas fa-graduation-cap"></i> Thesis Manager</a></li> <li><a href="https://scimatic.org/subjects"><i class="fas fa-calendar-alt"></i> Semester Manager</a></li> <li><a href="https://scimatic.org/journalshome"><i class="fas fa-newspaper"></i> Journals</a></li> <li><a href="https://scimatic.org/conferenceshome"><i class="fas fa-microphone-alt"></i> Conferences</a></li> <li><a href="https://journament.com"><i class="fas fa-list-ol"></i> Journament Indexings</a></li> <li><a href="https://scimatic.org/api"><i class="fas fa-code"></i> API</a></li> </ul> </div> <div class="col-lg-3 col-sm-6"> <div class="sc-footer-title">Legal</div> <div class="sc-footer-legal"> <a href="https://scimatic.org/scimatic" class="sc-brand-link"><strong>SciMatic</strong></a> <span class="sc-copyright">© 2014–2026</span> <p class="sc-rights">All Rights Reserved!</p> </div> <a rel="license" href="http://creativecommons.org/licenses/by-nc-nd/4.0/" class="sc-cc-badge"> <img alt="Creative Commons License" width="88" src="https://mirrors.creativecommons.org/presskit/buttons/88x31/png/by-nc-nd.png"> </a> </div> <div class="col-lg-3 col-sm-6"> <div class="sc-footer-title">License</div> <p class="sc-footer-text"> This work is licensed under a <a rel="license" href="http://creativecommons.org/licenses/by-nc-nd/4.0/" class="sc-license-link"> Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License</a>. </p> <div class="sc-social-links"> <a href="#" title="Facebook"><i class="fab fa-facebook-f"></i></a> <a href="#" title="Twitter"><i class="fab fa-twitter"></i></a> <a href="#" title="LinkedIn"><i class="fab fa-linkedin-in"></i></a> <a href="#" title="GitHub"><i class="fab fa-github"></i></a> </div> </div> </div> </div> <div id="scibot-widget"> <button id="scibot-toggle" class="sc-contact-btn" title="Chat with SciBot"> <i class="fas fa-robot" id="scibot-icon-open"></i> <i class="fas fa-times" id="scibot-icon-close" style="display:none"></i> </button> <div id="scibot-window" style="display:none"> <div id="scibot-header"> <div style="display:flex;align-items:center;gap:8px"> <div style="width:32px;height:32px;border-radius:8px;background:rgba(255,255,255,.2);display:flex;align-items:center;justify-content:center;font-size:14px"><i class="fas fa-robot"></i></div> <div> <div style="font-weight:700;font-size:14px">SciBot</div> <div style="font-size:11px;opacity:.8">AI Assistant</div> </div> </div> <div style="display:flex;gap:6px"> <button onclick="document.getElementById('contact_admin')&&($('#contact_admin').modal?$('#contact_admin').modal('show'):void 0)" title="Contact Form" style="background:rgba(255,255,255,.15);border:none;color:#fff;width:28px;height:28px;border-radius:6px;cursor:pointer;font-size:12px"><i class="fas fa-envelope"></i></button> <button onclick="toggleScibot()" title="Close" style="background:rgba(255,255,255,.15);border:none;color:#fff;width:28px;height:28px;border-radius:6px;cursor:pointer;font-size:12px"><i class="fas fa-minus"></i></button> </div> </div> <div id="scibot-messages"> <div class="scibot-msg bot"><div class="scibot-bubble">Hi! I'm <strong>SciBot</strong>, your SciMatic assistant. I can help with manuscript submissions, journal info, and navigating the platform. How can I help?</div></div> </div> <div id="scibot-input-area"> <input type="text" id="scibot-hp" name="website" style="display:none!important" tabindex="-1" autocomplete="off"> <input type="text" id="scibot-input" placeholder="Ask about SciMatic..." maxlength="500" autocomplete="off"> <button id="scibot-send" onclick="scibotSend()"><i class="fas fa-paper-plane"></i></button> </div> </div> </div> <div class="modal fade" id="contact_admin" tabindex="-1" aria-labelledby="contactAdminLabel" aria-hidden="true"> <div class="modal-dialog modal-dialog-centered modal-lg"> <div class="modal-content" style="border:none;border-radius:14px;box-shadow:0 20px 60px rgba(0,0,0,.15)"> <div class="modal-header" style="background:var(--sc-primary,#4834d4);color:#fff;border-radius:14px 14px 0 0;padding:20px 24px;border:none"> <h5 class="modal-title" id="contactAdminLabel" style="font-weight:600"> <i class="fas fa-envelope me-2"></i> Contact Us </h5> <button type="button" class="btn-close btn-close-white" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body" style="padding:24px"> <div class="text-center py-3"> <div class="alert alert-warning d-flex align-items-center gap-3" style="border-radius:10px"> <i class="fas fa-lock fa-2x"></i> <div class="text-start"> <strong>Login Required</strong> <p class="mb-0">Register/Login first to send a message</p> </div> </div> <a href="https://scimatic.org/login" class="btn btn-primary btn-lg mt-2" style="border-radius:10px"> <i class="fas fa-sign-in-alt me-2"></i> Login </a> </div> </div> </div> </div> </div> </footer> <style> .sc-footer { background:linear-gradient(135deg,#1e293b,#334155); color:#cbd5e1;padding:48px 0 32px;font-size:14px;position:relative } .sc-footer-title { color:#fff;font-size:15px;font-weight:600;margin-bottom:20px; padding-bottom:12px;border-bottom:2px solid rgba(72,52,212,.5); display:inline-block } .sc-footer-links { list-style:none;padding:0;margin:0 } .sc-footer-links li { margin-bottom:10px } .sc-footer-links a { color:#94a3b8;text-decoration:none;display:inline-flex;align-items:center;gap:8px; font-size:13px;transition:all .2s } .sc-footer-links a i { color:#6366f1;font-size:12px;width:14px;text-align:center } .sc-footer-links a:hover { color:#fff;transform:translateX(3px) } .sc-footer-links a:hover i { color:#a5b4fc } .sc-footer-legal { margin-bottom:16px } .sc-brand-link { color:#a5b4fc;text-decoration:none;font-size:15px } .sc-brand-link:hover { color:#fff } .sc-copyright { color:#64748b;font-size:13px;margin-left:6px } .sc-rights { color:#64748b;font-size:12px;margin:4px 0 0 } .sc-cc-badge { display:inline-block;opacity:.7;transition:opacity .2s } .sc-cc-badge:hover { opacity:1 } .sc-cc-badge img { border-radius:4px } .sc-footer-text { font-size:13px;line-height:1.6;color:#94a3b8 } .sc-license-link { color:#a5b4fc;text-decoration:none } .sc-license-link:hover { color:#fff;text-decoration:underline } .sc-social-links { display:flex;gap:10px;margin-top:20px } .sc-social-links a { display:flex;align-items:center;justify-content:center; width:34px;height:34px;border-radius:8px; background:rgba(255,255,255,.08);color:#cbd5e1; text-decoration:none;transition:all .2s;font-size:14px } .sc-social-links a:hover { background:#6366f1;color:#fff;transform:translateY(-2px) } .sc-contact-btn { position:fixed;bottom:24px;right:24px; width:52px;height:52px;border-radius:14px; background:#6366f1;color:#fff;border:none; display:flex;align-items:center;justify-content:center; font-size:22px;cursor:pointer;z-index:1001; box-shadow:0 4px 16px rgba(99,102,241,.4);transition:all .2s } .sc-contact-btn:hover { background:#4f46e5;transform:scale(1.05) } #scibot-window { position:fixed;bottom:88px;right:24px;width:380px;height:500px; background:#fff;border-radius:16px;box-shadow:0 12px 48px rgba(0,0,0,.18); z-index:1000;display:flex;flex-direction:column;overflow:hidden; animation:scibotSlideUp .25s ease } @keyframes scibotSlideUp { from{opacity:0;transform:translateY(20px)} to{opacity:1;transform:translateY(0)} } #scibot-header { background:linear-gradient(135deg,#6366f1,#4f46e5);color:#fff; padding:14px 16px;display:flex;align-items:center;justify-content:space-between;flex-shrink:0 } #scibot-messages { flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:12px; background:#f8fafc } #scibot-messages::-webkit-scrollbar { width:4px } #scibot-messages::-webkit-scrollbar-thumb { background:#cbd5e1;border-radius:4px } .scibot-msg { display:flex;gap:8px;max-width:88% } .scibot-msg.bot { align-self:flex-start } .scibot-msg.user { align-self:flex-end;flex-direction:row-reverse } .scibot-bubble { padding:10px 14px;border-radius:12px;font-size:13px;line-height:1.5;word-break:break-word } .scibot-msg.bot .scibot-bubble { background:#fff;color:#334155;border:1px solid #e2e8f0;border-bottom-left-radius:4px } .scibot-msg.user .scibot-bubble { background:#6366f1;color:#fff;border-bottom-right-radius:4px } .scibot-bubble a { color:#6366f1;text-decoration:underline } .scibot-msg.user .scibot-bubble a { color:#c7d2fe } .scibot-typing { display:flex;gap:4px;padding:10px 14px } .scibot-typing span { width:7px;height:7px;border-radius:50%;background:#94a3b8;animation:scibotDot 1.2s infinite } .scibot-typing span:nth-child(2) { animation-delay:.2s } .scibot-typing span:nth-child(3) { animation-delay:.4s } @keyframes scibotDot { 0%,80%,100%{opacity:.3;transform:scale(.8)} 40%{opacity:1;transform:scale(1)} } #scibot-input-area { display:flex;gap:8px;padding:12px 16px;border-top:1px solid #e2e8f0;background:#fff;flex-shrink:0 } #scibot-input { flex:1;border:1px solid #e2e8f0;border-radius:10px;padding:10px 14px; font-size:13px;outline:none;transition:border .15s } #scibot-input:focus { border-color:#6366f1;box-shadow:0 0 0 3px rgba(99,102,241,.1) } #scibot-send { width:40px;height:40px;border-radius:10px;background:#6366f1;color:#fff; border:none;cursor:pointer;display:flex;align-items:center;justify-content:center; font-size:14px;transition:background .15s;flex-shrink:0 } #scibot-send:hover { background:#4f46e5 } #scibot-send:disabled { background:#cbd5e1;cursor:not-allowed } @media(max-width:767px){ .sc-footer { padding:32px 0 24px } .sc-contact-btn { width:46px;height:46px;font-size:20px;bottom:16px;right:16px;border-radius:12px } #scibot-window { bottom:74px;right:8px;left:8px;width:auto;height:70vh;max-height:500px } } </style> <script> (function(){ var scibotOpen = false; var scibotHistory = []; var scibotBusy = false; window.toggleScibot = function() { scibotOpen = !scibotOpen; document.getElementById('scibot-window').style.display = scibotOpen ? 'flex' : 'none'; document.getElementById('scibot-icon-open').style.display = scibotOpen ? 'none' : ''; document.getElementById('scibot-icon-close').style.display = scibotOpen ? '' : 'none'; if (scibotOpen) { var input = document.getElementById('scibot-input'); setTimeout(function(){ input.focus(); }, 200); } }; document.getElementById('scibot-toggle').addEventListener('click', toggleScibot); document.getElementById('scibot-input').addEventListener('keydown', function(e) { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); scibotSend(); } }); function appendMsg(role, html) { var wrap = document.createElement('div'); wrap.className = 'scibot-msg ' + role; var bubble = document.createElement('div'); bubble.className = 'scibot-bubble'; bubble.innerHTML = html; wrap.appendChild(bubble); var msgs = document.getElementById('scibot-messages'); msgs.appendChild(wrap); msgs.scrollTop = msgs.scrollHeight; return wrap; } function showTyping() { var wrap = document.createElement('div'); wrap.className = 'scibot-msg bot'; wrap.id = 'scibot-typing'; wrap.innerHTML = '<div class="scibot-typing"><span></span><span></span><span></span></div>'; var msgs = document.getElementById('scibot-messages'); msgs.appendChild(wrap); msgs.scrollTop = msgs.scrollHeight; } function hideTyping() { var el = document.getElementById('scibot-typing'); if (el) el.remove(); } function escapeHtml(text) { var div = document.createElement('div'); div.textContent = text; return div.innerHTML; } function formatReply(text) { // Convert markdown-style links and URLs to clickable links text = escapeHtml(text); // Convert **bold** text = text.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>'); // Convert URLs to links with navigation text = text.replace(/(https?:\/\/scimatic\.org[^\s<,)]*?)([.!?:;]?)(?=\s|<|$)/g, '<a href="$1" onclick="window.location.href=\'$1\';return false;">$1</a>$2'); // Convert newlines text = text.replace(/\n/g, '<br>'); return text; } window.scibotSend = function() { if (scibotBusy) return; var input = document.getElementById('scibot-input'); var msg = input.value.trim(); if (!msg) return; input.value = ''; appendMsg('user', escapeHtml(msg)); scibotHistory.push({ role: 'user', text: msg }); scibotBusy = true; document.getElementById('scibot-send').disabled = true; showTyping(); var csrfToken = document.querySelector('meta[name="csrf-token"]'); var token = csrfToken ? csrfToken.getAttribute('content') : ''; var xhr = new XMLHttpRequest(); xhr.open('POST', '/api/chatbot'); xhr.setRequestHeader('Content-Type', 'application/json'); xhr.setRequestHeader('X-CSRF-TOKEN', token); xhr.setRequestHeader('Accept', 'application/json'); xhr.timeout = 35000; xhr.onload = function() { hideTyping(); scibotBusy = false; document.getElementById('scibot-send').disabled = false; if (xhr.status === 429) { appendMsg('bot', 'You\'re sending messages too quickly. Please wait a moment and try again.'); return; } try { var data = JSON.parse(xhr.responseText); if (data.reply) { appendMsg('bot', formatReply(data.reply)); scibotHistory.push({ role: 'model', text: data.reply }); // Keep history manageable if (scibotHistory.length > 20) scibotHistory = scibotHistory.slice(-20); } else { appendMsg('bot', 'Sorry, I couldn\'t process that. Please try again.'); } } catch(e) { appendMsg('bot', 'Something went wrong. Please try again.'); } }; xhr.onerror = xhr.ontimeout = function() { hideTyping(); scibotBusy = false; document.getElementById('scibot-send').disabled = false; appendMsg('bot', 'I\'m having trouble connecting. Please try again in a moment.'); }; var hp = document.getElementById('scibot-hp'); xhr.send(JSON.stringify({ message: msg, history: scibotHistory.slice(-10), website: hp ? hp.value : '' })); }; })(); </script> </body> </html>