1// VARIABLE DECLARATION 2const LANDING_PAGE = document.getElementById("landing-page"); 3const MOBILE_MENU_TOGGLES = document.getElementsByClassName("mobile-menu-toggle"); 4const MOBILE_MENU_OVERLAY = document.getElementById("mobile-menu-overlay"); 5const MOBILE_MENU_CLOSE = document.getElementById("mobile-menu-close"); 6const NAVBAR_LINKS = document.getElementById("navbar-links"); 7const DROP_LINK = document.getElementsByClassName("drop-down-link"); 8const DROP_LINK_CONTENT = document.getElementsByClassName("drop-link-content"); 9const MAIN_TABS = document.getElementsByClassName("project-tab"); 10const TAB_CONTENTS = document.getElementsByClassName("tab-contents"); 11const FEE_BREAKDOWN_GRID = document.getElementById("fee-breakdown-grid"); 12const FEE_DETAILS = document.getElementsByClassName("fee-details"); 13const CURRENCY_BUTTONS = document.getElementsByClassName("currency-select"); 14const OUT_CURRENCY = document.getElementById("output-currency-select"); 15const OUTPUT_CONT = document.getElementById("receive-money-output-box"); 16const OUTPUT_VALUE = document.getElementById("output-value"); 17const RECEIVE_TEXT = document.getElementById("receive-text"); 18const INSUFF_ERROR = document.getElementById("insufficient-amount-error"); 19const INSUFF_TEXT = document.getElementById("insufficient-amount-error-text"); 20const ARRIVAL_TIME = document.getElementById("arrival-time"); 21const CLICKABLE_OBJECTS = document.querySelectorAll("[tabindex]"); 22const CASH_REGISTER = document.getElementById("cash-register"); 23 24const BASE_CHARGE = 0.8; 25const MONTH = ["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]; 26const EXCHANGE_RATES = { 27 EUR: 1, 28 GBP: 0.90032, 29 USD: 1.14541, 30 INR: 80.3551 31}; 32 33let isFeeDetailVisible = false; 34let isMenuVisible = false; 35let menuType = ""; 36let transferSpeed = 0.005; 37let exRate = 0; 38let tomorrow = new Date(); 39 40 41 42// FUNCTIONS 43 44function menuTypeQuery() { 45 menuType = window.innerWidth >= 741 ? "laptop" : "mobile"; 46 adjustMenuFormat(); 47 setToggleType(); 48 closeDropLinks(); 49} 50 51function toggleMobileMenu() { 52 isMenuVisible = !isMenuVisible; 53 adjustMenuFormat(); 54} 55 56function adjustMenuFormat() { 57 if (menuType === "mobile") { 58 if (isMenuVisible === false) { 59 NAVBAR_LINKS.style.display = "none"; 60 LANDING_PAGE.style.opacity = "1"; 61 MOBILE_MENU_OVERLAY.style.display = "none"; 62 MOBILE_MENU_OVERLAY.style.opacity = "0"; 63 MOBILE_MENU_CLOSE.style.display = "none"; 64 } else { 65 NAVBAR_LINKS.style.display = "inline-block"; 66 LANDING_PAGE.style.opacity = "0.4"; 67 MOBILE_MENU_OVERLAY.style.display = "block"; 68 MOBILE_MENU_OVERLAY.style.opacity = "0.5"; 69 MOBILE_MENU_CLOSE.style.display = "block"; 70 } 71 } else { 72 NAVBAR_LINKS.style.display = "inline-block"; 73 } 74} 75 76function openDropLink() { 77 closeDropLinks(); 78 this.children.item(1).style.display = "block"; 79 if (menuType === "mobile") { 80 this.style.color = "var(--logocol)"; 81 } 82} 83 84function closeDropLinks() { 85 [...DROP_LINK_CONTENT].map(content => content.style.display = "none"); 86 [...DROP_LINK].map(link => link.style.color = 87 menuType === "mobile" ? "var(--darkcol)" : "white"); 88} 89 90function openTab() { 91 [...MAIN_TABS].map(tab => tab.classList.remove("selected-tab")); 92 [...TAB_CONTENTS].map(content => content.style.display = "none"); 93 document.getElementById(`${this.id}-content`).style.display = "block"; 94 this.classList.add("selected-tab"); 95}; 96 97function calculateFee(val) { 98 return (BASE_CHARGE + (val - BASE_CHARGE) * transferSpeed).toFixed(2); 99} 100 101function calculateConvertValue(val) { 102 return (val - calculateFee(val)).toFixed(2); 103} 104 105function getSendCurrency() { 106 return document.getElementById("input-currency-select").value; 107} 108 109function getReceiveCurrency() { 110 return document.getElementById("output-currency-select").value; 111} 112 113// Maybe a better method would be, on the server-side, to update an EX_RATE object every x minutes and to then resend it to the client-side in bacthes every few minutes, rather than the client changing currencies and waiting a second or two between each change. This would mean the change is almost instant (as the data is stored on their computer) and improves UX and decrease the risk of the API being slow/overloaded/broken. 114// function getExRate(value, callback) { 115// REQ.onload = () => { 116// if (REQ.readyState === 4 && REQ.status === 200) { 117// callback(value, REQ.response); 118// } 119// } 120// REQ.open("GET", `https://free.currencyconverterapi.com/api/v6/convert?q=${getSendCurrency()}_${getReceiveCurrency()}&compact=ultra&apiKey=4bee894984d26fd53193`, true); 121// REQ.send(); 122// } 123 124// function setExRate(value, result) { 125// exRate = JSON.parse(result)[`${getSendCurrency()}_${getReceiveCurrency()}`].toFixed(5); 126// renderNewValues(value); 127// } 128 129// This asynchronous function makes the workflow much easier to work with/read than the previous XHR/callback method. 130async function setExchangeRate() { 131 const CURRENCIES = `${getSendCurrency()}_${getReceiveCurrency()}`; 132 await fetch(`https://free.currencyconverterapi.com/api/v6/convert?q=${CURRENCIES}&compact=ultra&apiKey=4bee894984d26fd53193`) 133 .then((response) => response.json()) 134 .then((json) => exRate = json[CURRENCIES].toFixed(5)); 135 runCalculator(); 136} 137 138function calculateReceiveValue(val) { 139 return (calculateConvertValue(val) * exRate).toFixed(2); 140} 141 142// Random savings of 4.7% for demo 143function calculateSavings(val) { 144 return (calculateConvertValue(val) * 0.047).toFixed(2); 145} 146 147// Update the DOM with newly-calculated values 148function renderNewValues(input) { 149 const SEND = getSendCurrency(); 150 151 if (isThereAnError(input) || isInputInvalid(input)) { return }; 152 153 document.getElementById("fee-value").innerHTML = 154 `-${calculateFee(input)} ${SEND}`; 155 156 document.getElementById("amount-to-convert").innerHTML = 157 `${calculateConvertValue(input)} ${SEND}`; 158 159 document.getElementById("exchange-rate").innerHTML = 160 exRate; 161 162 document.getElementById("total-savings").innerHTML = 163 `${calculateSavings(input)} ${SEND}`; 164 165 OUTPUT_VALUE.value = calculateReceiveValue(input); 166} 167 168function isThereAnError(val) { 169 if (val <= 0.8) { 170 OUTPUT_VALUE.value = "0.00"; 171 INSUFF_ERROR.style.display = "block"; 172 INSUFF_TEXT.innerHTML = `Please enter an amount more than 0.01 ${getReceiveCurrency()}`; 173 OUTPUT_CONT.classList.add("cash-value-box-error"); 174 OUT_CURRENCY.style.height = "70%"; 175 OUT_CURRENCY.style.borderRadius = "0 3px 0 0"; 176 RECEIVE_TEXT.style.color = "#C73B3B"; 177 return true; 178 } else { 179 INSUFF_ERROR.style.display = "none"; 180 RECEIVE_TEXT.style.color = "var(--shapecol)"; 181 OUTPUT_CONT.classList.remove("cash-value-box-error"); 182 OUT_CURRENCY.style.height = "100%"; 183 OUT_CURRENCY.style.borderRadius = "0 3px 3px 0"; 184 return false;
185 } 186} 187 188function isInputInvalid(input) { 189 if (input.match(/(?=\D)(?!\.)/) || input.match(/\.(.{3}|.*\.)/)) { 190 document.getElementById("output-value").value = "0.00"; 191 return true; 192 } 193} 194 195function resetInput(val) { 196 document.getElementById("input-value").placeholder = "1,000"; 197 runCalculator(); 198} 199 200function runCalculator() { 201 const INPUT_VALUE = document.getElementById("input-value").value || "1000"; 202 renderNewValues(INPUT_VALUE); 203 // getExRate(INPUT_VALUE, setExRate); 204} 205 206function toggleFeeBreakdown() { 207 isFeeDetailVisible = !isFeeDetailVisible; 208 showFees(); 209} 210 211function showFees() { 212 if (isFeeDetailVisible === true) { 213 FEE_BREAKDOWN_GRID.style.gridTemplateRows = "30px 30px 30px"; 214 [...FEE_DETAILS].map(cell => cell.style.visibility = "visible"); 215 } else { 216 FEE_BREAKDOWN_GRID.style.gridTemplateRows = "30px 0px 30px"; 217 [...FEE_DETAILS].map(cell => cell.style.visibility = "hidden"); 218 } 219} 220 221function setArrivalTime() { 222 if (this.value === "fast-easy-transfer") { 223 transferSpeed = 0.005; 224 ARRIVAL_TIME.innerHTML = "in seconds!"; 225 } else { 226 transferSpeed = 0.003; 227 tomorrow.setDate(tomorrow.getDate() + 1); 228 ARRIVAL_TIME.innerHTML = `by ${tomorrow.getDate()} ${MONTH[tomorrow.getMonth()]}`; 229 } 230 runCalculator(); 231} 232 233function removeMouseFocus() { 234 [...CLICKABLE_OBJECTS].map(obj => obj.classList.remove("removeMouseFocus")); 235 this.classList.add("removeMouseFocus"); 236} 237 238// Determine the correct event and assign event listener to drop links 239function setToggleType() { 240 [...DROP_LINK].map(droplink => determineToggleType(droplink)); 241} 242 243// Determine whether drop links open on click(mobile) or hover(laptop) 244function determineToggleType(droplink) { 245 if (menuType === "mobile") { 246 droplink.addEventListener("click", openDropLink); 247 droplink.removeEventListener("mouseover", openDropLink); 248 droplink.removeEventListener("mouseout", closeDropLinks); 249 } else { 250 droplink.addEventListener("mouseover", openDropLink); 251 droplink.addEventListener("mouseout", closeDropLinks); 252 } 253} 254 255// function resizeiFrame(iframe) { 256// document.getElementById(iframe).contentWindow.postMessage("i need ur height pls", "*"); 257// } 258 259// function iFrameHeightPipe(event) { 260// if (event.origin !== "https://fitfingers.github.io") { 261// return; 262// } 263// document.getElementById(event.data[0]).height = parseInt(event.data[1] * 0.48); 264// } 265 266function hidePhoto() { 267 if (window.innerWidth >= 926) { 268 document.getElementById("my-story-tab-content").style.display = "none"; 269 } 270} 271 272 273 274 275// EVENT LISTENERS 276 277window.addEventListener("resize", menuTypeQuery); 278window.addEventListener("resize", hidePhoto); 279// window.addEventListener("resize", () => resizeiFrame("cash-register")); 280// window.addEventListener("message", iFrameHeightPipe); 281 282[...CURRENCY_BUTTONS].map(button => button.addEventListener("change", setExchangeRate)); 283 284document.getElementById("transfer-speed").addEventListener("change", setArrivalTime); 285 286document.getElementById("show-fee-button").addEventListener("click", toggleFeeBreakdown); 287 288[...MAIN_TABS].map(tab => tab.addEventListener("click", openTab)); 289 290[...CLICKABLE_OBJECTS].map(obj => obj.addEventListener("click", removeMouseFocus)); 291 292[...MOBILE_MENU_TOGGLES].map(function(toggle) { 293 toggle.addEventListener("click", toggleMobileMenu); 294 toggle.addEventListener("click", closeDropLinks); 295}); 296 297 298 299 300// WINDOW.ONLOAD/PAGE SETUP 301window.onload = function() { 302 // getExRate(setExRate); 303 setExchangeRate(); 304 resetInput(); 305 menuTypeQuery(); 306 // resizeiFrame("cash-register"); 307}
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.