Skip to content

Commit b3cb0d1

Browse files
Merge pull request steam-bell-92#627 from madhavcodes25/fix/issue-568
Fix/Fixed bugs in the web calculator
2 parents d630ae4 + c8ffc21 commit b3cb0d1

2 files changed

Lines changed: 234 additions & 180 deletions

File tree

web-app/js/projects.js

Lines changed: 148 additions & 115 deletions
Original file line numberDiff line numberDiff line change
@@ -699,136 +699,169 @@ function getCalculatorHTML() {
699699
</style>
700700
`;
701701
}
702-
let calculatorKeyboardAdded = false;
702+
703703
function initCalculator() {
704-
const display = document.getElementById('calcDisplay');
705-
let currentValue = '0';
706-
let previousValue = '';
707-
let operation = '';
708-
709-
document.querySelectorAll('.calc-btn').forEach(btn => {
710-
btn.addEventListener('click', () => {
711-
const value = btn.getAttribute('data-value');
712-
const action = btn.getAttribute('data-action');
704+
const display = document.getElementById("calcDisplay");
705+
if (!display) return;
706+
let expression = "";
707+
708+
function update() {
709+
display.textContent = expression || "0";
710+
}
711+
712+
function format(expr) {
713+
return expr
714+
.replace(/÷/g, "/")
715+
.replace(/×/g, "*")
716+
.replace(/\^/g, "**");
717+
}
718+
719+
function safeEval(expr) {
720+
try {
721+
if (!expr) return "";
722+
let result = eval(format(expr));
723+
if (result === undefined) return "";
724+
if (isNaN(result)) return "Error";
725+
return String(result);
726+
} catch {
727+
return "Error";
728+
}
729+
}
730+
731+
function applyFunction(type) {
732+
try {
733+
let value = eval(format(expression || "0"));
734+
let result;
735+
switch (type) {
736+
case "sin": result = Math.sin(value); break;
737+
case "cos": result = Math.cos(value); break;
738+
case "tan": result = Math.tan(value); break;
739+
case "sqrt": result = Math.sqrt(value); break;
740+
case "square": result = value * value; break;
741+
case "inv": result = 1 / value; break;
742+
}
743+
if (isNaN(result)) return "Error";
744+
return String(result);
745+
} catch {
746+
return "Error";
747+
}
748+
}
749+
750+
751+
function clearIfFinished() {
752+
if (expression === "Error" || expression === "NaN") {
753+
expression = "";
754+
}
755+
}
756+
757+
document.querySelectorAll(".calc-btn").forEach((btn) => {
758+
btn.addEventListener("click", () => {
759+
clearIfFinished();
713760

714-
if (value) {
715-
handleNumber(value);
716-
} else if (action) {
717-
handleAction(action);
761+
const value = btn.dataset.value;
762+
const action = btn.dataset.action;
763+
764+
if (value !== undefined) {
765+
if (value === ".") {
766+
767+
const lastOperand = expression.split(/[\+\-\*\/\^\(\)]/).pop();
768+
if (lastOperand.includes(".")) return;
769+
}
770+
expression += value;
771+
update();
772+
return;
718773
}
719-
720-
updateDisplay();
774+
775+
if (!action) return;
776+
777+
778+
switch (action) {
779+
case "clear":
780+
expression = "";
781+
break;
782+
case "delete":
783+
if (expression === "Infinity" || expression === "-Infinity") {
784+
expression = "";
785+
} else {
786+
expression = expression.slice(0, -1);
787+
}
788+
break;
789+
case "=":
790+
expression = safeEval(expression);
791+
break;
792+
case "sin":
793+
case "cos":
794+
case "tan":
795+
case "sqrt":
796+
case "square":
797+
case "inv":
798+
expression = applyFunction(action);
799+
break;
800+
case "^":
801+
case "+":
802+
case "-":
803+
case "*":
804+
case "/":
805+
806+
const lastChar = expression.slice(-1);
807+
if (["+", "-", "*", "/", "^"].includes(lastChar)) {
808+
expression = expression.slice(0, -1) + action;
809+
} else {
810+
expression += action;
811+
}
812+
break;
813+
default:
814+
expression += action;
815+
}
816+
update();
721817
});
722818
});
723-
if (!calculatorKeyboardAdded) {
724-
document.addEventListener("keydown", (e) => {
725-
const display = document.getElementById("calcDisplay");
726-
if (!display) return;
727819

820+
document.addEventListener("keydown", (e) => {
728821
const key = e.key;
822+
if (!document.getElementById("calcDisplay")) return;
729823

730-
if (
731-
key === "Enter" ||
732-
key === " " ||
733-
key === "Backspace" ||
734-
key === "Escape" ||
735-
key === "=" ||
736-
key === "+" ||
737-
key === "-" ||
738-
key === "*" ||
739-
key === "/" ||
740-
key === "^" ||
741-
key === "." ||
742-
/^[0-9]$/.test(key) ||
743-
key.startsWith("Arrow")
744-
) {
824+
// Whitelist allowed keys to prevent typing letters
825+
const allowedKeys = ["Enter", "Backspace", "Escape", "=", "+", "-", "*", "/", "^", ".", "(", ")"];
826+
if (allowedKeys.includes(key) || /^[0-9]$/.test(key)) {
745827
e.preventDefault();
828+
} else {
829+
return;
746830
}
747831

832+
clearIfFinished();
833+
748834
if (/^[0-9]$/.test(key)) {
749-
handleNumber(key);
750-
}
751-
else if (key === ".") {
752-
handleNumber(".");
753-
}
754-
else if (["+", "-", "*", "/"].includes(key)) {
755-
handleAction(key);
756-
}
757-
else if (key === "^") {
758-
handleAction("**");
759-
}
760-
else if (key === "Enter" || key === "=") {
761-
handleAction("=");
762-
}
763-
else if (key === "Backspace") {
764-
handleAction("delete");
765-
}
766-
else if (key === "Escape" || key.toLowerCase() === "c") {
767-
handleAction("clear");
835+
expression += key;
836+
} else if (key === ".") {
837+
const lastOperand = expression.split(/[\+\-\*\/\^\(\)]/).pop();
838+
if (!lastOperand.includes(".")) {
839+
expression += ".";
840+
}
841+
} else if (["+", "-", "*", "/", "^"].includes(key)) {
842+
const lastChar = expression.slice(-1);
843+
if (["+", "-", "*", "/", "^"].includes(lastChar)) {
844+
expression = expression.slice(0, -1) + key;
845+
} else {
846+
expression += key;
847+
}
848+
} else if (key === ")" || key === "(") {
849+
expression += key;
850+
} else if (key === "Enter" || key === "=") {
851+
expression = safeEval(expression);
852+
} else if (key === "Backspace") {
853+
if (expression === "Infinity" || expression === "-Infinity") {
854+
expression = "";
855+
} else {
856+
expression = expression.slice(0, -1);
857+
}
858+
} else if (key === "Escape" || key.toLowerCase() === "c") {
859+
expression = "";
768860
}
769-
770-
updateDisplay();
861+
update();
771862
});
772863

773-
calculatorKeyboardAdded = true;
774-
}
775-
776-
function handleNumber(num) {
777-
if (currentValue === '0' || currentValue === 'Error') {
778-
currentValue = num;
779-
} else {
780-
currentValue += num;
781-
}
782-
}
783-
784-
function handleAction(action) {
785-
if (action === 'clear') {
786-
currentValue = '0';
787-
previousValue = '';
788-
operation = '';
789-
} else if (action === 'delete') {
790-
currentValue = currentValue.slice(0, -1) || '0';
791-
} else if (action === '=') {
792-
calculate();
793-
} else {
794-
if (previousValue && operation) {
795-
calculate();
796-
}
797-
previousValue = currentValue;
798-
currentValue = '0';
799-
operation = action;
800-
}
801-
}
802-
803-
function calculate() {
804-
try {
805-
const prev = parseFloat(previousValue);
806-
const curr = parseFloat(currentValue);
807-
let result;
808-
809-
switch (operation) {
810-
case '+': result = prev + curr; break;
811-
case '-': result = prev - curr; break;
812-
case '*': result = prev * curr; break;
813-
case '/': result = prev / curr; break;
814-
case '**': result = Math.pow(prev, curr); break;
815-
default: return;
816-
}
817-
818-
currentValue = result.toString();
819-
previousValue = '';
820-
operation = '';
821-
} catch (e) {
822-
currentValue = 'Error';
823-
}
824-
}
825-
826-
function updateDisplay() {
827-
const display = document.getElementById('calcDisplay');
828-
if (display) {
829-
display.textContent = currentValue;
830-
}
831-
}
864+
update();
832865
}
833866

834867
// ============================================

0 commit comments

Comments
 (0)