From d1a1d4457785138d57272ac79c123032d5e6e797 Mon Sep 17 00:00:00 2001 From: MatMoul Date: Fri, 15 May 2026 20:45:30 +0200 Subject: [PATCH] feat: support pasting numbers into the calculator stack MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add clipboard paste handling for the hidden input and the paste button so pasted text is parsed as a numeric value before being pushed. Also add the eˣ function key in the sample calculator and keep the hidden input selected on focus for Ctrl+V support. --- .memory/state.md | 1 + samples/calc-02/index.js | 65 +++++++++++++++++++++++++++------------- 2 files changed, 45 insertions(+), 21 deletions(-) diff --git a/.memory/state.md b/.memory/state.md index 33648ef..a3839b9 100644 --- a/.memory/state.md +++ b/.memory/state.md @@ -5,4 +5,5 @@ - Public API: `push`, `pop`, `clear`, `swap`, `remove`, `edit`, `isValidIndex`, `input`, `command`, `getOperationsByCategory`, `getConstants` - Config: `maxSize`, `base`, `angleMode`, `enabledCommands` - Commands: arithmetic, stack, trigonometry, constants `pi` and `e` +- Demo actions: paste now parses clipboard text as a number before pushing it to the stack; Ctrl+V is supported via the hidden input paste event - Exports: browser `window.RpnCalculator`, CommonJS `module.exports` diff --git a/samples/calc-02/index.js b/samples/calc-02/index.js index 129807d..169da61 100644 --- a/samples/calc-02/index.js +++ b/samples/calc-02/index.js @@ -55,7 +55,7 @@ const functionKeys = [ { label: '', spacer: true }, { label: 'log', action: 'log', className: 'key-default' }, { label: 'ln', action: 'ln', className: 'key-default' }, - { label: '', spacer: true }, + { label: 'eˣ', action: 'exp', className: 'key-default' }, { label: '', spacer: true }, ]; @@ -126,6 +126,24 @@ function inputToX(value) { } } +function pasteTextIntoStack(text) { + if (!text) { + setStatus('Clipboard empty'); + return; + } + const value = calc.parseInputValue(text); + if (!Number.isFinite(value)) { + setStatus('Clipboard is not a number'); + return; + } + pushEditingValueIfNeeded(); + calc.push(value); + calc.isEditing = false; + calc.inputValue = ''; + setStatus('Pasted'); + render(); +} + function execute(name) { try { if (name === 'enter') { @@ -162,6 +180,10 @@ function execute(name) { pushEditingValueIfNeeded(); calc.push(10); calc.command('pow'); + } else if (name === 'exp') { + pushEditingValueIfNeeded(); + calc.push(Math.E); + calc.command('pow'); } else { pushEditingValueIfNeeded(); calc.command(name); @@ -286,23 +308,18 @@ window.addEventListener('click', (event) => { pasteButton.addEventListener('click', async () => { try { const text = await navigator.clipboard.readText(); - if (!text) { - setStatus('Clipboard empty'); - return; - } - if (calc.isEditing) { - calc.inputValue += text; - } else { - calc.isEditing = true; - calc.inputValue = text; - } - setStatus('Pasted'); - render(); + pasteTextIntoStack(text); } catch (error) { setStatus('Paste unavailable'); } }); +hiddenInput.addEventListener('paste', (event) => { + event.preventDefault(); + const text = event.clipboardData?.getData('text') ?? ''; + pasteTextIntoStack(text); +}); + upButton.addEventListener('click', () => {}); const constants = [ @@ -357,14 +374,14 @@ constButton.addEventListener('click', (event) => { leftButton.addEventListener('click', () => {}); downButton.addEventListener('click', () => { -if (!calc.isEditing && calc.isValidIndex(0)) { - const value = calc.stack[0]; - calc.remove(0); - calc.isEditing = true; - calc.inputValue = calc.formatNumber(value); - render(); - focusInput(); -} + if (!calc.isEditing && calc.isValidIndex(0)) { + const value = calc.stack[0]; + calc.remove(0); + calc.isEditing = true; + calc.inputValue = calc.formatNumber(value); + render(); + focusInput(); + } }); @@ -376,6 +393,12 @@ rightButton.addEventListener('click', () => { window.addEventListener('keydown', handleKeyboard); window.addEventListener('load', focusInput); +hiddenInput.addEventListener('focus', () => { + window.requestAnimationFrame(() => { + hiddenInput.select(); + }); +}); + document.addEventListener('click', (event) => { if (!event.target.closest('.calculator')) { focusInput();