// ==UserScript== // @name Atomi Keyboard Shortcuts // @namespace atomi-keyboard // @version 1.0.2 // @author Callum Wong // @description Keyboard shortcuts for Atomi questions // @license MIT // @homepageURL https://github.com/wongcallum/atomi-userscripts // @downloadURL https://raw.githubusercontent.com/wongcallum/atomi-userscripts/releases/atomi-keyboard.user.js // @updateURL https://raw.githubusercontent.com/wongcallum/atomi-userscripts/releases/atomi-keyboard.user.js // @match https://learn.getatomi.com/* // @run-at document-idle // @noframes // ==/UserScript== (function(){"use strict";var e=[`Shift`,`Meta`,`Alt`,`Control`],t=1e3,n=`keydown`,r=typeof navigator==`object`?navigator.platform:``,i=/Mac|iPod|iPhone|iPad/.test(r)?`Meta`:`Control`,a=r===`Win32`?[`Control`,`Alt`]:[`Alt`];function o(e){return!!(e.key&&e.code&&e.getModifierState)}function s(e){let t=e.target;return e.repeat||e.isComposing||t!==e.currentTarget&&t.matches(`[contenteditable],input,select,textarea`)}function c(e,t){return typeof e.getModifierState==`function`?e.getModifierState(t)||a.includes(t)&&e.getModifierState(`AltGraph`):!1}function l(e){return e.trim().split(` `).map(e=>{let t=e.split(/(?<=\w|\])\+/),n=t.pop(),r=n.match(/^\((.+)\)$/),a=r?RegExp(`^(?:${r[1]})$`,`iv`):n,o=[],s=[];for(let e of t){let t=e.match(/^\[(.*)\]$/),n=t?.[1]??e;n=n===`$mod`?i:n,t?s.push(n):o.push(n)}return[o,s,a]})}function u(t,[n,r,i]){let o=n.includes(`AltGraph`);return!((i instanceof RegExp?!(i.test(t.key)||i.test(t.code)):i.toUpperCase()!==t.key.toUpperCase()&&i!==t.code)||n.find(e=>!c(t,e))||e.find(e=>!n.includes(e)&&!r.includes(e)&&i!==e&&c(t,e)&&!(o&&a.includes(e))))}function d(e,n={}){let r=n.timeout??t,i=n.ignore??s,a=Object.keys(e).map(t=>[t,l(t),e[t]]),d=new Map,f=null;return e=>{if(!o(e)||i(e))return;let t=[];for(let[n,r,i]of a){let[a,...o]=d.get(n)||r;if(!u(e,a))c(e,e.key)||d.delete(n);else if(o.length>0)d.set(n,o),t.push(n);else if(d.delete(n),t.length)console.warn(`tinykeys: Conflict found, "${n}" did not fire, waiting for:`,t);else{i(e);break}}f&&clearTimeout(f),f=setTimeout(()=>d.clear(),r)}}function f(e,t,r={}){let i=r.event??n,a=d(t,r);return e.addEventListener(i,a,r.capture),()=>{e.removeEventListener(i,a,r.capture)}}var p=`[popover]{color:var(--lightningcss-light,#1a1a1a)var(--lightningcss-dark,#e1e3e7);background:var(--lightningcss-light,#fff)var(--lightningcss-dark,#1c1e22);border:1px solid #8080804d;border-radius:8px;padding:20px 24px;font-size:15px;line-height:1.5;box-shadow:0 8px 32px #00000026}h2{margin:0 0 12px;font-size:18px}dl{grid-template-columns:auto 1fr;align-items:baseline;gap:6px 16px;margin:0;display:grid}dt{text-align:center}dd{margin:0}kbd{min-width:2em;font:inherit;background:#8080800f;border:1px solid #80808080;border-bottom-width:2px;border-radius:4px;padding:0 6px;font-size:13px;font-weight:600;display:inline-block}`,m=[[`$mod+Enter`,`${/Mac|iPhone|iPad/.test(navigator.platform)?`⌘`:`Ctrl`}+Enter`,`Check answer, or Next once checked`,C,!0],[`ArrowRight`,`→`,`Next`,/^(next|continue|done|finish)/i],[`ArrowLeft`,`←`,`Back`,/^(back|previous)/i],[`s`,`s`,`Skip question`,/^skip$/i],[`f`,`f`,`Focus answer box`,x],[`d`,`d`,`Toggle Draw`,()=>v(`Draw`,/^draw$/i)],[`y`,`y`,`Toggle Symbols`,()=>v(`Formula Keyboard`,/^symbols$/i)],[`[Shift]+([1-9])`,`1–9`,`Pick multiple choice option`,e=>T(Number(e.key))],[`ArrowUp`,`↑`,`Previous option (once an option is focused)`,()=>E(-1)],[`ArrowDown`,`↓`,`Next option (once an option is focused)`,()=>E(1)],[`Escape`,`Esc`,`Close help / leave the answer box`,S,!0],[`[Shift]+?`,`?`,`Show this help`,A]],h=e=>(e.getAttribute(`aria-label`)||e.textContent||``).trim(),g=e=>e.offsetParent!==null&&!e.disabled&&e.getAttribute(`aria-disabled`)!==`true`;function _(e,t=document){let n=[...t.querySelectorAll(`button, a[href], [role="button"]`)].find(t=>g(t)&&e.test(h(t)));return n?.click(),!!n}function v(e,t){let n=document.querySelector(`[role="dialog"][aria-label="${e}"]`);return n&&!n.closest(`[inert]`)?_(/^close$/i,n):_(t)}var y=e=>e instanceof Element&&!!e.closest(`input, textarea, select, [contenteditable=""], [contenteditable="true"], [role="textbox"]`);function b(){let e=document.activeElement;for(;e?.shadowRoot?.activeElement;)e=e.shadowRoot.activeElement;return e}function x(){let e=document.querySelector(`main [role="textbox"], main textarea, main [contenteditable="true"]`);return e?.focus(),e?.scrollIntoView({block:`center`}),!!e}function S(){if(O.matches(`:popover-open`))return A();let e=b();return!y(e)||[...document.querySelectorAll(`[role="menu"]`)].some(g)?!1:(e.blur(),!0)}function C(){return _(/^(check answer|self-mark answer)/i)||_(/^next/i)}var w=()=>[...document.querySelectorAll(`main article ul > li > button`)].filter(g);function T(e){let t=w()[e-1];return t?.click(),t?.focus(),!!t}function E(e){let t=w(),n=t.indexOf(document.activeElement);return n!==-1&&T(Math.min(Math.max(n+e,0),t.length-1)+1)}var D=document.createElement(`div`),O=Object.assign(document.createElement(`div`),{popover:`auto`}),k=document.createElement(`dl`);for(let[,e,t]of m){let n=document.createElement(`dt`);n.append(Object.assign(document.createElement(`kbd`),{textContent:e})),k.append(n,Object.assign(document.createElement(`dd`),{textContent:t}))}O.append(Object.assign(document.createElement(`h2`),{textContent:`Keyboard shortcuts`}),k),D.attachShadow({mode:`open`}).append(Object.assign(document.createElement(`style`),{textContent:p}),O),document.body.append(D);function A(){return O.togglePopover(),!0}f(window,Object.fromEntries(m.map(([e,,,t,n])=>[e,e=>{(n||!y(e.composedPath()[0]))&&(t instanceof RegExp?_(t):t(e))&&(e.preventDefault(),e.stopPropagation())}])),{capture:!0,ignore:e=>e.defaultPrevented||e.isComposing||e.repeat})})();