import { firstLineRange, currentLine, advance, copyText, adjustCopiedLine, trimTrailing } from './queue.mjs'; import { serializePrefs, parsePrefs } from './prefs.mjs'; const pasteField = document.getElementById('pasteField'); const queueSwitch = document.getElementById('queueSwitch'); const advanceBtn = document.getElementById('advanceBtn'); const focusSwitch = document.getElementById('focusSwitch'); const newlineSwitch = document.getElementById('newlineSwitch'); const savedPrefs = parsePrefs(localStorage.getItem('queued-paste-prefs')); newlineSwitch.checked = savedPrefs.newLines; focusSwitch.checked = savedPrefs.advanceFocus; function savePrefs() { localStorage.setItem('queued-paste-prefs', serializePrefs({ newLines: newlineSwitch.checked, advanceFocus: focusSwitch.checked, })); } // Focus-based advancing is a heuristic: a paste outside this page cannot be // observed, so a window blur followed by a refocus is treated as one paste. // blurredSinceAdvance gates that, and armedAt suppresses the focus events // fired by clipboard permission prompts right after arming. let blurredSinceAdvance = false; let armedAt = 0; async function copyCurrentLine() { await navigator.clipboard.writeText(copyText(pasteField.value, newlineSwitch.checked)); } function selectCurrentLine() { const { start, end } = firstLineRange(pasteField.value); pasteField.setSelectionRange(start, end); } function setQueueing(on) { queueSwitch.checked = on; pasteField.readOnly = on; pasteField.classList.toggle('paste-active', on); advanceBtn.disabled = !on; if (!on) { pasteField.setSelectionRange(pasteField.value.length, pasteField.value.length); } } async function startQueueing() { pasteField.value = trimTrailing(pasteField.value); if (pasteField.value === '') { // Nothing to queue. setQueueing(false); return; } try { await copyCurrentLine(); } catch (err) { alert('Could not access the clipboard: ' + err.message); setQueueing(false); return; } setQueueing(true); selectCurrentLine(); blurredSinceAdvance = false; armedAt = Date.now(); } async function advanceQueue() { pasteField.value = advance(pasteField.value); if (pasteField.value === '') { setQueueing(false); return; } try { await copyCurrentLine(); } catch (err) { alert('Could not copy the next line: ' + err.message); setQueueing(false); return; } selectCurrentLine(); } queueSwitch.addEventListener('change', () => { if (queueSwitch.checked) { startQueueing(); } else { setQueueing(false); } }); advanceBtn.addEventListener('click', () => { advanceQueue(); }); focusSwitch.addEventListener('change', () => { blurredSinceAdvance = false; armedAt = Date.now(); savePrefs(); }); newlineSwitch.addEventListener('change', async () => { savePrefs(); if (!queueSwitch.checked) return; try { const clipboardText = await navigator.clipboard.readText(); const adjusted = adjustCopiedLine(clipboardText, currentLine(pasteField.value), newlineSwitch.checked); if (adjusted !== null) { await navigator.clipboard.writeText(adjusted); } } catch (err) { alert('Could not update the clipboard: ' + err.message); } }); window.addEventListener('blur', () => { blurredSinceAdvance = true; }); window.addEventListener('focus', () => { if (!queueSwitch.checked || !focusSwitch.checked) return; if (!blurredSinceAdvance) return; if (Date.now() - armedAt < 1000) return; blurredSinceAdvance = false; advanceQueue(); });