259 lines
		
	
	
		
			9.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			259 lines
		
	
	
		
			9.9 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 only the calculator inside the currently active tab to avoid duplicate-id issues
 | 
						|
        const activeContent = document.querySelector('.tab-content.active');
 | 
						|
        if (!activeContent) {
 | 
						|
            // Fallback: try to update the first calculator on the page
 | 
						|
            const fallbackInput = document.querySelector('.calc-input-field');
 | 
						|
            if (fallbackInput) fallbackInput.value = hexStr;
 | 
						|
            const fallbackHex = document.querySelector('.hex-value');
 | 
						|
            if (fallbackHex) fallbackHex.textContent = hexStr;
 | 
						|
            const fallbackDec = document.querySelector('.dec-value');
 | 
						|
            if (fallbackDec) fallbackDec.textContent = decStr;
 | 
						|
            const fallbackBin = document.querySelector('.bin-value');
 | 
						|
            if (fallbackBin) fallbackBin.textContent = binStr;
 | 
						|
            return;
 | 
						|
        }
 | 
						|
 | 
						|
        const input = activeContent.querySelector('.calc-input-field');
 | 
						|
        if (input) input.value = hexStr;
 | 
						|
 | 
						|
        const hexElement = activeContent.querySelector('.hex-value');
 | 
						|
        if (hexElement) hexElement.textContent = hexStr;
 | 
						|
 | 
						|
        const decElement = activeContent.querySelector('.dec-value');
 | 
						|
        if (decElement) decElement.textContent = decStr;
 | 
						|
 | 
						|
        const binElement = activeContent.querySelector('.bin-value');
 | 
						|
        if (binElement) binElement.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 there is a pending operation and we are not waiting for a new operand,
 | 
						|
        // evaluate it first so chained operations work as expected.
 | 
						|
        if (this.state.operation !== null && !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 === 'DELETE') {
 | 
						|
                // Use Escape or Delete to clear. Do not use 'C' since it collides with hex digit 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" class="calc-input-field" placeholder="0x0" readonly>
 | 
						|
                    </div>
 | 
						|
                    <div class="calc-conversions">
 | 
						|
                        <div class="conversion-row">
 | 
						|
                            <span class="conv-label">HEX:</span>
 | 
						|
                            <span class="conv-value hex-value">0x0</span>
 | 
						|
                        </div>
 | 
						|
                        <div class="conversion-row">
 | 
						|
                            <span class="conv-label">DEC:</span>
 | 
						|
                            <span class="conv-value dec-value">0</span>
 | 
						|
                        </div>
 | 
						|
                        <div class="conversion-row">
 | 
						|
                            <span class="conv-label">BIN:</span>
 | 
						|
                            <span class="conv-value bin-value">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">CLR</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>
 | 
						|
        `;
 | 
						|
    }
 | 
						|
} |