feat: support pasting numbers into the calculator stack
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.
This commit is contained in:
@@ -5,4 +5,5 @@
|
|||||||
- Public API: `push`, `pop`, `clear`, `swap`, `remove`, `edit`, `isValidIndex`, `input`, `command`, `getOperationsByCategory`, `getConstants`
|
- Public API: `push`, `pop`, `clear`, `swap`, `remove`, `edit`, `isValidIndex`, `input`, `command`, `getOperationsByCategory`, `getConstants`
|
||||||
- Config: `maxSize`, `base`, `angleMode`, `enabledCommands`
|
- Config: `maxSize`, `base`, `angleMode`, `enabledCommands`
|
||||||
- Commands: arithmetic, stack, trigonometry, constants `pi` and `e`
|
- 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`
|
- Exports: browser `window.RpnCalculator`, CommonJS `module.exports`
|
||||||
|
|||||||
+38
-15
@@ -55,7 +55,7 @@ const functionKeys = [
|
|||||||
{ label: '', spacer: true },
|
{ label: '', spacer: true },
|
||||||
{ label: 'log', action: 'log', className: 'key-default' },
|
{ label: 'log', action: 'log', className: 'key-default' },
|
||||||
{ label: 'ln', action: 'ln', className: 'key-default' },
|
{ label: 'ln', action: 'ln', className: 'key-default' },
|
||||||
{ label: '', spacer: true },
|
{ label: 'eˣ', action: 'exp', className: 'key-default' },
|
||||||
{ label: '', spacer: true },
|
{ 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) {
|
function execute(name) {
|
||||||
try {
|
try {
|
||||||
if (name === 'enter') {
|
if (name === 'enter') {
|
||||||
@@ -162,6 +180,10 @@ function execute(name) {
|
|||||||
pushEditingValueIfNeeded();
|
pushEditingValueIfNeeded();
|
||||||
calc.push(10);
|
calc.push(10);
|
||||||
calc.command('pow');
|
calc.command('pow');
|
||||||
|
} else if (name === 'exp') {
|
||||||
|
pushEditingValueIfNeeded();
|
||||||
|
calc.push(Math.E);
|
||||||
|
calc.command('pow');
|
||||||
} else {
|
} else {
|
||||||
pushEditingValueIfNeeded();
|
pushEditingValueIfNeeded();
|
||||||
calc.command(name);
|
calc.command(name);
|
||||||
@@ -286,23 +308,18 @@ window.addEventListener('click', (event) => {
|
|||||||
pasteButton.addEventListener('click', async () => {
|
pasteButton.addEventListener('click', async () => {
|
||||||
try {
|
try {
|
||||||
const text = await navigator.clipboard.readText();
|
const text = await navigator.clipboard.readText();
|
||||||
if (!text) {
|
pasteTextIntoStack(text);
|
||||||
setStatus('Clipboard empty');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (calc.isEditing) {
|
|
||||||
calc.inputValue += text;
|
|
||||||
} else {
|
|
||||||
calc.isEditing = true;
|
|
||||||
calc.inputValue = text;
|
|
||||||
}
|
|
||||||
setStatus('Pasted');
|
|
||||||
render();
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
setStatus('Paste unavailable');
|
setStatus('Paste unavailable');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
hiddenInput.addEventListener('paste', (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
const text = event.clipboardData?.getData('text') ?? '';
|
||||||
|
pasteTextIntoStack(text);
|
||||||
|
});
|
||||||
|
|
||||||
upButton.addEventListener('click', () => {});
|
upButton.addEventListener('click', () => {});
|
||||||
|
|
||||||
const constants = [
|
const constants = [
|
||||||
@@ -357,14 +374,14 @@ constButton.addEventListener('click', (event) => {
|
|||||||
leftButton.addEventListener('click', () => {});
|
leftButton.addEventListener('click', () => {});
|
||||||
|
|
||||||
downButton.addEventListener('click', () => {
|
downButton.addEventListener('click', () => {
|
||||||
if (!calc.isEditing && calc.isValidIndex(0)) {
|
if (!calc.isEditing && calc.isValidIndex(0)) {
|
||||||
const value = calc.stack[0];
|
const value = calc.stack[0];
|
||||||
calc.remove(0);
|
calc.remove(0);
|
||||||
calc.isEditing = true;
|
calc.isEditing = true;
|
||||||
calc.inputValue = calc.formatNumber(value);
|
calc.inputValue = calc.formatNumber(value);
|
||||||
render();
|
render();
|
||||||
focusInput();
|
focusInput();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
@@ -376,6 +393,12 @@ rightButton.addEventListener('click', () => {
|
|||||||
window.addEventListener('keydown', handleKeyboard);
|
window.addEventListener('keydown', handleKeyboard);
|
||||||
window.addEventListener('load', focusInput);
|
window.addEventListener('load', focusInput);
|
||||||
|
|
||||||
|
hiddenInput.addEventListener('focus', () => {
|
||||||
|
window.requestAnimationFrame(() => {
|
||||||
|
hiddenInput.select();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
document.addEventListener('click', (event) => {
|
document.addEventListener('click', (event) => {
|
||||||
if (!event.target.closest('.calculator')) {
|
if (!event.target.closest('.calculator')) {
|
||||||
focusInput();
|
focusInput();
|
||||||
|
|||||||
Reference in New Issue
Block a user