init geek calc
Some checks failed
Deploy to GitHub Pages / build-and-deploy (push) Has been cancelled
Some checks failed
Deploy to GitHub Pages / build-and-deploy (push) Has been cancelled
This commit is contained in:
184
calculator.js
Normal file
184
calculator.js
Normal file
@@ -0,0 +1,184 @@
|
||||
// Calculator core module
|
||||
const Calculator = (function() {
|
||||
class Calculator {
|
||||
constructor() {
|
||||
this.clear();
|
||||
}
|
||||
|
||||
clear() {
|
||||
this.currentValue = '0';
|
||||
this.operator = null;
|
||||
this.previousValue = null;
|
||||
this.shouldResetDisplay = false;
|
||||
}
|
||||
|
||||
getCurrentDisplay() {
|
||||
return this.currentValue;
|
||||
}
|
||||
|
||||
// Add two numbers
|
||||
add(a, b) {
|
||||
return a + b;
|
||||
}
|
||||
|
||||
// Subtract two numbers
|
||||
subtract(a, b) {
|
||||
return a - b;
|
||||
}
|
||||
|
||||
// Multiply two numbers
|
||||
multiply(a, b) {
|
||||
return a * b;
|
||||
}
|
||||
|
||||
// Divide two numbers (handles division by zero)
|
||||
divide(a, b) {
|
||||
if (b === 0) {
|
||||
return Infinity;
|
||||
}
|
||||
return a / b;
|
||||
}
|
||||
|
||||
// Handle percentage operations
|
||||
percentage(value, percent = null) {
|
||||
if (percent !== null) {
|
||||
// If two arguments, calculate percentage of value
|
||||
return value * (percent / 100);
|
||||
} else {
|
||||
// If single argument, convert to decimal (e.g., 50% = 0.5)
|
||||
return value / 100;
|
||||
}
|
||||
}
|
||||
|
||||
// Toggle sign of a number
|
||||
toggleSign(value) {
|
||||
return -value;
|
||||
}
|
||||
|
||||
// Evaluate an arithmetic expression in standard notation
|
||||
evaluate(expression) {
|
||||
try {
|
||||
// Basic validation to prevent dangerous eval usage
|
||||
// Only allow numbers, operators, parentheses, and decimal points
|
||||
if (!/^[0-9+\-*/(). %]+$/.test(expression)) {
|
||||
return 'Error';
|
||||
}
|
||||
|
||||
// Handle percentage expressions by evaluating them properly
|
||||
// Replace 'X%' with '(X/100)' for proper evaluation
|
||||
let processedExpression = expression.replace(/(\d+(\.\d+)?)%/g, (match, number) => {
|
||||
return `(${number}/100)`;
|
||||
});
|
||||
|
||||
// Handle expressions like "100 + 10%" by replacing with "100 + (100 * 0.1)"
|
||||
processedExpression = processedExpression.replace(/(\d+(?:\.\d+)?)\s*\+\s*(\d+(?:\.\d+)?)%/g, (match, base, percent) => {
|
||||
return `${base} + (${base} * ${percent}/100)`;
|
||||
});
|
||||
|
||||
processedExpression = processedExpression.replace(/(\d+(?:\.\d+)?)\s*-\s*(\d+(?:\.\d+)?)%/g, (match, base, percent) => {
|
||||
return `${base} - (${base} * ${percent}/100)`;
|
||||
});
|
||||
|
||||
processedExpression = processedExpression.replace(/(\d+(?:\.\d+)?)\s*\*\s*(\d+(?:\.\d+)?)%/g, (match, base, percent) => {
|
||||
return `${base} * (${percent}/100)`;
|
||||
});
|
||||
|
||||
// Use Function constructor instead of eval for safety
|
||||
const result = new Function('return ' + processedExpression)();
|
||||
|
||||
// Check for invalid results
|
||||
if (isNaN(result) || !isFinite(result)) {
|
||||
return 'Error';
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (error) {
|
||||
return 'Error';
|
||||
}
|
||||
}
|
||||
|
||||
// Process input for UI interactions
|
||||
processInput(value) {
|
||||
if (['+', '-', '*', '/'].includes(value)) {
|
||||
// Handle operator input
|
||||
if (this.operator && !this.shouldResetDisplay) {
|
||||
// If there's already an operator, evaluate the current expression
|
||||
this.calculate();
|
||||
}
|
||||
|
||||
this.operator = value;
|
||||
this.previousValue = parseFloat(this.currentValue);
|
||||
this.shouldResetDisplay = true;
|
||||
} else if (value === '=') {
|
||||
this.calculate();
|
||||
} else if (value === 'C' || value === 'CE') {
|
||||
this.clear();
|
||||
} else if (value === '±') {
|
||||
// Toggle sign
|
||||
this.currentValue = this.toggleSign(parseFloat(this.currentValue)).toString();
|
||||
} else if (value === '.') {
|
||||
// Handle decimal point
|
||||
if (this.shouldResetDisplay) {
|
||||
this.currentValue = '0.';
|
||||
this.shouldResetDisplay = false;
|
||||
} else if (!this.currentValue.includes('.')) {
|
||||
this.currentValue += '.';
|
||||
}
|
||||
} else if (['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'].includes(value)) {
|
||||
// Handle number input
|
||||
if (this.shouldResetDisplay) {
|
||||
this.currentValue = value;
|
||||
this.shouldResetDisplay = false;
|
||||
} else {
|
||||
if (this.currentValue === '0') {
|
||||
this.currentValue = value;
|
||||
} else {
|
||||
this.currentValue += value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Perform calculation based on current values
|
||||
calculate() {
|
||||
if (this.operator === null || this.previousValue === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
const current = parseFloat(this.currentValue);
|
||||
let result;
|
||||
|
||||
switch (this.operator) {
|
||||
case '+':
|
||||
result = this.add(this.previousValue, current);
|
||||
break;
|
||||
case '-':
|
||||
result = this.subtract(this.previousValue, current);
|
||||
break;
|
||||
case '*':
|
||||
result = this.multiply(this.previousValue, current);
|
||||
break;
|
||||
case '/':
|
||||
result = this.divide(this.previousValue, current);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
// Check for invalid results
|
||||
if (isNaN(result) || !isFinite(result)) {
|
||||
this.currentValue = 'Error';
|
||||
} else {
|
||||
// Round to avoid floating point precision issues
|
||||
this.currentValue = Math.round(result * 100000000) / 100000000;
|
||||
this.currentValue = this.currentValue.toString();
|
||||
}
|
||||
|
||||
this.operator = null;
|
||||
this.previousValue = null;
|
||||
this.shouldResetDisplay = true;
|
||||
}
|
||||
}
|
||||
|
||||
return { Calculator };
|
||||
})();
|
||||
Reference in New Issue
Block a user