// keyboard shortcuts and the help overlay (press ?). Drives the page through its own buttons, // plus the small camera hooks app.js exposes on window.unrollView. const $ = (id) => document.getElementById(id); const KEYS = [ ['Space', 'Play or pause the unroll'], ['← →', 'Step the unroll (hold Shift for bigger steps)'], ['Home / End', 'Jump to rolled / fully unrolled'], ['1 2 3', 'X-ray, published ink, ink_9um'], ['R', 'Read the current winding close up'], ['V', 'Reset the camera view'], ['U', 'Roll it back up (again to stop)'], ['T', 'Destroy on or off'], ['X C B W', 'Destroy tools: Tear, Crush, Burn, Water'], ['K', 'Crumble the whole scroll to dust (Reset restores it)'], ['F', 'Full screen'], ['I', 'About this page'], ['?', 'Show or hide this help'], ['Esc', 'Close any panel'], ]; const help = document.createElement('section'); help.id = 'help'; help.className = 'sheet help'; help.hidden = true; help.setAttribute('role', 'dialog'); help.setAttribute('aria-modal', 'false'); help.setAttribute('aria-labelledby', 'helpTitle'); help.innerHTML = `
Drag to orbit, scroll or pinch to zoom, click a sheet to read it.
`; document.body.appendChild(help); const tools = document.querySelector('.tools'); if (tools && !$('btnHelp')) { const b = document.createElement('button'); b.className = 'icon'; b.id = 'btnHelp'; b.title = 'Keyboard shortcuts (?)'; b.setAttribute('aria-label', 'Keyboard shortcuts'); b.textContent = '?'; b.dataset.testid = 'help'; b.dataset.api = "panel('help')"; tools.prepend(b); b.onclick = () => toggleHelp(); } let opener = null; function toggleHelp(force) { const show = force ?? help.hidden; if (show) { opener = document.activeElement; help.hidden = false; $('hClose').focus(); } else if (!help.hidden) { help.hidden = true; opener?.focus?.(); } } $('hClose').onclick = () => toggleHelp(false); const click = (id) => { const el = $(id); if (el && !el.hidden) { el.click(); return true; } return false; }; const sheetOpen = () => ['focus', 'about', 'openSheet'].some((id) => $(id) && !$(id).hidden); addEventListener('keydown', (e) => { if (e.ctrlKey || e.metaKey || e.altKey) return; if (e.target.closest?.('textarea,select,input:not([type=range])')) return; const k = e.key; if (k === '?' || (k === '/' && e.shiftKey)) { e.preventDefault(); toggleHelp(); return; } if (k === 'Escape') { toggleHelp(false); return; } if (!help.hidden || sheetOpen()) return; const range = $('scrubIn'); const step = (d) => { range.value = Math.max(0, Math.min(1000, +range.value + d)); range.dispatchEvent(new Event('input', { bubbles: true })); range.dispatchEvent(new Event('change', { bubbles: true })); }; switch (k.toLowerCase()) { case '1': document.querySelector('[data-layer=xray]')?.click(); break; case '2': document.querySelector('[data-layer=ink]')?.click(); break; case '3': document.querySelector('[data-layer=gpu]:not([hidden])')?.click(); break; case 'r': click('btnRead'); break; case 'v': window.unrollView?.reset(); break; case 't': click('btnTear'); break; case 'c': click('btnCrush'); break; case 'x': click('toolTear'); break; case 'b': click('toolBurn'); break; case 'w': click('toolWater'); break; case 'k': window.unrollView?.crumble(); break; case 'u': click('btnRollUp'); break; case 'i': click('btnInfo'); break; case 'f': if (document.fullscreenElement) document.exitFullscreen?.(); else document.documentElement.requestFullscreen?.().catch(() => {}); break; case 'home': e.preventDefault(); step(-1000); break; case 'end': e.preventDefault(); step(1000); break; case 'arrowright': case 'arrowleft': // app.js steps by 1 percent; Shift adds a 5 percent jump if (e.shiftKey && e.target === document.body) step(k === 'ArrowRight' ? 40 : -40); break; default: return; } });