diff --git a/newtab.html b/newtab.html index 93ff1a5..ae73e13 100644 --- a/newtab.html +++ b/newtab.html @@ -507,6 +507,7 @@ + diff --git a/src/css/main.css b/src/css/main.css index 6a196bd..e622a4f 100644 --- a/src/css/main.css +++ b/src/css/main.css @@ -1332,6 +1332,65 @@ body.show-desc .bm-desc { display: block; } overflow-x: hidden; } +/* Calculator Scientific Mode */ +.calc-sci-buttons { + grid-template-columns: repeat(3, 1fr); + margin-bottom: 4px; +} +.calc-formula-helper { + border-top: 1px solid var(--border); + padding-top: 8px; + margin-top: 4px; +} +.calc-formula-label { + font-size: 9px; + color: var(--text-muted); + text-transform: uppercase; + letter-spacing: 1px; + margin-bottom: 4px; +} +.calc-formula-select { + width: 100%; + padding: 4px 6px; + background: rgba(0,0,0,0.3); + border: 1px solid var(--border); + border-radius: var(--radius-sm); + color: var(--text-primary); + font-size: 12px; + font-family: 'Rajdhani', sans-serif; + margin-bottom: 6px; +} +.calc-formula-row { + display: flex; + align-items: center; + gap: 8px; + margin-bottom: 4px; +} +.calc-formula-row label { + font-size: 11px; + color: var(--text-secondary); + min-width: 50px; +} +.calc-formula-input { + flex: 1; + padding: 4px 6px; + background: rgba(0,0,0,0.3); + border: 1px solid var(--border); + border-radius: var(--radius-sm); + color: var(--text-primary); + font-size: 12px; + font-family: 'Rajdhani', sans-serif; +} +.calc-formula-result { + font-size: 14px; + color: var(--accent); + font-weight: 600; + font-family: 'Rajdhani', monospace; + text-align: right; + min-height: 20px; + padding: 2px 0; +} + /* ============================================ TIMER WIDGET ============================================ */ diff --git a/src/js/calc-scientific.js b/src/js/calc-scientific.js new file mode 100644 index 0000000..ba3824b --- /dev/null +++ b/src/js/calc-scientific.js @@ -0,0 +1,284 @@ +/* ============================================= + HELLION NEWTAB — calc-scientific.js + Scientific-Modus für Calculator Widget + ============================================= */ + +(function() { + 'use strict'; + + const FORMULAS = [ + { + key: 'circle_area', + fields: [{ key: 'radius', default: '' }], + calc: (vals) => Math.PI * vals.radius * vals.radius + }, + { + key: 'circle_circumference', + fields: [{ key: 'radius', default: '' }], + calc: (vals) => 2 * Math.PI * vals.radius + }, + { + key: 'celsius_to_fahrenheit', + fields: [{ key: 'temp', default: '' }], + calc: (vals) => (vals.temp * 9 / 5) + 32 + }, + { + key: 'fahrenheit_to_celsius', + fields: [{ key: 'temp', default: '' }], + calc: (vals) => (vals.temp - 32) * 5 / 9 + }, + { + key: 'pythagoras', + fields: [{ key: 'a', default: '' }, { key: 'b', default: '' }], + calc: (vals) => Math.sqrt(vals.a * vals.a + vals.b * vals.b) + }, + { + key: 'percentage', + fields: [{ key: 'value', default: '' }, { key: 'percent', default: '' }], + calc: (vals) => vals.value * vals.percent / 100 + } + ]; + + let _keyboardExtHandler = null; + + function renderSciButtons(container) { + const grid = document.createElement('div'); + grid.className = 'calc-buttons calc-sci-buttons'; + + const buttons = [ + ['√', 'sqrt', 'operator'], + ['x²', 'square', 'operator'], + ['xⁿ', 'power', 'operator'], + ['π', 'pi', 'operator'], + ['e', 'euler', 'operator'], + ['±', 'negate', 'operator'] + ]; + + buttons.forEach(([label, value, cls]) => { + const btn = document.createElement('button'); + btn.className = 'calc-btn' + (cls ? ' ' + cls : ''); + btn.textContent = label; + btn.type = 'button'; + btn.addEventListener('click', () => handleSciKey(value)); + grid.appendChild(btn); + }); + + container.appendChild(grid); + } + + function handleSciKey(key) { + switch (key) { + case 'sqrt': + Calculator._currentExpr += 'sqrt('; + Calculator._updateDisplay(); + break; + case 'square': + Calculator._currentExpr += '^2'; + Calculator._updateDisplay(); + break; + case 'power': + Calculator._handleKey('^'); + break; + case 'pi': + Calculator._currentExpr += '3.14159265359'; + Calculator._updateDisplay(); + break; + case 'euler': + Calculator._currentExpr += '2.71828182846'; + Calculator._updateDisplay(); + break; + case 'negate': + handleNegate(); + break; + } + } + + function handleNegate() { + const expr = Calculator._currentExpr; + if (!expr && Calculator._lastResult) { + const num = parseFloat(Calculator._lastResult); + if (!isNaN(num)) { + Calculator._currentExpr = String(-num); + Calculator._lastResult = ''; + Calculator._updateDisplay(); + } + return; + } + const match = expr.match(/(-?\d+\.?\d*)$/); + if (match) { + const num = parseFloat(match[1]); + const negated = String(-num); + Calculator._currentExpr = expr.slice(0, expr.length - match[1].length) + negated; + Calculator._updateDisplay(); + } + } + + function renderFormulaHelper(container) { + const wrapper = document.createElement('div'); + wrapper.className = 'calc-formula-helper'; + + const label = document.createElement('div'); + label.className = 'calc-formula-label'; + label.textContent = t('calculator.sci.formulas'); + + const select = document.createElement('select'); + select.className = 'calc-formula-select'; + + const emptyOpt = document.createElement('option'); + emptyOpt.value = ''; + emptyOpt.textContent = t('calculator.sci.select_formula'); + select.appendChild(emptyOpt); + + FORMULAS.forEach((f, i) => { + const opt = document.createElement('option'); + opt.value = String(i); + opt.textContent = t('calculator.sci.formula.' + f.key); + select.appendChild(opt); + }); + + const inputsContainer = document.createElement('div'); + inputsContainer.className = 'calc-formula-inputs'; + + const resultContainer = document.createElement('div'); + resultContainer.className = 'calc-formula-result'; + + select.addEventListener('change', () => { + while (inputsContainer.firstChild) { + inputsContainer.removeChild(inputsContainer.firstChild); + } + resultContainer.textContent = ''; + + const idx = parseInt(select.value, 10); + if (isNaN(idx)) return; + + const formula = FORMULAS[idx]; + renderFormulaInputs(formula, inputsContainer, resultContainer); + }); + + wrapper.append(label, select, inputsContainer, resultContainer); + container.appendChild(wrapper); + } + + function renderFormulaInputs(formula, inputsEl, resultEl) { + const inputs = {}; + + formula.fields.forEach(field => { + const row = document.createElement('div'); + row.className = 'calc-formula-row'; + + const lbl = document.createElement('label'); + lbl.textContent = t('calculator.sci.field.' + field.key); + + const inp = document.createElement('input'); + inp.type = 'number'; + inp.className = 'calc-formula-input'; + inp.placeholder = '0'; + inp.step = 'any'; + inputs[field.key] = inp; + + inp.addEventListener('input', () => { + recalcFormula(formula, inputs, resultEl); + }); + + row.append(lbl, inp); + inputsEl.appendChild(row); + }); + } + + function recalcFormula(formula, inputs, resultEl) { + const vals = {}; + let allValid = true; + + for (const field of formula.fields) { + const v = parseFloat(inputs[field.key].value); + if (isNaN(v)) { allValid = false; break; } + vals[field.key] = v; + } + + if (!allValid) { + resultEl.textContent = ''; + return; + } + + const result = formula.calc(vals); + if (result === null || !isFinite(result)) { + resultEl.textContent = t('calculator.error'); + return; + } + + resultEl.textContent = '= ' + Calculator._formatResult(result); + } + + function bindSciKeyboard(widgetEl) { + _keyboardExtHandler = (e) => { + if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') return; + if (e.target.contentEditable === 'true') return; + + if (e.key === 'p') { + handleSciKey('pi'); + e.preventDefault(); + e.stopPropagation(); + } else if (e.key === '^') { + handleSciKey('power'); + e.preventDefault(); + e.stopPropagation(); + } + }; + widgetEl.addEventListener('keydown', _keyboardExtHandler); + } + + Calculator.registerMode('scientific', { + label: '📐', + shortName: 'Sci', + titleKey: 'calculator.tab.scientific', + + render(bodyEl) { + bodyEl.style.padding = '8px'; + bodyEl.style.display = 'flex'; + bodyEl.style.flexDirection = 'column'; + bodyEl.style.flex = '1'; + bodyEl.style.overflow = 'hidden'; + + const display = document.createElement('div'); + display.className = 'calc-display'; + + const exprEl = document.createElement('div'); + exprEl.className = 'calc-expression'; + Calculator._displayExprEl = exprEl; + + const resultEl = document.createElement('div'); + resultEl.className = 'calc-result'; + resultEl.textContent = Calculator._lastResult || '0'; + Calculator._displayResultEl = resultEl; + + display.append(exprEl, resultEl); + + const sciSection = document.createElement('div'); + renderSciButtons(sciSection); + + const stdButtons = Calculator._createButtons(); + const historyEl = Calculator._createHistoryPanel(); + + const formulaSection = document.createElement('div'); + renderFormulaHelper(formulaSection); + + bodyEl.append(display, sciSection, stdButtons, historyEl, formulaSection); + Calculator._updateDisplay(); + + const entry = WidgetManager._widgets.get(Calculator.WIDGET_ID); + if (entry) bindSciKeyboard(entry.el); + }, + + destroy() { + if (_keyboardExtHandler) { + const entry = WidgetManager._widgets.get(Calculator.WIDGET_ID); + if (entry) { + entry.el.removeEventListener('keydown', _keyboardExtHandler); + } + _keyboardExtHandler = null; + } + Calculator._displayExprEl = null; + Calculator._displayResultEl = null; + } + }); +})(); diff --git a/src/js/i18n.js b/src/js/i18n.js index 6af8df9..0039cb7 100644 --- a/src/js/i18n.js +++ b/src/js/i18n.js @@ -84,6 +84,21 @@ const STRINGS = { 'calculator.history': 'History', 'calculator.error': 'Fehler', 'calculator.tab.standard': 'Standard', + 'calculator.tab.scientific': 'Wissenschaftlich', + 'calculator.sci.formulas': 'Formel-Helfer', + 'calculator.sci.select_formula': 'Formel wählen…', + 'calculator.sci.formula.circle_area': 'Kreisfläche (π×r²)', + 'calculator.sci.formula.circle_circumference':'Kreisumfang (2πr)', + 'calculator.sci.formula.celsius_to_fahrenheit':'°C → °F', + 'calculator.sci.formula.fahrenheit_to_celsius':'°F → °C', + 'calculator.sci.formula.pythagoras': 'Pythagoras (√(a²+b²))', + 'calculator.sci.formula.percentage': 'Prozentwert', + 'calculator.sci.field.radius': 'Radius', + 'calculator.sci.field.temp': 'Temperatur', + 'calculator.sci.field.a': 'Seite a', + 'calculator.sci.field.b': 'Seite b', + 'calculator.sci.field.value': 'Wert', + 'calculator.sci.field.percent': 'Prozent', // Timer 'timer.title': 'Timer', @@ -393,6 +408,21 @@ const STRINGS = { 'calculator.history': 'History', 'calculator.error': 'Error', 'calculator.tab.standard': 'Standard', + 'calculator.tab.scientific': 'Scientific', + 'calculator.sci.formulas': 'Formula Helper', + 'calculator.sci.select_formula': 'Choose formula…', + 'calculator.sci.formula.circle_area': 'Circle Area (π×r²)', + 'calculator.sci.formula.circle_circumference':'Circle Circumference (2πr)', + 'calculator.sci.formula.celsius_to_fahrenheit':'°C → °F', + 'calculator.sci.formula.fahrenheit_to_celsius':'°F → °C', + 'calculator.sci.formula.pythagoras': 'Pythagoras (√(a²+b²))', + 'calculator.sci.formula.percentage': 'Percentage', + 'calculator.sci.field.radius': 'Radius', + 'calculator.sci.field.temp': 'Temperature', + 'calculator.sci.field.a': 'Side a', + 'calculator.sci.field.b': 'Side b', + 'calculator.sci.field.value': 'Value', + 'calculator.sci.field.percent': 'Percent', // Timer 'timer.title': 'Timer',