fscalc/webroot/js/calculator.js
2025-10-04 20:20:08 +02:00

240 lines
9.0 KiB
JavaScript

// Hex calculator functionality
export class Calculator {
constructor() {
this.state = {
currentValue: 0,
previousValue: 0,
operation: null,
waitingForOperand: false
};
}
updateDisplay() {
const value = Math.max(0, Math.min(Math.floor(this.state.currentValue), Number.MAX_SAFE_INTEGER));
const hexStr = '0x' + value.toString(16).toUpperCase();
const decStr = value.toString(10);
const binStr = '0b' + value.toString(2);
// Update all calculator displays (for current active tab)
const inputs = document.querySelectorAll('[id*="calcInput"]');
const hexElements = document.querySelectorAll('[id*="hexValue"]');
const decElements = document.querySelectorAll('[id*="decValue"]');
const binElements = document.querySelectorAll('[id*="binValue"]');
inputs.forEach(input => input.value = hexStr);
hexElements.forEach(el => el.textContent = hexStr);
decElements.forEach(el => el.textContent = decStr);
binElements.forEach(el => el.textContent = binStr);
}
input(digit) {
if (this.state.waitingForOperand) {
this.state.currentValue = 0;
this.state.waitingForOperand = false;
}
const digitValue = parseInt(digit, 16);
if (isNaN(digitValue)) return;
const newValue = this.state.currentValue * 16 + digitValue;
if (newValue <= Number.MAX_SAFE_INTEGER && newValue >= 0) {
this.state.currentValue = newValue;
}
this.updateDisplay();
}
operation(operation) {
if (this.state.previousValue !== 0 && !this.state.waitingForOperand) {
this.equals(false);
}
this.state.previousValue = this.state.currentValue;
this.state.operation = operation;
this.state.waitingForOperand = true;
}
equals(updateDisplay = true) {
if (this.state.operation && this.state.previousValue !== null) {
const prev = Math.floor(this.state.previousValue);
const curr = Math.floor(this.state.currentValue);
try {
let result = 0;
switch (this.state.operation) {
case '+':
result = prev + curr;
break;
case '-':
result = prev - curr;
break;
case '*':
result = prev * curr;
break;
case '/':
if (curr === 0) {
alert('Division durch Null!');
return;
}
result = Math.floor(prev / curr);
break;
case 'MOD':
if (curr === 0) {
alert('Modulo durch Null!');
return;
}
result = prev % curr;
break;
}
this.state.currentValue = Math.max(0, Math.min(result, Number.MAX_SAFE_INTEGER));
} catch (error) {
alert('Berechnungsfehler: ' + error.message);
this.state.currentValue = 0;
}
this.state.operation = null;
this.state.previousValue = 0;
this.state.waitingForOperand = true;
}
if (updateDisplay) {
this.updateDisplay();
}
}
clear() {
this.state.currentValue = 0;
this.state.previousValue = 0;
this.state.operation = null;
this.state.waitingForOperand = false;
this.updateDisplay();
}
backspace() {
if (!this.state.waitingForOperand) {
this.state.currentValue = Math.floor(this.state.currentValue / 16);
this.updateDisplay();
}
}
setupEventListeners() {
// Event delegation for calculator buttons
document.addEventListener('click', (e) => {
// Only handle clicks on calculator buttons
if (!e.target.classList.contains('calc-btn')) return;
const button = e.target;
if (button.classList.contains('number')) {
this.input(button.textContent);
} else if (button.classList.contains('operation')) {
this.operation(button.textContent);
} else if (button.classList.contains('equals')) {
this.equals();
} else if (button.classList.contains('clear')) {
this.clear();
} else if (button.classList.contains('backspace')) {
this.backspace();
}
});
// Keyboard support
document.addEventListener('keydown', (e) => {
if (e.target.tagName === 'INPUT' && !e.target.readOnly) return;
const key = e.key.toUpperCase();
if (/^[0-9A-F]$/.test(key)) {
e.preventDefault();
this.input(key);
} else if (key === '+') {
e.preventDefault();
this.operation('+');
} else if (key === '-') {
e.preventDefault();
this.operation('-');
} else if (key === '*') {
e.preventDefault();
this.operation('*');
} else if (key === '/') {
e.preventDefault();
this.operation('/');
} else if (key === 'ENTER' || key === '=') {
e.preventDefault();
this.equals();
} else if (key === 'ESCAPE' || key === 'C') {
e.preventDefault();
this.clear();
} else if (key === 'BACKSPACE') {
e.preventDefault();
this.backspace();
}
});
}
generateHTML() {
return `
<div class="calculator-container">
<div class="calc-display">
<div class="calc-input">
<input type="text" id="calcInput" placeholder="0x0" readonly>
</div>
<div class="calc-conversions">
<div class="conversion-row">
<span class="conv-label">HEX:</span>
<span class="conv-value" id="hexValue">0x0</span>
</div>
<div class="conversion-row">
<span class="conv-label">DEC:</span>
<span class="conv-value" id="decValue">0</span>
</div>
<div class="conversion-row">
<span class="conv-label">BIN:</span>
<span class="conv-value" id="binValue">0b0</span>
</div>
</div>
</div>
<div class="calc-buttons">
<div class="calc-row">
<button class="calc-btn number">A</button>
<button class="calc-btn number">B</button>
<button class="calc-btn number">C</button>
<button class="calc-btn number">D</button>
<button class="calc-btn clear">C</button>
</div>
<div class="calc-row">
<button class="calc-btn number">E</button>
<button class="calc-btn number">F</button>
<button class="calc-btn number">7</button>
<button class="calc-btn number">8</button>
<button class="calc-btn operation">/</button>
</div>
<div class="calc-row">
<button class="calc-btn number">4</button>
<button class="calc-btn number">5</button>
<button class="calc-btn number">6</button>
<button class="calc-btn operation">*</button>
<button class="calc-btn operation">MOD</button>
</div>
<div class="calc-row">
<button class="calc-btn number">1</button>
<button class="calc-btn number">2</button>
<button class="calc-btn number">3</button>
<button class="calc-btn operation">-</button>
<button class="calc-btn operation">+</button>
</div>
<div class="calc-row">
<button class="calc-btn number wide">0</button>
<button class="calc-btn number">9</button>
<button class="calc-btn backspace">⌫</button>
<button class="calc-btn equals">=</button>
</div>
</div>
</div>
`;
}
}