parent
9e8dd00f10
commit
9588b4fb5c
@ -0,0 +1,276 @@
|
||||
class Calculator {
|
||||
constructor() {
|
||||
this.display = document.querySelector('.display-screen');
|
||||
this.buttons = document.querySelector('.buttons');
|
||||
this.currentNumber = '0';
|
||||
this.previousNumber = null;
|
||||
this.operation = null;
|
||||
this.waitingForOperand = false;
|
||||
this.maxDigits = 8;
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
this.buttons.addEventListener('click', this.handleButtonClick.bind(this));
|
||||
this.updateDisplay();
|
||||
}
|
||||
|
||||
handleButtonClick(event) {
|
||||
const button = event.target;
|
||||
|
||||
if (!button.classList.contains('btn')) return;
|
||||
|
||||
if (button.hasAttribute('data-number')) {
|
||||
this.inputNumber(button.getAttribute('data-number'));
|
||||
} else if (button.hasAttribute('data-action')) {
|
||||
const action = button.getAttribute('data-action');
|
||||
this.handleAction(action);
|
||||
}
|
||||
}
|
||||
|
||||
inputNumber(number) {
|
||||
if (this.waitingForOperand) {
|
||||
this.currentNumber = number;
|
||||
this.waitingForOperand = false;
|
||||
} else {
|
||||
// Check if we're at the digit limit
|
||||
const currentLength = this.currentNumber.replace('.', '').length;
|
||||
if (currentLength >= this.maxDigits) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.currentNumber = this.currentNumber === '0' ? number : this.currentNumber + number;
|
||||
}
|
||||
|
||||
this.updateDisplay();
|
||||
}
|
||||
|
||||
handleAction(action) {
|
||||
switch (action) {
|
||||
case 'clear-all':
|
||||
this.clearAll();
|
||||
break;
|
||||
case 'clear':
|
||||
this.clear();
|
||||
break;
|
||||
case 'sign':
|
||||
this.changeSign();
|
||||
break;
|
||||
case 'decimal':
|
||||
this.inputDecimal();
|
||||
break;
|
||||
case 'add':
|
||||
case 'subtract':
|
||||
case 'multiply':
|
||||
case 'divide':
|
||||
this.performOperation(action);
|
||||
break;
|
||||
case 'calculate':
|
||||
this.calculate();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
clearAll() {
|
||||
this.currentNumber = '0';
|
||||
this.previousNumber = null;
|
||||
this.operation = null;
|
||||
this.waitingForOperand = false;
|
||||
this.updateDisplay();
|
||||
}
|
||||
|
||||
clear() {
|
||||
if (this.operation && this.waitingForOperand) {
|
||||
// If last action was an operation, clear it and show previous number
|
||||
this.operation = null;
|
||||
this.waitingForOperand = false;
|
||||
this.currentNumber = this.previousNumber || '0';
|
||||
this.previousNumber = null;
|
||||
} else {
|
||||
// Clear current number
|
||||
this.currentNumber = '0';
|
||||
}
|
||||
this.updateDisplay();
|
||||
}
|
||||
|
||||
changeSign() {
|
||||
if (this.currentNumber !== '0') {
|
||||
this.currentNumber = this.currentNumber.charAt(0) === '-'
|
||||
? this.currentNumber.slice(1)
|
||||
: '-' + this.currentNumber;
|
||||
this.updateDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
inputDecimal() {
|
||||
if (this.waitingForOperand) {
|
||||
this.currentNumber = '0.';
|
||||
this.waitingForOperand = false;
|
||||
} else if (this.currentNumber.indexOf('.') === -1) {
|
||||
this.currentNumber += '.';
|
||||
}
|
||||
this.updateDisplay();
|
||||
}
|
||||
|
||||
performOperation(nextOperation) {
|
||||
const inputValue = parseFloat(this.currentNumber);
|
||||
|
||||
if (this.previousNumber === null) {
|
||||
this.previousNumber = inputValue;
|
||||
} else if (this.operation) {
|
||||
const currentValue = this.previousNumber || 0;
|
||||
const newValue = this.performCalculation(this.operation, currentValue, inputValue);
|
||||
|
||||
if (this.isError(newValue)) {
|
||||
this.showError();
|
||||
return;
|
||||
}
|
||||
|
||||
this.currentNumber = String(newValue);
|
||||
this.previousNumber = newValue;
|
||||
}
|
||||
|
||||
this.waitingForOperand = true;
|
||||
this.operation = nextOperation;
|
||||
this.updateDisplay();
|
||||
}
|
||||
|
||||
calculate() {
|
||||
const inputValue = parseFloat(this.currentNumber);
|
||||
|
||||
if (this.previousNumber !== null && this.operation) {
|
||||
const newValue = this.performCalculation(this.operation, this.previousNumber, inputValue);
|
||||
|
||||
if (this.isError(newValue)) {
|
||||
this.showError();
|
||||
return;
|
||||
}
|
||||
|
||||
this.currentNumber = String(newValue);
|
||||
this.previousNumber = null;
|
||||
this.operation = null;
|
||||
this.waitingForOperand = true;
|
||||
this.updateDisplay();
|
||||
}
|
||||
}
|
||||
|
||||
performCalculation(operation, firstOperand, secondOperand) {
|
||||
switch (operation) {
|
||||
case 'add':
|
||||
return firstOperand + secondOperand;
|
||||
case 'subtract':
|
||||
return firstOperand - secondOperand;
|
||||
case 'multiply':
|
||||
return firstOperand * secondOperand;
|
||||
case 'divide':
|
||||
if (secondOperand === 0) {
|
||||
return NaN;
|
||||
}
|
||||
return firstOperand / secondOperand;
|
||||
default:
|
||||
return secondOperand;
|
||||
}
|
||||
}
|
||||
|
||||
isError(value) {
|
||||
if (isNaN(value) || !isFinite(value)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check if result exceeds 8 digits (excluding decimal point)
|
||||
const stringValue = String(Math.abs(value));
|
||||
const integerPart = stringValue.split('.')[0];
|
||||
|
||||
return integerPart.length > this.maxDigits;
|
||||
}
|
||||
|
||||
showError() {
|
||||
this.display.textContent = 'ERR';
|
||||
this.display.classList.add('error');
|
||||
|
||||
setTimeout(() => {
|
||||
this.display.classList.remove('error');
|
||||
this.clearAll();
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
formatNumber(number) {
|
||||
const parts = number.split('.');
|
||||
const integerPart = parts[0];
|
||||
const decimalPart = parts[1];
|
||||
|
||||
// Format integer part with commas for readability
|
||||
const formattedInteger = integerPart.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
|
||||
|
||||
if (decimalPart !== undefined) {
|
||||
// Limit decimal places to 3
|
||||
const limitedDecimal = decimalPart.slice(0, 3);
|
||||
return formattedInteger + '.' + limitedDecimal;
|
||||
}
|
||||
|
||||
return formattedInteger;
|
||||
}
|
||||
|
||||
updateDisplay() {
|
||||
// Remove commas for internal calculations
|
||||
const cleanNumber = this.currentNumber.replace(/,/g, '');
|
||||
|
||||
// Format for display
|
||||
if (cleanNumber === '0' || cleanNumber === '' || cleanNumber === '-0') {
|
||||
this.display.textContent = '0';
|
||||
} else {
|
||||
this.display.textContent = this.formatNumber(cleanNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize calculator when DOM is loaded
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
new Calculator();
|
||||
});
|
||||
|
||||
// Keyboard support
|
||||
document.addEventListener('keydown', (event) => {
|
||||
const key = event.key;
|
||||
let button = null;
|
||||
|
||||
if (key >= '0' && key <= '9') {
|
||||
button = document.querySelector(`[data-number="${key}"]`);
|
||||
} else {
|
||||
switch (key) {
|
||||
case '+':
|
||||
button = document.querySelector('[data-action="add"]');
|
||||
break;
|
||||
case '-':
|
||||
button = document.querySelector('[data-action="subtract"]');
|
||||
break;
|
||||
case '*':
|
||||
button = document.querySelector('[data-action="multiply"]');
|
||||
break;
|
||||
case '/':
|
||||
event.preventDefault(); // Prevent browser search
|
||||
button = document.querySelector('[data-action="divide"]');
|
||||
break;
|
||||
case '=':
|
||||
case 'Enter':
|
||||
button = document.querySelector('[data-action="calculate"]');
|
||||
break;
|
||||
case '.':
|
||||
button = document.querySelector('[data-action="decimal"]');
|
||||
break;
|
||||
case 'Escape':
|
||||
button = document.querySelector('[data-action="clear-all"]');
|
||||
break;
|
||||
case 'Backspace':
|
||||
button = document.querySelector('[data-action="clear"]');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (button) {
|
||||
button.click();
|
||||
button.classList.add('btn-active');
|
||||
setTimeout(() => button.classList.remove('btn-active'), 100);
|
||||
}
|
||||
});
|
||||
@ -0,0 +1,157 @@
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: 'Arial', sans-serif;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.calculator {
|
||||
background: #2c3e50;
|
||||
border-radius: 20px;
|
||||
padding: 20px;
|
||||
box-shadow: 0 20px 50px rgba(0, 0, 0, 0.3);
|
||||
width: 100%;
|
||||
max-width: 400px;
|
||||
}
|
||||
|
||||
.display {
|
||||
background: #1a252f;
|
||||
border-radius: 15px;
|
||||
padding: 20px;
|
||||
margin-bottom: 20px;
|
||||
box-shadow: inset 0 3px 10px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.display-screen {
|
||||
color: #ffffff;
|
||||
font-size: 2.5rem;
|
||||
font-weight: 300;
|
||||
text-align: right;
|
||||
min-height: 60px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-end;
|
||||
word-wrap: break-word;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, 1fr);
|
||||
gap: 15px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
background: #34495e;
|
||||
border: none;
|
||||
border-radius: 15px;
|
||||
color: #ffffff;
|
||||
font-size: 1.2rem;
|
||||
font-weight: 500;
|
||||
padding: 20px;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 15px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
.btn:active {
|
||||
transform: translateY(0);
|
||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.btn-number {
|
||||
background: #34495e;
|
||||
}
|
||||
|
||||
.btn-number:hover {
|
||||
background: #4a6274;
|
||||
}
|
||||
|
||||
.btn-operator {
|
||||
background: #e74c3c;
|
||||
}
|
||||
|
||||
.btn-operator:hover {
|
||||
background: #c0392b;
|
||||
}
|
||||
|
||||
.btn-equals {
|
||||
background: #27ae60;
|
||||
grid-column: span 2;
|
||||
}
|
||||
|
||||
.btn-equals:hover {
|
||||
background: #229954;
|
||||
}
|
||||
|
||||
.btn-clear {
|
||||
background: #f39c12;
|
||||
}
|
||||
|
||||
.btn-clear:hover {
|
||||
background: #d68910;
|
||||
}
|
||||
|
||||
.btn-zero {
|
||||
grid-column: span 2;
|
||||
}
|
||||
|
||||
/* Error state */
|
||||
.error {
|
||||
color: #e74c3c !important;
|
||||
animation: shake 0.5s ease-in-out;
|
||||
}
|
||||
|
||||
@keyframes shake {
|
||||
0%, 100% { transform: translateX(0); }
|
||||
25% { transform: translateX(-5px); }
|
||||
75% { transform: translateX(5px); }
|
||||
}
|
||||
|
||||
/* Responsive design */
|
||||
@media (max-width: 480px) {
|
||||
.calculator {
|
||||
padding: 15px;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.display-screen {
|
||||
font-size: 2rem;
|
||||
min-height: 50px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 15px;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
|
||||
.buttons {
|
||||
gap: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 360px) {
|
||||
.display-screen {
|
||||
font-size: 1.8rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
padding: 12px;
|
||||
font-size: 1rem;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in new issue