1// js/popup.js 2var voteButton = null; 3var walletHandler = null; 4 5const checkRequiredVotingFieds = (fields) => { 6 let valid = true; 7 fields.forEach((field) => { 8 if (field && field.required && !field.value.trim()) { 9 valid = false; 10 field.classList.add('error'); 11 setTimeout(() => { 12 field.classList.remove('error'); 13 }, 3000); 14 } 15 }); 16 return valid; 17} 18 19const resetPopup = (id) => { 20 hideVotingElementsById(['qr-container', 'blur-overlay', 'payment-loading', 'payment-popup', 'thank-you-popup'], 'coinsnap-bitcoin-voting-', id) 21 showVotingElementById('public-donor-popup', 'flex', 'coinsnap-bitcoin-voting-', id) 22 voteButton.disabled = false; 23 const payInWalletBtn = document.getElementById(`coinsnap-bitcoin-voting-pay-in-wallet${id}`); 24 if (walletHandler) { 25 payInWalletBtn.removeEventListener('click', walletHandler); 26 walletHandler = null; 27 } 28} 29 30const addWindowListeners = () => { 31 window.addEventListener("click", function (event) { 32 const votingForms = document.getElementsByClassName('coinsnap-bitcoin-voting-form'); 33 for (let i = 0; i < votingForms.length; i++) { 34 const votingForm = votingForms[i]; 35 const pollId = votingForm.dataset.pollId 36 const qrContainer = document.getElementById(`coinsnap-bitcoin-voting-qr-container${pollId}`); 37 const element = event.target 38 if (qrContainer.style.display == 'flex') { 39 if (element.classList.contains('close-popup') || (!qrContainer.contains(event.target) && !element.id.includes('pay') && !element.classList.contains('poll-option'))) { 40 resetPopup(pollId) 41 42 } 43 } 44 } 45 }); 46 47} 48 49const popupButtonListener = (exchangeRates, pollId, amount, publicDonor) => { 50 51 document.getElementById(`coinsnap-bitcoin-voting-public-donors-pay${pollId}`)?.addEventListener('click', async () => { 52 event.preventDefault(); 53 var retryId = ''; 54 55 const option = voteButton.dataset.option 56 const optionName = document.querySelector(`.poll-option[data-option='${option}']`)?.textContent 57 const firstNameField = document.getElementById(`coinsnap-bitcoin-voting-first-name${pollId}`); 58 const lastNameField = document.getElementById(`coinsnap-bitcoin-voting-last-name${pollId}`); 59 const emailField = document.getElementById(`coinsnap-bitcoin-voting-donor-email${pollId}`); 60 const streetField = document.getElementById(`coinsnap-bitcoin-voting-street${pollId}`); 61 const houseNumberField = document.getElementById(`coinsnap-bitcoin-voting-house-number${pollId}`); 62 const postalCodeField = document.getElementById(`coinsnap-bitcoin-voting-postal${pollId}`); 63 const cityField = document.getElementById(`coinsnap-bitcoin-voting-town${pollId}`); 64 const countryField = document.getElementById(`coinsnap-bitcoin-voting-country${pollId}`); 65 const address = `${streetField?.value ?? ''} ${houseNumberField?.value ?? ''}, ${postalCodeField?.value ?? ''} ${cityField?.value ?? ''}, ${countryField?.value ?? ''}`; 66 const customField = document.getElementById(`coinsnap-bitcoin-voting-custom${pollId}`); 67 const customNameField = document.getElementById(`coinsnap-bitcoin-voting-custom-name${pollId}`); 68 const customContent = customNameField?.textContent && customField?.value ? `${customNameField.textContent}: ${customField.value}` : '' 69 const validForm = !publicDonor || checkRequiredVotingFieds([firstNameField, lastNameField, emailField, streetField, houseNumberField, postalCodeField, cityField, countryField, customField]); 70 const voteTitle = voteButton.dataset.name ?? ''; 71 const metadata = { 72 donorName: `${firstNameField.value} ${lastNameField?.value ?? ''}`, 73 donorEmail: emailField?.value, 74 donorAddress: address != ' , , ' ? address : '', 75 donorCustom: customContent, 76 formType: 'Bitcoin Voting', 77 amount: `${amount} sats`, 78 publicDonor: publicDonor || 0, 79 modal: true, 80 optionId: option, 81 option: optionName, 82 pollId: pollId, 83 voteTitle: voteTitle, 84 } 85 if (!validForm) return; 86 87 showVotingElementById('payment-loading', 'flex', 'coinsnap-bitcoin-voting-', pollId) 88 hideVotingElementById('public-donor-popup', 'coinsnap-bitcoin-voting-', pollId) 89 90
91 const res = await createVotingInvoice(amount, 'VOTED for {IDK}', 'SATS', undefined, 'Bitcoin Voting', false, metadata) 92 93 if (res) { 94 // Update addresses 95 const qrLightning = res.lightningInvoice 96 const qrBitcoin = res.onchainAddress 97 98 if (qrBitcoin) { 99 showVotingElementsById(['btc-wrapper', 'qr-btc-container'], 'flex', 'coinsnap-bitcoin-voting-', pollId) 100 } 101 102 // Hide spinner and show qr code stuff 103 showVotingElementsById(['qrCode', 'lightning-wrapper', 'qr-fiat', 'qrCodeBtc'], 'block', 'coinsnap-bitcoin-voting-', pollId) 104 showVotingElementsById(['qr-summary', 'qr-lightning-container', 'pay-in-wallet'], 'flex', 'coinsnap-bitcoin-voting-', pollId) 105 hideVotingElementById('payment-loading', 'coinsnap-bitcoin-voting-', pollId) 106 showVotingElementById('payment-popup', 'flex', 'coinsnap-bitcoin-voting-', pollId) 107 // Update actuall data 108 document.getElementById(`coinsnap-bitcoin-voting-qrCode${pollId}`).src = res.qrCodes.lightningQR; 109 document.getElementById(`coinsnap-bitcoin-voting-qr-lightning${pollId}`).textContent = `${qrLightning.substring(0, 20)}...${qrLightning.slice(-15)}`; 110 document.getElementById(`coinsnap-bitcoin-voting-qr-btc${pollId}`).textContent = `${qrBitcoin.substring(0, 20)}...${qrBitcoin.slice(-15)}`; 111 document.getElementById(`coinsnap-bitcoin-voting-qr-amount${pollId}`).textContent = `Amount: ${res.amount} sats`; 112 113 // Copy address functionallity 114 const copyLightning = document.querySelector(`#coinsnap-bitcoin-voting-qr-lightning-container${pollId} .qr-copy-icon`); 115 const copyBtc = document.querySelector(`#coinsnap-bitcoin-voting-qr-btc-container${pollId} .qr-copy-icon`); 116 copyLightning.addEventListener('click', () => { navigator.clipboard.writeText(qrLightning); }); 117 copyBtc.addEventListener('click', () => { navigator.clipboard.writeText(qrBitcoin); }); 118 119 // Add fiat amount 120 if (exchangeRates['EUR']) { 121 document.getElementById(`coinsnap-bitcoin-voting-qr-fiat${pollId}`).textContent = `â ${(res.amount * exchangeRates['EUR'])?.toFixed(3)} EUR`; 122 // Store the handler function when adding the listener 123 walletHandler = function () { 124 window.location.href = `lightning:${qrLightning}`; 125 }; 126 document.getElementById(`coinsnap-bitcoin-voting-pay-in-wallet${pollId}`).addEventListener('click', walletHandler); 127 } 128 129 // Reset retry counter 130 var retryNum = 0; 131 retryId = res.id 132 133 const checkPaymentStatus = () => { 134 fetch(`/wp-json/voting/v1/check-payment-status/${res.id}`) 135 .then(response => response.json()) 136 .then(data => { 137 const qrContainer = document.getElementById(`coinsnap-bitcoin-voting-qr-container${pollId}`); 138 if (data.status === 'completed') { 139 showVotingElementById('thank-you-popup', 'flex', 'coinsnap-bitcoin-voting-', pollId) 140 hideVotingElementById('payment-popup', 'coinsnap-bitcoin-voting-', pollId) 141 setCookie(`coinsnap_poll_${pollId}`, option, 30 * 24 * 60); 142 setTimeout(() => { 143 resetPopup(pollId); 144 document.getElementById(`check-results${pollId}`).click(); 145 }, 2000); 146 setTimeout(() => { 147 document.getElementById(`return-button${pollId}`).click(); 148 }, 7000); 149 150 151 } else if (qrContainer.style.display != 'flex') { 152 retryId = ''; 153 } 154 else if (retryNum < 180 && retryId == res.id) { 155 retryNum++; 156 checkPaymentStatus(); 157 } else { 158 //TODO Invoice expired 159 } 160 }) 161 .catch(error => { 162 console.error('Error checking payment status:', error); 163 retryNum++; 164 if (retryId == res.id) { 165 setTimeout(checkPaymentStatus, 5000); 166 } 167 }); 168 } 169 checkPaymentStatus() 170 171 } 172 else { 173 console.error('Error creating invoice') 174 } 175 176 }); 177} 178 179const addVotingPopupListener = (button, publicDonor, amount, pollId) => { 180 button.addEventListener('click', async () => { 181 button.disabled = true; 182 event.preventDefault(); 183 voteButton = button 184 if (publicDonor != 1) {
185 const publicDonorsPay = document.getElementById(`coinsnap-bitcoin-voting-public-donors-pay${pollId}`); 186 publicDonorsPay.click() 187 } 188 showVotingElementsById(['blur-overlay', 'qr-container'], 'flex', 'coinsnap-bitcoin-voting-', pollId) 189 }); 190 191 192}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.