Skip to content

Commit c8ffc21

Browse files
committed
Fix calculator decimal and infinity logic
1 parent 82d2cc3 commit c8ffc21

1 file changed

Lines changed: 148 additions & 115 deletions

File tree

web-app/js/projects.js

Lines changed: 148 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -1195,136 +1195,169 @@ function getCalculatorHTML() {
11951195
</style>
11961196
`;
11971197
}
1198-
let calculatorKeyboardAdded = false;
1198+
11991199
function initCalculator() {
1200-
const display = document.getElementById('calcDisplay');
1201-
let currentValue = '0';
1202-
let previousValue = '';
1203-
let operation = '';
1204-
1205-
document.querySelectorAll('.calc-btn').forEach(btn => {
1206-
btn.addEventListener('click', () => {
1207-
const value = btn.getAttribute('data-value');
1208-
const action = btn.getAttribute('data-action');
1200+
const display = document.getElementById("calcDisplay");
1201+
if (!display) return;
1202+
let expression = "";
1203+
1204+
function update() {
1205+
display.textContent = expression || "0";
1206+
}
1207+
1208+
function format(expr) {
1209+
return expr
1210+
.replace(/÷/g, "/")
1211+
.replace(/×/g, "*")
1212+
.replace(/\^/g, "**");
1213+
}
1214+
1215+
function safeEval(expr) {
1216+
try {
1217+
if (!expr) return "";
1218+
let result = eval(format(expr));
1219+
if (result === undefined) return "";
1220+
if (isNaN(result)) return "Error";
1221+
return String(result);
1222+
} catch {
1223+
return "Error";
1224+
}
1225+
}
1226+
1227+
function applyFunction(type) {
1228+
try {
1229+
let value = eval(format(expression || "0"));
1230+
let result;
1231+
switch (type) {
1232+
case "sin": result = Math.sin(value); break;
1233+
case "cos": result = Math.cos(value); break;
1234+
case "tan": result = Math.tan(value); break;
1235+
case "sqrt": result = Math.sqrt(value); break;
1236+
case "square": result = value * value; break;
1237+
case "inv": result = 1 / value; break;
1238+
}
1239+
if (isNaN(result)) return "Error";
1240+
return String(result);
1241+
} catch {
1242+
return "Error";
1243+
}
1244+
}
1245+
1246+
1247+
function clearIfFinished() {
1248+
if (expression === "Error" || expression === "NaN") {
1249+
expression = "";
1250+
}
1251+
}
1252+
1253+
document.querySelectorAll(".calc-btn").forEach((btn) => {
1254+
btn.addEventListener("click", () => {
1255+
clearIfFinished();
12091256

1210-
if (value) {
1211-
handleNumber(value);
1212-
} else if (action) {
1213-
handleAction(action);
1257+
const value = btn.dataset.value;
1258+
const action = btn.dataset.action;
1259+
1260+
if (value !== undefined) {
1261+
if (value === ".") {
1262+
1263+
const lastOperand = expression.split(/[\+\-\*\/\^\(\)]/).pop();
1264+
if (lastOperand.includes(".")) return;
1265+
}
1266+
expression += value;
1267+
update();
1268+
return;
12141269
}
1215-
1216-
updateDisplay();
1270+
1271+
if (!action) return;
1272+
1273+
1274+
switch (action) {
1275+
case "clear":
1276+
expression = "";
1277+
break;
1278+
case "delete":
1279+
if (expression === "Infinity" || expression === "-Infinity") {
1280+
expression = "";
1281+
} else {
1282+
expression = expression.slice(0, -1);
1283+
}
1284+
break;
1285+
case "=":
1286+
expression = safeEval(expression);
1287+
break;
1288+
case "sin":
1289+
case "cos":
1290+
case "tan":
1291+
case "sqrt":
1292+
case "square":
1293+
case "inv":
1294+
expression = applyFunction(action);
1295+
break;
1296+
case "^":
1297+
case "+":
1298+
case "-":
1299+
case "*":
1300+
case "/":
1301+
1302+
const lastChar = expression.slice(-1);
1303+
if (["+", "-", "*", "/", "^"].includes(lastChar)) {
1304+
expression = expression.slice(0, -1) + action;
1305+
} else {
1306+
expression += action;
1307+
}
1308+
break;
1309+
default:
1310+
expression += action;
1311+
}
1312+
update();
12171313
});
12181314
});
1219-
if (!calculatorKeyboardAdded) {
1220-
document.addEventListener("keydown", (e) => {
1221-
const display = document.getElementById("calcDisplay");
1222-
if (!display) return;
12231315

1316+
document.addEventListener("keydown", (e) => {
12241317
const key = e.key;
1318+
if (!document.getElementById("calcDisplay")) return;
12251319

1226-
if (
1227-
key === "Enter" ||
1228-
key === " " ||
1229-
key === "Backspace" ||
1230-
key === "Escape" ||
1231-
key === "=" ||
1232-
key === "+" ||
1233-
key === "-" ||
1234-
key === "*" ||
1235-
key === "/" ||
1236-
key === "^" ||
1237-
key === "." ||
1238-
/^[0-9]$/.test(key) ||
1239-
key.startsWith("Arrow")
1240-
) {
1320+
// Whitelist allowed keys to prevent typing letters
1321+
const allowedKeys = ["Enter", "Backspace", "Escape", "=", "+", "-", "*", "/", "^", ".", "(", ")"];
1322+
if (allowedKeys.includes(key) || /^[0-9]$/.test(key)) {
12411323
e.preventDefault();
1324+
} else {
1325+
return;
12421326
}
12431327

1328+
clearIfFinished();
1329+
12441330
if (/^[0-9]$/.test(key)) {
1245-
handleNumber(key);
1246-
}
1247-
else if (key === ".") {
1248-
handleNumber(".");
1249-
}
1250-
else if (["+", "-", "*", "/"].includes(key)) {
1251-
handleAction(key);
1252-
}
1253-
else if (key === "^") {
1254-
handleAction("**");
1255-
}
1256-
else if (key === "Enter" || key === "=") {
1257-
handleAction("=");
1258-
}
1259-
else if (key === "Backspace") {
1260-
handleAction("delete");
1261-
}
1262-
else if (key === "Escape" || key.toLowerCase() === "c") {
1263-
handleAction("clear");
1331+
expression += key;
1332+
} else if (key === ".") {
1333+
const lastOperand = expression.split(/[\+\-\*\/\^\(\)]/).pop();
1334+
if (!lastOperand.includes(".")) {
1335+
expression += ".";
1336+
}
1337+
} else if (["+", "-", "*", "/", "^"].includes(key)) {
1338+
const lastChar = expression.slice(-1);
1339+
if (["+", "-", "*", "/", "^"].includes(lastChar)) {
1340+
expression = expression.slice(0, -1) + key;
1341+
} else {
1342+
expression += key;
1343+
}
1344+
} else if (key === ")" || key === "(") {
1345+
expression += key;
1346+
} else if (key === "Enter" || key === "=") {
1347+
expression = safeEval(expression);
1348+
} else if (key === "Backspace") {
1349+
if (expression === "Infinity" || expression === "-Infinity") {
1350+
expression = "";
1351+
} else {
1352+
expression = expression.slice(0, -1);
1353+
}
1354+
} else if (key === "Escape" || key.toLowerCase() === "c") {
1355+
expression = "";
12641356
}
1265-
1266-
updateDisplay();
1357+
update();
12671358
});
12681359

1269-
calculatorKeyboardAdded = true;
1270-
}
1271-
1272-
function handleNumber(num) {
1273-
if (currentValue === '0' || currentValue === 'Error') {
1274-
currentValue = num;
1275-
} else {
1276-
currentValue += num;
1277-
}
1278-
}
1279-
1280-
function handleAction(action) {
1281-
if (action === 'clear') {
1282-
currentValue = '0';
1283-
previousValue = '';
1284-
operation = '';
1285-
} else if (action === 'delete') {
1286-
currentValue = currentValue.slice(0, -1) || '0';
1287-
} else if (action === '=') {
1288-
calculate();
1289-
} else {
1290-
if (previousValue && operation) {
1291-
calculate();
1292-
}
1293-
previousValue = currentValue;
1294-
currentValue = '0';
1295-
operation = action;
1296-
}
1297-
}
1298-
1299-
function calculate() {
1300-
try {
1301-
const prev = parseFloat(previousValue);
1302-
const curr = parseFloat(currentValue);
1303-
let result;
1304-
1305-
switch (operation) {
1306-
case '+': result = prev + curr; break;
1307-
case '-': result = prev - curr; break;
1308-
case '*': result = prev * curr; break;
1309-
case '/': result = prev / curr; break;
1310-
case '**': result = Math.pow(prev, curr); break;
1311-
default: return;
1312-
}
1313-
1314-
currentValue = result.toString();
1315-
previousValue = '';
1316-
operation = '';
1317-
} catch (e) {
1318-
currentValue = 'Error';
1319-
}
1320-
}
1321-
1322-
function updateDisplay() {
1323-
const display = document.getElementById('calcDisplay');
1324-
if (display) {
1325-
display.textContent = currentValue;
1326-
}
1327-
}
1360+
update();
13281361
}
13291362

13301363
// ============================================

0 commit comments

Comments
 (0)