<!-- Calculator widget. This file should contain all required CSS, HTML, and JS for it. --> <style> #calc-text { background: var(--whoogle-dark-page-bg); padding: 8px; border-radius: 8px; text-align: right; font-family: monospace; font-size: 16px; color: var(--whoogle-dark-text); } #prev-equation { text-align: right; } .error-border { border: 1px solid red; } #calc-btns { display: grid; grid-template-columns: repeat(6, 1fr); grid-template-rows: repeat(5, 1fr); gap: 5px; } #calc-btns button { background: #313141; color: var(--whoogle-dark-text); border: none; border-radius: 8px; padding: 8px; cursor: pointer; } #calc-btns button:hover { background: #414151; } #calc-btns .common { background: #51516a; } #calc-btns .common:hover { background: #61617a; } #calc-btn-0 { grid-row: 5; grid-column: 3; } #calc-btn-1 { grid-row: 4; grid-column: 3; } #calc-btn-2 { grid-row: 4; grid-column: 4; } #calc-btn-3 { grid-row: 4; grid-column: 5; } #calc-btn-4 { grid-row: 3; grid-column: 3; } #calc-btn-5 { grid-row: 3; grid-column: 4; } #calc-btn-6 { grid-row: 3; grid-column: 5; } #calc-btn-7 { grid-row: 2; grid-column: 3; } #calc-btn-8 { grid-row: 2; grid-column: 4; } #calc-btn-9 { grid-row: 2; grid-column: 5; } #calc-btn-EQ { grid-row: 5; grid-column: 5; } #calc-btn-PT { grid-row: 5; grid-column: 4; } #calc-btn-BCK { grid-row: 5; grid-column: 6; } #calc-btn-ADD { grid-row: 4; grid-column: 6; } #calc-btn-SUB { grid-row: 3; grid-column: 6; } #calc-btn-MLT { grid-row: 2; grid-column: 6; } #calc-btn-DIV { grid-row: 1; grid-column: 6; } #calc-btn-CLR { grid-row: 1; grid-column: 5; } #calc-btn-PRC{ grid-row: 1; grid-column: 4; } #calc-btn-RP { grid-row: 1; grid-column: 3; } #calc-btn-LP { grid-row: 1; grid-column: 2; } #calc-btn-ABS { grid-row: 1; grid-column: 1; } #calc-btn-SIN { grid-row: 2; grid-column: 2; } #calc-btn-COS { grid-row: 3; grid-column: 2; } #calc-btn-TAN { grid-row: 4; grid-column: 2; } #calc-btn-SQR { grid-row: 5; grid-column: 2; } #calc-btn-EXP { grid-row: 2; grid-column: 1; } #calc-btn-E { grid-row: 3; grid-column: 1; } #calc-btn-PI { grid-row: 4; grid-column: 1; } #calc-btn-LOG { grid-row: 5; grid-column: 1; } </style> <p id="prev-equation"></p> <div id="calculator-widget"> <p id="calc-text">0</p> <div id="calc-btns"> <button id="calc-btn-0" class="common">0</button> <button id="calc-btn-1" class="common">1</button> <button id="calc-btn-2" class="common">2</button> <button id="calc-btn-3" class="common">3</button> <button id="calc-btn-4" class="common">4</button> <button id="calc-btn-5" class="common">5</button> <button id="calc-btn-6" class="common">6</button> <button id="calc-btn-7" class="common">7</button> <button id="calc-btn-8" class="common">8</button> <button id="calc-btn-9" class="common">9</button> <button id="calc-btn-EQ" class="common">=</button> <button id="calc-btn-PT" class="common">.</button> <button id="calc-btn-BCK">⬅</button> <button id="calc-btn-ADD">+</button> <button id="calc-btn-SUB">-</button> <button id="calc-btn-MLT">x</button> <button id="calc-btn-DIV">/</button> <button id="calc-btn-CLR">C</button> <button id="calc-btn-PRC">%</button> <button id="calc-btn-RP">)</button> <button id="calc-btn-LP">(</button> <button id="calc-btn-ABS">|x|</button> <button id="calc-btn-SIN">sin</button> <button id="calc-btn-COS">cos</button> <button id="calc-btn-TAN">tan</button> <button id="calc-btn-SQR">√</button> <button id="calc-btn-EXP">^</button> <button id="calc-btn-E">ℇ</button> <button id="calc-btn-PI">π</button> <button id="calc-btn-LOG">log</button> </div> </div> <script> // JS does not have this by default. // from https://www.freecodecamp.org/news/how-to-factorialize-a-number-in-javascript-9263c89a4b38/ function factorial(num) { if (num < 0) return -1; else if (num === 0) return 1; else { return (num * factorial(num - 1)); } } // returns true if the user is currently focused on the calculator widget function usingCalculator() { let activeElement = document.activeElement; while (true) { if (!activeElement) return false; if (activeElement.id === "calculator-wrapper") return true; activeElement = activeElement.parentElement; } } const $ = q => document.querySelectorAll(q); // key bindings for commonly used buttons const keybindings = { "0": "0", "1": "1", "2": "2", "3": "3", "4": "4", "5": "5", "6": "6", "7": "7", "8": "8", "9": "9", "Enter": "EQ", ".": "PT", "+": "ADD", "-": "SUB", "*": "MLT", "/": "DIV", "%": "PRC", "c": "CLR", "(": "LP", ")": "RP", "Backspace": "BCK", } window.addEventListener("keydown", event => { if (!usingCalculator()) return; if (event.key === "Enter" && document.activeElement.id !== "search-bar") event.preventDefault(); if (keybindings[event.key]) document.getElementById("calc-btn-" + keybindings[event.key]).click(); }) // calculates the string const calc = () => { var mathtext = document.getElementById("calc-text"); var statement = mathtext.innerHTML // remove empty () .replace("()", "") // special constants .replace("π", "(Math.PI)") .replace("ℇ", "(Math.E)") // turns 3(1+2) into 3*(1+2) (for example) .replace(/(?<=[0-9\)])(?<=[^+\-x*\/%^])\(/, "x(") // same except reversed .replace(/\)(?=[0-9\(])(?=[^+\-x*\/%^])/, ")x") // replace human friendly x with JS * .replace("x", "*") // trig & misc functions .replace("sin", "Math.sin") .replace("cos", "Math.cos") .replace("tan", "Math.tan") .replace("√", "Math.sqrt") .replace("^", "**") .replace("abs", "Math.abs") .replace("log", "Math.log") ; // add any missing )s to the end while(true) if ( (statement.match(/\(/g) || []).length > (statement.match(/\)/g) || []).length ) statement += ")"; else break; // evaluate the expression. console.log("calculating [" + statement + "]"); try { var result = eval(statement); document.getElementById("prev-equation").innerHTML = mathtext.innerHTML + " = "; mathtext.innerHTML = result; mathtext.classList.remove("error-border"); } catch (e) { mathtext.classList.add("error-border"); console.error(e); } } const updateCalc = (e) => { // character(s) recieved from button var c = event.target.innerHTML; var mathtext = document.getElementById("calc-text"); if (mathtext.innerHTML === "0") mathtext.innerHTML = ""; // special cases switch (c) { case "C": // Clear mathtext.innerHTML = "0"; break; case "⬅": // Delete mathtext.innerHTML = mathtext.innerHTML.slice(0, -1); if (mathtext.innerHTML.length === 0) { mathtext.innerHTML = "0"; } break; case "=": calc() break; case "sin": case "cos": case "tan": case "log": case "√": mathtext.innerHTML += `${c}(`; break; case "|x|": mathtext.innerHTML += "abs(" break; case "+": case "-": case "x": case "/": case "%": case "^": if (mathtext.innerHTML.length === 0) mathtext.innerHTML = "0"; // prevent typing 2 operators in a row if (mathtext.innerHTML.match(/[+\-x\/%^] $/)) mathtext.innerHTML = mathtext.innerHTML.slice(0, -3); mathtext.innerHTML += ` ${c} `; break; default: mathtext.innerHTML += c; } } for (let i of $("#calc-btns button")) { i.addEventListener('click', event => { updateCalc(event); }) } </script>