From ad5dd09cc3125d3f14e2341be1d63ffdacb57700 Mon Sep 17 00:00:00 2001 From: Alex Gu Date: Mon, 14 Jun 2021 04:11:15 +0300 Subject: [PATCH 01/12] Override useless browser hotkeys if editor is active For example Ctrl+B open Bookmarks, Ctrl+I open page info. It's useful shortcuts but unless we edit hypha text. --- static/shortcuts.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/static/shortcuts.js b/static/shortcuts.js index beaa088..0736e22 100644 --- a/static/shortcuts.js +++ b/static/shortcuts.js @@ -88,10 +88,11 @@ class Shortcut { // Advanced stuff. class ShortcutHandler { - constructor(element, filter = () => true) { + constructor(element, override, filter = () => true) { this.element = element; this.map = {}; this.active = this.map; + this.override = override; this.filter = filter; this.timeout = null; @@ -166,6 +167,9 @@ class Shortcut { this.active = this.active[shortcut]; if (this.active.action) { this.active.action(event); + if (this.override) { + event.preventDefault(); + } this.resetActive(); return; } @@ -268,7 +272,7 @@ class Shortcut { closeShortcutsReference(); }; - let dialogShortcuts = new ShortcutHandler(dialog, notTextField); + let dialogShortcuts = new ShortcutHandler(dialog, true, notTextField); dialogShortcuts.add('Escape', handleClose); closeButton.addEventListener('click', handleClose); @@ -298,7 +302,7 @@ class Shortcut { } window.addEventListener('load', () => { - let globalShortcuts = new ShortcutHandler(document, notTextField); + let globalShortcuts = new ShortcutHandler(document, false, notTextField); // Global shortcuts @@ -343,7 +347,7 @@ class Shortcut { // * Editor shortcuts if (typeof editTextarea !== 'undefined') { - let editorShortcuts = new ShortcutHandler(editTextarea); + let editorShortcuts = new ShortcutHandler(editTextarea, true); let bindElement = bindElementFactory(editorShortcuts); let shortcuts = [ From f6e32a16ebb957c2c865d70c71c6c0e73f7ce1cf Mon Sep 17 00:00:00 2001 From: handlerug Date: Mon, 14 Jun 2021 10:13:07 +0700 Subject: [PATCH 02/12] Revert "Read Handlerug's code" This reverts commit d069bd536efe9b94a7dc758908f590149c686952. "Because... everything was just fine?" --- static/shortcuts.js | 94 +++++++++++++++++++-------------------------- 1 file changed, 40 insertions(+), 54 deletions(-) diff --git a/static/shortcuts.js b/static/shortcuts.js index 0736e22..b88c9bf 100644 --- a/static/shortcuts.js +++ b/static/shortcuts.js @@ -1,6 +1,10 @@ -class Shortcut { - // turns the given event into a string representation of it. - static fromEvent(event) { +(() => { + const $ = document.querySelector.bind(document); + const $$ = (...args) => Array.prototype.slice.call(document.querySelectorAll(...args)); + + const isMac = /Macintosh/.test(window.navigator.userAgent); + + function keyEventToShortcut(event) { let elideShift = event.key.toUpperCase() === event.key && event.shiftKey; return (event.ctrlKey ? 'Ctrl+' : '') + (event.altKey ? 'Alt+' : '') + @@ -9,11 +13,9 @@ class Shortcut { (event.key === ',' ? 'Comma' : event.key === ' ' ? 'Space' : event.key); } - // Some keys look better with cool symbols instead of their long and boring names. - static prettify(shortcut, isMac) { + function prettifyShortcut(shortcut) { let keys = shortcut.split('+'); - // Uh it places the cmd sign before the letter to follow the Mac conventions, I guess. if (isMac) { let cmdIdx = keys.indexOf('Meta'); if (cmdIdx !== -1 && keys.length - cmdIdx > 2) { @@ -24,52 +26,39 @@ class Shortcut { } let lastKey = keys[keys.length - 1]; - // Uhh add Shift if the letter is uppercase?? if (!keys.includes('Shift') && lastKey.toUpperCase() === lastKey && lastKey.toLowerCase() !== lastKey) { keys.splice(keys.length - 1, 0, 'Shift'); } - return keys.map((key, i) => { - // If last element and there is more than one element and it's a letter - if (i === keys.length - 1 && i > 0 && key.length === 1) { - // Show in upper case. ⌘K looks better ⌘k, no doubt. - key = key.toUpperCase(); + for (let i = 0; i < keys.length; i++) { + if (isMac) { + switch (keys[i]) { + case 'Ctrl': keys[i] = '⌃'; break; + case 'Alt': keys[i] = '⌥'; break; + case 'Shift': keys[i] = '⇧'; break; + case 'Meta': keys[i] = '⌘'; break; + } } - return `${Shortcut.symbolifyKey(key, isMac)}`; - }).join(isMac ? '' : ' + '); - } - - static symbolifyKey(key, isMac) { - if (isMac) { - switch (key) { - case 'Ctrl': return '⌃'; - case 'Alt': return '⌥'; - case 'Shift': return '⇧'; - case 'Meta': return '⌘'; + if (i === keys.length - 1 && i > 0 && keys[i].length === 1) { + keys[i] = keys[i].toUpperCase(); } + + switch (keys[i]) { + case 'ArrowLeft': keys[i] = '←'; break; + case 'ArrowRight': keys[i] = '→'; break; + case 'ArrowTop': keys[i] = '↑'; break; + case 'ArrowBottom': keys[i] = '↓'; break; + case 'Comma': keys[i] = ','; break; + case 'Enter': keys[i] = '↩'; break; + case ' ': keys[i] = 'Space'; break; + } + + keys[i] = `${keys[i]}`; } - switch (key) { - case 'ArrowLeft': return '←'; - case 'ArrowRight': return '→'; - case 'ArrowUp': return '↑'; - case 'ArrowDown': return '↓'; - case 'Comma': return ','; - case 'Enter': return '↩'; - case ' ': return 'Space'; - } - return key + return keys.join(isMac ? '' : ' + '); } -} - -(() => { - const $ = document.querySelector.bind(document); - const $$ = (...args) => Array.prototype.slice.call(document.querySelectorAll(...args)); - - // Some things look different on Mac. - // Note that the ⌘ command key is called Meta in JS for some reason. - const isMac = /Macintosh/.test(window.navigator.userAgent); function isTextField(element) { let name = element.nodeName.toLowerCase(); @@ -81,12 +70,9 @@ class Shortcut { let notTextField = event => !(event.target instanceof Node && isTextField(event.target)); - // The whole shortcut table for current page. It is used for generating the dialog. let allShortcuts = []; - // Temporary variable for building a shortcut group. let shortcutsGroup = null; - // Advanced stuff. class ShortcutHandler { constructor(element, override, filter = () => true) { this.element = element; @@ -98,6 +84,10 @@ class Shortcut { this.handleKeyDown = this.handleKeyDown.bind(this); this.resetActive = this.resetActive.bind(this); + this.addEventListeners(); + } + + addEventListeners() { this.element.addEventListener('keydown', this.handleKeyDown); } @@ -141,11 +131,8 @@ class Shortcut { shortcutsGroup = null; } - // A dirty and shameful hack for inserting non-generated entries into the table. fakeItem(shortcut, description = null) { - // So it's a boolean, right? let list = shortcutsGroup || allShortcuts; - // And we push something into a boolean. I give up. list.push({ shortcut: description ? shortcut : null, description: description || shortcut, @@ -157,7 +144,7 @@ class Shortcut { if (['Control', 'Alt', 'Shift', 'Meta'].includes(event.key)) return; if (!this.filter(event)) return; - let shortcut = Shortcut.fromEvent(event); + let shortcut = keyEventToShortcut(event); if (!this.active[shortcut]) { this.resetActive(); @@ -209,7 +196,7 @@ class Shortcut { let shortcutsListDialog = null; function openShortcutsReference() { - if (!shortcutsListDialog) { // I guess the dialog is reused for second and subsequent invocations. + if (!shortcutsListDialog) { let wrap = document.createElement('div'); wrap.className = 'dialog-wrap'; shortcutsListDialog = wrap; @@ -230,7 +217,7 @@ class Shortcut { let closeButton = document.createElement('button'); closeButton.className = 'dialog__close-button'; - closeButton.setAttribute('aria-label', 'Close this dialog'); // a11y gang + closeButton.setAttribute('aria-label', 'Close this dialog'); dialogHeader.appendChild(closeButton); for (let item of allShortcuts) { @@ -257,7 +244,7 @@ class Shortcut { let shortcutColumn = document.createElement('div'); shortcutColumn.className = 'shortcut-row__keys'; shortcutColumn.innerHTML = shortcut.shortcut.split(',') - .map(shortcuts => shortcuts.trim().split(' ').map((sc) => Shortcut.prettify(sc, isMac)).join(' ')) + .map(shortcuts => shortcuts.trim().split(' ').map(prettifyShortcut).join(' ')) .join(' or '); listItem.appendChild(shortcutColumn); } @@ -312,7 +299,6 @@ class Shortcut { // * Common shortcuts globalShortcuts.fakeItem('Common'); - // Nice indentation here globalShortcuts.groupStart(); globalShortcuts.fakeItem('g 1 – 9', 'First 9 header links'); bindLink('g h', '/', 'Home'); @@ -345,7 +331,7 @@ class Shortcut { } } - // * Editor shortcuts + // Hypha editor shortcuts if (typeof editTextarea !== 'undefined') { let editorShortcuts = new ShortcutHandler(editTextarea, true); let bindElement = bindElementFactory(editorShortcuts); From c5740085644bf5678db42af1ad456f86db529be2 Mon Sep 17 00:00:00 2001 From: handlerug Date: Mon, 14 Jun 2021 10:15:37 +0700 Subject: [PATCH 03/12] Change superscript and subscript shortcuts on Mac Now they won't conflict with the default browser actions, if we're going to not stop the browser from doing its own thing. --- static/shortcuts.js | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/static/shortcuts.js b/static/shortcuts.js index b88c9bf..f4cc2df 100644 --- a/static/shortcuts.js +++ b/static/shortcuts.js @@ -340,17 +340,15 @@ // Inspired by MS Word, Pages, Google Docs and Telegram desktop clients. // And by myself, too. - // Win+Linux Mac Action Description - ['Ctrl+b', 'Meta+b', wrapBold, 'Format: Bold'], - ['Ctrl+i', 'Meta+i', wrapItalic, 'Format: Italic'], - ['Ctrl+M', 'Meta+Shift+m', wrapMonospace, 'Format: Monospaced'], - ['Ctrl+I', 'Meta+Shift+i', wrapHighlighted, 'Format: Highlight'], - ['Ctrl+.', 'Meta+.', wrapLifted, 'Format: Superscript'], - ['Ctrl+Comma', 'Meta+Comma', wrapLowered, 'Format: Subscript'], - // Strikethrough conflicts with 1Password on my machine but - // I'm probably the only Mycorrhiza user who uses 1Password. -handlerug - ['Ctrl+X', 'Meta+Shift+x', wrapStrikethrough, 'Format: Strikethrough'], - ['Ctrl+k', 'Meta+k', wrapLink, 'Format: Link'], + // Win+Linux Mac Action Description + ['Ctrl+b', 'Meta+b', wrapBold, 'Format: Bold'], + ['Ctrl+i', 'Meta+i', wrapItalic, 'Format: Italic'], + ['Ctrl+M', 'Meta+Shift+m', wrapMonospace, 'Format: Monospaced'], + ['Ctrl+I', 'Meta+Shift+i', wrapHighlighted, 'Format: Highlight'], + ['Ctrl+.', 'Meta+Shift+.', wrapLifted, 'Format: Superscript'], + ['Ctrl+Comma', 'Meta+Shift+Comma', wrapLowered, 'Format: Subscript'], + ['Ctrl+X', 'Meta+Shift+x', wrapStrikethrough, 'Format: Strikethrough'], + ['Ctrl+k', 'Meta+k', wrapLink, 'Format: Link'], ]; editorShortcuts.fakeItem('Editor'); From 2f9ea998bf962b4190621e9166c0e3c83f6ac39c Mon Sep 17 00:00:00 2001 From: handlerug Date: Mon, 14 Jun 2021 10:33:11 +0700 Subject: [PATCH 04/12] Fix shortcuts prettifier (vertical arrow keys) --- static/shortcuts.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/static/shortcuts.js b/static/shortcuts.js index f4cc2df..75179c0 100644 --- a/static/shortcuts.js +++ b/static/shortcuts.js @@ -47,8 +47,8 @@ switch (keys[i]) { case 'ArrowLeft': keys[i] = '←'; break; case 'ArrowRight': keys[i] = '→'; break; - case 'ArrowTop': keys[i] = '↑'; break; - case 'ArrowBottom': keys[i] = '↓'; break; + case 'ArrowUp': keys[i] = '↑'; break; + case 'ArrowDown': keys[i] = '↓'; break; case 'Comma': keys[i] = ','; break; case 'Enter': keys[i] = '↩'; break; case ' ': keys[i] = 'Space'; break; From 50dfabe279b63b433cb46599d250f61bcc0f8588 Mon Sep 17 00:00:00 2001 From: handlerug Date: Mon, 14 Jun 2021 10:35:37 +0700 Subject: [PATCH 05/12] Make the shortcuts prettifier even prettier --- static/default.css | 4 ++++ static/shortcuts.js | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/static/default.css b/static/default.css index 3e554d6..c148758 100644 --- a/static/default.css +++ b/static/default.css @@ -312,6 +312,10 @@ kbd { text-align: center; } +.kbd-or { + opacity: .4; +} + .dialog-wrap { position: fixed; top: 0; diff --git a/static/shortcuts.js b/static/shortcuts.js index 75179c0..35fc941 100644 --- a/static/shortcuts.js +++ b/static/shortcuts.js @@ -245,7 +245,7 @@ shortcutColumn.className = 'shortcut-row__keys'; shortcutColumn.innerHTML = shortcut.shortcut.split(',') .map(shortcuts => shortcuts.trim().split(' ').map(prettifyShortcut).join(' ')) - .join(' or '); + .join(' or '); listItem.appendChild(shortcutColumn); } From 6120e3b27fd4b39d0d58b890cc7c9dd8144fad09 Mon Sep 17 00:00:00 2001 From: handlerug Date: Mon, 14 Jun 2021 10:40:15 +0700 Subject: [PATCH 06/12] Split shortcuts help into columns if enough space --- static/default.css | 16 +++++++++++++--- static/shortcuts.js | 21 ++++++++++++++++++--- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/static/default.css b/static/default.css index c148758..b5ccf70 100644 --- a/static/default.css +++ b/static/default.css @@ -332,7 +332,7 @@ kbd { position: relative; width: 100%; - max-width: 400px; + max-width: 700px; margin: 96px auto; padding: 24px; @@ -341,6 +341,10 @@ kbd { box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2); } +.dialog__header { + grid-column: 1 / -1; +} + .dialog__title { margin: 0; font-size: 1.5em; @@ -364,17 +368,23 @@ kbd { opacity: .7; } +.shortcuts-modal { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); + grid-column-gap: 32px; +} + .shortcuts-group-heading { margin: 1em 0 0.5em; font-size: 1.2em; } -.shortcuts-group { +.shortcuts-list { margin: 0; padding: 0; } -.shortcuts-group + .shortcuts-group { +.shortcuts-list + .shortcuts-list { margin-top: 1.5em; } diff --git a/static/shortcuts.js b/static/shortcuts.js index 35fc941..a5d2333 100644 --- a/static/shortcuts.js +++ b/static/shortcuts.js @@ -220,16 +220,26 @@ closeButton.setAttribute('aria-label', 'Close this dialog'); dialogHeader.appendChild(closeButton); + let shortcutsGroupTemplate = document.createElement('div'); + shortcutsGroupTemplate.className = 'shortcuts-group'; + + let shortcutsGroup = shortcutsGroupTemplate.cloneNode(); + for (let item of allShortcuts) { if (item.description && !item.shortcut) { + if (shortcutsGroup.children.length > 0) { + dialog.appendChild(shortcutsGroup); + shortcutsGroup = shortcutsGroupTemplate.cloneNode(); + } + let heading = document.createElement('h2'); heading.className = 'shortcuts-group-heading'; heading.textContent = item.description; - dialog.appendChild(heading); + shortcutsGroup.appendChild(heading); } else { let list = document.createElement('ul'); - list.className = 'shortcuts-group'; + list.className = 'shortcuts-list'; for (let shortcut of item) { let listItem = document.createElement('li'); @@ -249,10 +259,15 @@ listItem.appendChild(shortcutColumn); } - dialog.appendChild(list); + shortcutsGroup.appendChild(list); } } + if (shortcutsGroup.children.length > 0) { + dialog.appendChild(shortcutsGroup); + shortcutsGroup = shortcutsGroupTemplate.cloneNode(); + } + let handleClose = (event) => { event.preventDefault(); event.stopPropagation(); From 6b074e88eab9dd012a0e2d6e153edb8c7a376319 Mon Sep 17 00:00:00 2001 From: handlerug Date: Mon, 14 Jun 2021 10:58:36 +0700 Subject: [PATCH 07/12] bindCollection helper, better code --- static/shortcuts.js | 91 +++++++++++++++++++++------------------------ 1 file changed, 42 insertions(+), 49 deletions(-) diff --git a/static/shortcuts.js b/static/shortcuts.js index a5d2333..e1214cc 100644 --- a/static/shortcuts.js +++ b/static/shortcuts.js @@ -78,7 +78,7 @@ this.element = element; this.map = {}; this.active = this.map; - this.override = override; + this.override = override; this.filter = filter; this.timeout = null; @@ -91,10 +91,10 @@ this.element.addEventListener('keydown', this.handleKeyDown); } - add(text, action, description = null) { - let shortcuts = text.split(',').map(shortcut => shortcut.trim().split(' ')); + add(text, action, description = null, shownInHelp = true) { + let shortcuts = text.trim().split(',').map(shortcut => shortcut.trim().split(' ')); - if (shortcutsGroup) { + if (shortcutsGroup && shownInHelp) { shortcutsGroup.push({ action, shortcut: text, @@ -122,7 +122,8 @@ } } - groupStart() { + groupStart(title = null) { + if (title) this.fakeItem(title); shortcutsGroup = []; } @@ -154,9 +155,7 @@ this.active = this.active[shortcut]; if (this.active.action) { this.active.action(event); - if (this.override) { - event.preventDefault(); - } + if (this.override) event.preventDefault(); this.resetActive(); return; } @@ -192,6 +191,22 @@ return (shortcut, link, ...other) => handler.add(shortcut, () => window.location.href = link, ...other); } + function bindCollectionFactory(handler) { + return (prefix, elements, collectionDescription, itemDescription) => { + handler.fakeItem(prefix + ' 1 – 9', collectionDescription); + + if (typeof elements === 'string') { + elements = $$(elements); + } else if (Array.isArray(elements)) { + elements = elements.map(el => typeof el === 'string' ? $(el) : el); + } + + for (let i = 1; i <= elements.length && i < 10; i++) { + bindElementFactory(handler)(`${prefix} ${i}`, elements[i-1], `${itemDescription} #${i}`, false); + } + } + } + let prevActiveElement = null; let shortcutsListDialog = null; @@ -304,57 +319,43 @@ } window.addEventListener('load', () => { - let globalShortcuts = new ShortcutHandler(document, false, notTextField); + // Global shortcuts work everywhere. + let globalShortcuts = new ShortcutHandler(document, false); + globalShortcuts.add('?, ' + (isMac ? 'Meta+/' : 'Ctrl+/'), openShortcutsReference); - // Global shortcuts + // Common shortcuts work everywhere except on text fields. + let commonShortcuts = new ShortcutHandler(document, false, notTextField); - let bindElement = bindElementFactory(globalShortcuts); - let bindLink = bindLinkFactory(globalShortcuts); + let bindElement = bindElementFactory(commonShortcuts); + let bindLink = bindLinkFactory(commonShortcuts); + let bindCollection = bindCollectionFactory(commonShortcuts); - // * Common shortcuts - globalShortcuts.fakeItem('Common'); - - globalShortcuts.groupStart(); - globalShortcuts.fakeItem('g 1 – 9', 'First 9 header links'); + // Common shortcuts + commonShortcuts.groupStart('Common'); + bindCollection('g', '.header-links__link', 'First 9 header links', 'Header link'); bindLink('g h', '/', 'Home'); bindLink('g l', '/list/', 'List of hyphae'); bindLink('g r', '/recent-changes/', 'Recent changes'); bindElement('g u', '.header-links__entry_user .header-links__link', 'Your profile′s hypha'); - globalShortcuts.groupEnd(); + commonShortcuts.groupEnd(); - let headerLinks = $$('.header-links__link'); - for (let i = 1; i <= headerLinks.length && i < 10; i++) { - bindElement(`g ${i}`, headerLinks[i-1], `Header link #${i}`); - } - - // * Hypha shortcuts if (typeof editTextarea === 'undefined') { - globalShortcuts.fakeItem('Hypha'); - - globalShortcuts.groupStart(); - globalShortcuts.fakeItem('1 – 9', 'First 9 hypha′s links'); + // Hypha shortcuts + commonShortcuts.groupStart('Hypha'); + bindCollection('', 'article .wikilink', 'First 9 hypha′s links', 'Hypha link'); bindElement('p, Alt+ArrowLeft, Ctrl+Alt+ArrowLeft', '.prevnext__prev', 'Next hypha'); bindElement('n, Alt+ArrowRight, Ctrl+Alt+ArrowRight', '.prevnext__next', 'Previous hypha'); bindElement('s, Alt+ArrowUp, Ctrl+Alt+ArrowUp', $$('.navi-title a').slice(1, -1).slice(-1)[0], 'Parent hypha'); bindElement('c, Alt+ArrowDown, Ctrl+Alt+ArrowDown', '.subhyphae__link', 'First child hypha'); bindElement('e, Ctrl+Enter', '.hypha-tabs__link[href^="/edit/"]', 'Edit this hypha'); - globalShortcuts.groupEnd(); + commonShortcuts.groupEnd(); - let hyphaLinks = $$('article .wikilink'); - for (let i = 1; i <= hyphaLinks.length && i < 10; i++) { - bindElement(i.toString(), hyphaLinks[i-1], `Hypha link #${i}`); - } - } - - // Hypha editor shortcuts - if (typeof editTextarea !== 'undefined') { + } else { + // Hypha editor shortcuts. These work only on editor's text area. let editorShortcuts = new ShortcutHandler(editTextarea, true); let bindElement = bindElementFactory(editorShortcuts); let shortcuts = [ - // Inspired by MS Word, Pages, Google Docs and Telegram desktop clients. - // And by myself, too. - // Win+Linux Mac Action Description ['Ctrl+b', 'Meta+b', wrapBold, 'Format: Bold'], ['Ctrl+i', 'Meta+i', wrapItalic, 'Format: Italic'], @@ -366,9 +367,7 @@ ['Ctrl+k', 'Meta+k', wrapLink, 'Format: Link'], ]; - editorShortcuts.fakeItem('Editor'); - - editorShortcuts.groupStart(); + editorShortcuts.groupStart('Editor'); for (let shortcut of shortcuts) { if (isMac) { editorShortcuts.add(shortcut[1], ...shortcut.slice(2)) @@ -381,12 +380,6 @@ editorShortcuts.groupStart(); bindElement(isMac ? 'Meta+Enter' : 'Ctrl+Enter', $('.edit-form__save'), 'Save changes'); editorShortcuts.groupEnd(); - - // Help shortcut - editorShortcuts.add(isMac ? 'Meta+/' : 'Ctrl+/', openShortcutsReference); } - - // * Meta shortcuts - globalShortcuts.add('?', openShortcutsReference); }); })(); From b4910edcca8643abadc8e0198667336a6458f046 Mon Sep 17 00:00:00 2001 From: handlerug Date: Mon, 14 Jun 2021 12:16:50 +0700 Subject: [PATCH 08/12] Refactor shortcut help --- static/default.css | 2 +- static/shortcuts.js | 99 +++++-------- views/stuff.qtpl | 12 ++ views/stuff.qtpl.go | 350 +++++++++++++++++++++++--------------------- 4 files changed, 233 insertions(+), 230 deletions(-) diff --git a/static/default.css b/static/default.css index b5ccf70..cb5fd23 100644 --- a/static/default.css +++ b/static/default.css @@ -368,7 +368,7 @@ kbd { opacity: .7; } -.shortcuts-modal { +.shortcuts-help .dialog__content { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); grid-column-gap: 32px; diff --git a/static/shortcuts.js b/static/shortcuts.js index e1214cc..54c7146 100644 --- a/static/shortcuts.js +++ b/static/shortcuts.js @@ -207,45 +207,36 @@ } } - let prevActiveElement = null; - let shortcutsListDialog = null; + class ShortcutsHelpDialog { + constructor() { + let template = $('#dialog-template'); + this.wrap = template.content.firstElementChild.cloneNode(true); + this.wrap.classList.add('shortcuts-help'); + this.wrap.hidden = true; - function openShortcutsReference() { - if (!shortcutsListDialog) { - let wrap = document.createElement('div'); - wrap.className = 'dialog-wrap'; - shortcutsListDialog = wrap; + let handleClose = (event) => { + event.preventDefault(); + event.stopPropagation(); + this.close(); + }; - let dialog = document.createElement('div'); - dialog.className = 'dialog shortcuts-modal'; - dialog.tabIndex = 0; - wrap.appendChild(dialog); + this.shortcuts = new ShortcutHandler(this.wrap, false); + this.shortcuts.add('Escape', handleClose, null, false); - let dialogHeader = document.createElement('div'); - dialogHeader.className = 'dialog__header'; - dialog.appendChild(dialogHeader); + this.wrap.querySelector('.dialog__title').textContent = 'List of shortcuts'; + this.wrap.querySelector('.dialog__close-button').addEventListener('click', handleClose); - let title = document.createElement('h1'); - title.className = 'dialog__title'; - title.textContent = 'List of shortcuts'; - dialogHeader.appendChild(title); - - let closeButton = document.createElement('button'); - closeButton.className = 'dialog__close-button'; - closeButton.setAttribute('aria-label', 'Close this dialog'); - dialogHeader.appendChild(closeButton); + this.wrap.addEventListener('click', handleClose); + this.wrap.querySelector('.dialog').addEventListener('click', event => event.stopPropagation()); + let shortcutsGroup; let shortcutsGroupTemplate = document.createElement('div'); shortcutsGroupTemplate.className = 'shortcuts-group'; - let shortcutsGroup = shortcutsGroupTemplate.cloneNode(); - for (let item of allShortcuts) { if (item.description && !item.shortcut) { - if (shortcutsGroup.children.length > 0) { - dialog.appendChild(shortcutsGroup); - shortcutsGroup = shortcutsGroupTemplate.cloneNode(); - } + shortcutsGroup = shortcutsGroupTemplate.cloneNode(); + this.wrap.querySelector('.dialog__content').appendChild(shortcutsGroup); let heading = document.createElement('h2'); heading.className = 'shortcuts-group-heading'; @@ -278,47 +269,35 @@ } } - if (shortcutsGroup.children.length > 0) { - dialog.appendChild(shortcutsGroup); - shortcutsGroup = shortcutsGroupTemplate.cloneNode(); - } - - let handleClose = (event) => { - event.preventDefault(); - event.stopPropagation(); - closeShortcutsReference(); - }; - - let dialogShortcuts = new ShortcutHandler(dialog, true, notTextField); - - dialogShortcuts.add('Escape', handleClose); - closeButton.addEventListener('click', handleClose); - wrap.addEventListener('click', handleClose); - - dialog.addEventListener('click', event => event.stopPropagation()); - - document.body.appendChild(wrap); + document.body.appendChild(this.wrap); } - document.body.overflow = 'hidden'; - shortcutsListDialog.hidden = false; - prevActiveElement = document.activeElement; - shortcutsListDialog.children[0].focus(); - } + open() { + this.prevActiveElement = document.activeElement; - function closeShortcutsReference() { - if (shortcutsListDialog) { + document.body.overflow = 'hidden'; + this.wrap.hidden = false; + this.wrap.children[0].focus(); + } + + close() { document.body.overflow = ''; - shortcutsListDialog.hidden = true; + this.wrap.hidden = true; - if (prevActiveElement) { - prevActiveElement.focus(); - prevActiveElement = null; + if (this.prevActiveElement) { + this.prevActiveElement.focus(); + this.prevActiveElement = null; } } } window.addEventListener('load', () => { + let helpDialog = null; + let openHelp = () => { + if (!helpDialog) helpDialog = new ShortcutsHelpDialog(); + helpDialog.open(); + }; + // Global shortcuts work everywhere. let globalShortcuts = new ShortcutHandler(document, false); globalShortcuts.add('?, ' + (isMac ? 'Meta+/' : 'Ctrl+/'), openShortcutsReference); diff --git a/views/stuff.qtpl b/views/stuff.qtpl index 0e75d94..7a27a98 100644 --- a/views/stuff.qtpl +++ b/views/stuff.qtpl @@ -28,6 +28,18 @@ {%s= body %} + {%= omnipresentScripts() %} diff --git a/views/stuff.qtpl.go b/views/stuff.qtpl.go index 5a255bb..054aab3 100644 --- a/views/stuff.qtpl.go +++ b/views/stuff.qtpl.go @@ -93,52 +93,64 @@ func StreamBaseHTML(qw422016 *qt422016.Writer, title, body string, u *user.User, qw422016.N().S(body) //line views/stuff.qtpl:30 qw422016.N().S(` + `) -//line views/stuff.qtpl:31 +//line views/stuff.qtpl:43 streamomnipresentScripts(qw422016) -//line views/stuff.qtpl:31 +//line views/stuff.qtpl:43 qw422016.N().S(` `) -//line views/stuff.qtpl:34 +//line views/stuff.qtpl:46 } -//line views/stuff.qtpl:34 +//line views/stuff.qtpl:46 func WriteBaseHTML(qq422016 qtio422016.Writer, title, body string, u *user.User, headElements ...string) { -//line views/stuff.qtpl:34 +//line views/stuff.qtpl:46 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/stuff.qtpl:34 +//line views/stuff.qtpl:46 StreamBaseHTML(qw422016, title, body, u, headElements...) -//line views/stuff.qtpl:34 +//line views/stuff.qtpl:46 qt422016.ReleaseWriter(qw422016) -//line views/stuff.qtpl:34 +//line views/stuff.qtpl:46 } -//line views/stuff.qtpl:34 +//line views/stuff.qtpl:46 func BaseHTML(title, body string, u *user.User, headElements ...string) string { -//line views/stuff.qtpl:34 +//line views/stuff.qtpl:46 qb422016 := qt422016.AcquireByteBuffer() -//line views/stuff.qtpl:34 +//line views/stuff.qtpl:46 WriteBaseHTML(qb422016, title, body, u, headElements...) -//line views/stuff.qtpl:34 +//line views/stuff.qtpl:46 qs422016 := string(qb422016.B) -//line views/stuff.qtpl:34 +//line views/stuff.qtpl:46 qt422016.ReleaseByteBuffer(qb422016) -//line views/stuff.qtpl:34 +//line views/stuff.qtpl:46 return qs422016 -//line views/stuff.qtpl:34 +//line views/stuff.qtpl:46 } -//line views/stuff.qtpl:36 +//line views/stuff.qtpl:48 func StreamUserListHTML(qw422016 *qt422016.Writer) { -//line views/stuff.qtpl:36 +//line views/stuff.qtpl:48 qw422016.N().S(`

List of users

`) -//line views/stuff.qtpl:41 +//line views/stuff.qtpl:53 var ( admins = make([]string, 0) moderators = make([]string, 0) @@ -155,303 +167,303 @@ func StreamUserListHTML(qw422016 *qt422016.Writer) { } } -//line views/stuff.qtpl:56 +//line views/stuff.qtpl:68 qw422016.N().S(`

Admins

    `) -//line views/stuff.qtpl:59 +//line views/stuff.qtpl:71 for _, name := range admins { -//line views/stuff.qtpl:59 +//line views/stuff.qtpl:71 qw422016.N().S(`
  1. `) -//line views/stuff.qtpl:60 +//line views/stuff.qtpl:72 qw422016.E().S(name) -//line views/stuff.qtpl:60 +//line views/stuff.qtpl:72 qw422016.N().S(`
  2. `) -//line views/stuff.qtpl:61 +//line views/stuff.qtpl:73 } -//line views/stuff.qtpl:61 +//line views/stuff.qtpl:73 qw422016.N().S(`

Moderators

    `) -//line views/stuff.qtpl:65 +//line views/stuff.qtpl:77 for _, name := range moderators { -//line views/stuff.qtpl:65 +//line views/stuff.qtpl:77 qw422016.N().S(`
  1. `) -//line views/stuff.qtpl:66 +//line views/stuff.qtpl:78 qw422016.E().S(name) -//line views/stuff.qtpl:66 +//line views/stuff.qtpl:78 qw422016.N().S(`
  2. `) -//line views/stuff.qtpl:67 +//line views/stuff.qtpl:79 } -//line views/stuff.qtpl:67 +//line views/stuff.qtpl:79 qw422016.N().S(`

Editors

    `) -//line views/stuff.qtpl:71 +//line views/stuff.qtpl:83 for _, name := range editors { -//line views/stuff.qtpl:71 +//line views/stuff.qtpl:83 qw422016.N().S(`
  1. `) -//line views/stuff.qtpl:72 +//line views/stuff.qtpl:84 qw422016.E().S(name) -//line views/stuff.qtpl:72 +//line views/stuff.qtpl:84 qw422016.N().S(`
  2. `) -//line views/stuff.qtpl:73 +//line views/stuff.qtpl:85 } -//line views/stuff.qtpl:73 +//line views/stuff.qtpl:85 qw422016.N().S(`
`) -//line views/stuff.qtpl:77 +//line views/stuff.qtpl:89 } -//line views/stuff.qtpl:77 +//line views/stuff.qtpl:89 func WriteUserListHTML(qq422016 qtio422016.Writer) { -//line views/stuff.qtpl:77 +//line views/stuff.qtpl:89 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/stuff.qtpl:77 +//line views/stuff.qtpl:89 StreamUserListHTML(qw422016) -//line views/stuff.qtpl:77 +//line views/stuff.qtpl:89 qt422016.ReleaseWriter(qw422016) -//line views/stuff.qtpl:77 +//line views/stuff.qtpl:89 } -//line views/stuff.qtpl:77 +//line views/stuff.qtpl:89 func UserListHTML() string { -//line views/stuff.qtpl:77 +//line views/stuff.qtpl:89 qb422016 := qt422016.AcquireByteBuffer() -//line views/stuff.qtpl:77 +//line views/stuff.qtpl:89 WriteUserListHTML(qb422016) -//line views/stuff.qtpl:77 +//line views/stuff.qtpl:89 qs422016 := string(qb422016.B) -//line views/stuff.qtpl:77 +//line views/stuff.qtpl:89 qt422016.ReleaseByteBuffer(qb422016) -//line views/stuff.qtpl:77 +//line views/stuff.qtpl:89 return qs422016 -//line views/stuff.qtpl:77 +//line views/stuff.qtpl:89 } -//line views/stuff.qtpl:79 +//line views/stuff.qtpl:91 func StreamHyphaListHTML(qw422016 *qt422016.Writer) { -//line views/stuff.qtpl:79 +//line views/stuff.qtpl:91 qw422016.N().S(`

List of hyphae

This wiki has `) -//line views/stuff.qtpl:83 +//line views/stuff.qtpl:95 qw422016.N().D(hyphae.Count()) -//line views/stuff.qtpl:83 +//line views/stuff.qtpl:95 qw422016.N().S(` hyphae.

    `) -//line views/stuff.qtpl:85 +//line views/stuff.qtpl:97 for h := range hyphae.YieldExistingHyphae() { -//line views/stuff.qtpl:85 +//line views/stuff.qtpl:97 qw422016.N().S(`
  • `) -//line views/stuff.qtpl:87 +//line views/stuff.qtpl:99 qw422016.E().S(util.BeautifulName(h.Name)) -//line views/stuff.qtpl:87 +//line views/stuff.qtpl:99 qw422016.N().S(` `) -//line views/stuff.qtpl:88 +//line views/stuff.qtpl:100 if h.BinaryPath != "" { -//line views/stuff.qtpl:88 +//line views/stuff.qtpl:100 qw422016.N().S(` `) -//line views/stuff.qtpl:89 +//line views/stuff.qtpl:101 qw422016.E().S(filepath.Ext(h.BinaryPath)[1:]) -//line views/stuff.qtpl:89 +//line views/stuff.qtpl:101 qw422016.N().S(` `) -//line views/stuff.qtpl:90 +//line views/stuff.qtpl:102 } -//line views/stuff.qtpl:90 +//line views/stuff.qtpl:102 qw422016.N().S(`
  • `) -//line views/stuff.qtpl:92 +//line views/stuff.qtpl:104 } -//line views/stuff.qtpl:92 +//line views/stuff.qtpl:104 qw422016.N().S(`
`) -//line views/stuff.qtpl:96 +//line views/stuff.qtpl:108 } -//line views/stuff.qtpl:96 +//line views/stuff.qtpl:108 func WriteHyphaListHTML(qq422016 qtio422016.Writer) { -//line views/stuff.qtpl:96 +//line views/stuff.qtpl:108 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/stuff.qtpl:96 +//line views/stuff.qtpl:108 StreamHyphaListHTML(qw422016) -//line views/stuff.qtpl:96 +//line views/stuff.qtpl:108 qt422016.ReleaseWriter(qw422016) -//line views/stuff.qtpl:96 +//line views/stuff.qtpl:108 } -//line views/stuff.qtpl:96 +//line views/stuff.qtpl:108 func HyphaListHTML() string { -//line views/stuff.qtpl:96 +//line views/stuff.qtpl:108 qb422016 := qt422016.AcquireByteBuffer() -//line views/stuff.qtpl:96 +//line views/stuff.qtpl:108 WriteHyphaListHTML(qb422016) -//line views/stuff.qtpl:96 +//line views/stuff.qtpl:108 qs422016 := string(qb422016.B) -//line views/stuff.qtpl:96 +//line views/stuff.qtpl:108 qt422016.ReleaseByteBuffer(qb422016) -//line views/stuff.qtpl:96 +//line views/stuff.qtpl:108 return qs422016 -//line views/stuff.qtpl:96 +//line views/stuff.qtpl:108 } -//line views/stuff.qtpl:98 +//line views/stuff.qtpl:110 func StreamAboutHTML(qw422016 *qt422016.Writer) { -//line views/stuff.qtpl:98 +//line views/stuff.qtpl:110 qw422016.N().S(`

About `) -//line views/stuff.qtpl:102 +//line views/stuff.qtpl:114 qw422016.E().S(cfg.WikiName) -//line views/stuff.qtpl:102 +//line views/stuff.qtpl:114 qw422016.N().S(`

See /list for information about hyphae on this wiki.

`) -//line views/stuff.qtpl:120 +//line views/stuff.qtpl:132 } -//line views/stuff.qtpl:120 +//line views/stuff.qtpl:132 func WriteAboutHTML(qq422016 qtio422016.Writer) { -//line views/stuff.qtpl:120 +//line views/stuff.qtpl:132 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/stuff.qtpl:120 +//line views/stuff.qtpl:132 StreamAboutHTML(qw422016) -//line views/stuff.qtpl:120 +//line views/stuff.qtpl:132 qt422016.ReleaseWriter(qw422016) -//line views/stuff.qtpl:120 +//line views/stuff.qtpl:132 } -//line views/stuff.qtpl:120 +//line views/stuff.qtpl:132 func AboutHTML() string { -//line views/stuff.qtpl:120 +//line views/stuff.qtpl:132 qb422016 := qt422016.AcquireByteBuffer() -//line views/stuff.qtpl:120 +//line views/stuff.qtpl:132 WriteAboutHTML(qb422016) -//line views/stuff.qtpl:120 +//line views/stuff.qtpl:132 qs422016 := string(qb422016.B) -//line views/stuff.qtpl:120 +//line views/stuff.qtpl:132 qt422016.ReleaseByteBuffer(qb422016) -//line views/stuff.qtpl:120 +//line views/stuff.qtpl:132 return qs422016 -//line views/stuff.qtpl:120 +//line views/stuff.qtpl:132 } -//line views/stuff.qtpl:122 +//line views/stuff.qtpl:134 func StreamAdminPanelHTML(qw422016 *qt422016.Writer) { -//line views/stuff.qtpl:122 +//line views/stuff.qtpl:134 qw422016.N().S(`
@@ -488,80 +500,80 @@ func StreamAdminPanelHTML(qw422016 *qt422016.Writer) {
`) -//line views/stuff.qtpl:157 +//line views/stuff.qtpl:169 } -//line views/stuff.qtpl:157 +//line views/stuff.qtpl:169 func WriteAdminPanelHTML(qq422016 qtio422016.Writer) { -//line views/stuff.qtpl:157 +//line views/stuff.qtpl:169 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/stuff.qtpl:157 +//line views/stuff.qtpl:169 StreamAdminPanelHTML(qw422016) -//line views/stuff.qtpl:157 +//line views/stuff.qtpl:169 qt422016.ReleaseWriter(qw422016) -//line views/stuff.qtpl:157 +//line views/stuff.qtpl:169 } -//line views/stuff.qtpl:157 +//line views/stuff.qtpl:169 func AdminPanelHTML() string { -//line views/stuff.qtpl:157 +//line views/stuff.qtpl:169 qb422016 := qt422016.AcquireByteBuffer() -//line views/stuff.qtpl:157 +//line views/stuff.qtpl:169 WriteAdminPanelHTML(qb422016) -//line views/stuff.qtpl:157 +//line views/stuff.qtpl:169 qs422016 := string(qb422016.B) -//line views/stuff.qtpl:157 +//line views/stuff.qtpl:169 qt422016.ReleaseByteBuffer(qb422016) -//line views/stuff.qtpl:157 +//line views/stuff.qtpl:169 return qs422016 -//line views/stuff.qtpl:157 +//line views/stuff.qtpl:169 } -//line views/stuff.qtpl:159 +//line views/stuff.qtpl:171 func streamomnipresentScripts(qw422016 *qt422016.Writer) { -//line views/stuff.qtpl:159 +//line views/stuff.qtpl:171 qw422016.N().S(` `) -//line views/stuff.qtpl:160 +//line views/stuff.qtpl:172 for _, scriptPath := range cfg.OmnipresentScripts { -//line views/stuff.qtpl:160 +//line views/stuff.qtpl:172 qw422016.N().S(` `) -//line views/stuff.qtpl:162 +//line views/stuff.qtpl:174 } -//line views/stuff.qtpl:162 +//line views/stuff.qtpl:174 qw422016.N().S(` `) -//line views/stuff.qtpl:163 +//line views/stuff.qtpl:175 } -//line views/stuff.qtpl:163 +//line views/stuff.qtpl:175 func writeomnipresentScripts(qq422016 qtio422016.Writer) { -//line views/stuff.qtpl:163 +//line views/stuff.qtpl:175 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/stuff.qtpl:163 +//line views/stuff.qtpl:175 streamomnipresentScripts(qw422016) -//line views/stuff.qtpl:163 +//line views/stuff.qtpl:175 qt422016.ReleaseWriter(qw422016) -//line views/stuff.qtpl:163 +//line views/stuff.qtpl:175 } -//line views/stuff.qtpl:163 +//line views/stuff.qtpl:175 func omnipresentScripts() string { -//line views/stuff.qtpl:163 +//line views/stuff.qtpl:175 qb422016 := qt422016.AcquireByteBuffer() -//line views/stuff.qtpl:163 +//line views/stuff.qtpl:175 writeomnipresentScripts(qb422016) -//line views/stuff.qtpl:163 +//line views/stuff.qtpl:175 qs422016 := string(qb422016.B) -//line views/stuff.qtpl:163 +//line views/stuff.qtpl:175 qt422016.ReleaseByteBuffer(qb422016) -//line views/stuff.qtpl:163 +//line views/stuff.qtpl:175 return qs422016 -//line views/stuff.qtpl:163 +//line views/stuff.qtpl:175 } From 4dc319116a1e5e3ba1294c41a54ebc949a207938 Mon Sep 17 00:00:00 2001 From: handlerug Date: Mon, 14 Jun 2021 13:50:52 +0700 Subject: [PATCH 09/12] Aaaaaa more shortcuts refactoring --- static/default.css | 29 ++-- static/shortcuts.js | 178 +++++++++++----------- views/stuff.qtpl | 15 +- views/stuff.qtpl.go | 353 ++++++++++++++++++++++---------------------- 4 files changed, 284 insertions(+), 291 deletions(-) diff --git a/static/default.css b/static/default.css index cb5fd23..22874a2 100644 --- a/static/default.css +++ b/static/default.css @@ -316,32 +316,33 @@ kbd { opacity: .4; } -.dialog-wrap { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - background-color: rgba(0, 0, 0, 0.3); - overflow-y: auto; - - padding: 0 16px; -} - .dialog { - position: relative; + position: absolute; + top: 0; + left: 50%; width: 100%; max-width: 700px; margin: 96px auto; padding: 24px; + transform: translate(-50%, 0); background-color: #fff; border-radius: 4px; box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2); } +.dialog-backdrop { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.3); +} + .dialog__header { + position: relative; grid-column: 1 / -1; } @@ -355,7 +356,7 @@ kbd { display: block; top: 0; right: 0; - margin: 16px; + margin: 0; padding: 8px; border: none; background: url(/static/icon/x.svg) no-repeat 8px 8px / 16px 16px; diff --git a/static/shortcuts.js b/static/shortcuts.js index 54c7146..841ce12 100644 --- a/static/shortcuts.js +++ b/static/shortcuts.js @@ -122,16 +122,46 @@ } } - groupStart(title = null) { - if (title) this.fakeItem(title); + group(...args) { + if (typeof args[0] === 'string') this.fakeItem(args.shift()); shortcutsGroup = []; - } - groupEnd() { + args[0].bind(this)(); + if (shortcutsGroup && shortcutsGroup.length) allShortcuts.push(shortcutsGroup); shortcutsGroup = null; } + bindElement(shortcut, element, ...other) { + element = typeof element === 'string' ? $(element) : element; + if (!element) return; + this.add(shortcut, () => { + if (isTextField(element)) { + element.focus(); + } else { + element.click(); + } + }, ...other); + } + + bindLink(shortcut, link, ...other) { + this.add(shortcut, () => window.location.href = link, ...other); + } + + bindCollection(prefix, elements, collectionDescription, itemDescription) { + this.fakeItem(prefix + ' 1 – 9', collectionDescription); + + if (typeof elements === 'string') { + elements = $$(elements); + } else if (Array.isArray(elements)) { + elements = elements.map(el => typeof el === 'string' ? $(el) : el); + } + + for (let i = 1; i <= elements.length && i < 10; i++) { + this.bindElement(`${prefix} ${i}`, elements[i-1], `${itemDescription} #${i}`, false); + } + } + fakeItem(shortcut, description = null) { let list = shortcutsGroup || allShortcuts; list.push({ @@ -154,6 +184,7 @@ this.active = this.active[shortcut]; if (this.active.action) { + event.stopPropagation(); this.active.action(event); if (this.override) event.preventDefault(); this.resetActive(); @@ -173,61 +204,28 @@ } } - function bindElementFactory(handler) { - return (shortcut, element, ...other) => { - element = typeof element === 'string' ? $(element) : element; - if (!element) return; - handler.add(shortcut, () => { - if (isTextField(element)) { - element.focus(); - } else { - element.click(); - } - }, ...other); - }; - } - - function bindLinkFactory(handler) { - return (shortcut, link, ...other) => handler.add(shortcut, () => window.location.href = link, ...other); - } - - function bindCollectionFactory(handler) { - return (prefix, elements, collectionDescription, itemDescription) => { - handler.fakeItem(prefix + ' 1 – 9', collectionDescription); - - if (typeof elements === 'string') { - elements = $$(elements); - } else if (Array.isArray(elements)) { - elements = elements.map(el => typeof el === 'string' ? $(el) : el); - } - - for (let i = 1; i <= elements.length && i < 10; i++) { - bindElementFactory(handler)(`${prefix} ${i}`, elements[i-1], `${itemDescription} #${i}`, false); - } - } - } - class ShortcutsHelpDialog { constructor() { let template = $('#dialog-template'); - this.wrap = template.content.firstElementChild.cloneNode(true); - this.wrap.classList.add('shortcuts-help'); - this.wrap.hidden = true; + let clonedTemplate = template.content.cloneNode(true); + this.backdrop = clonedTemplate.children[0]; + this.dialog = clonedTemplate.children[1]; - let handleClose = (event) => { - event.preventDefault(); - event.stopPropagation(); - this.close(); - }; + this.dialog.classList.add('shortcuts-help'); + this.dialog.hidden = true; + this.backdrop.hidden = true; - this.shortcuts = new ShortcutHandler(this.wrap, false); - this.shortcuts.add('Escape', handleClose, null, false); + document.body.appendChild(this.backdrop); + document.body.appendChild(this.dialog); - this.wrap.querySelector('.dialog__title').textContent = 'List of shortcuts'; - this.wrap.querySelector('.dialog__close-button').addEventListener('click', handleClose); + this.close = this.close.bind(this); - this.wrap.addEventListener('click', handleClose); - this.wrap.querySelector('.dialog').addEventListener('click', event => event.stopPropagation()); + this.dialog.querySelector('.dialog__title').textContent = 'List of shortcuts'; + this.dialog.querySelector('.dialog__close-button').addEventListener('click', this.close); + this.backdrop.addEventListener('click', this.close); + + this.shortcuts = new ShortcutHandler(this.dialog, false); + this.shortcuts.add('Escape', this.close, null, false); let shortcutsGroup; let shortcutsGroupTemplate = document.createElement('div'); @@ -236,7 +234,7 @@ for (let item of allShortcuts) { if (item.description && !item.shortcut) { shortcutsGroup = shortcutsGroupTemplate.cloneNode(); - this.wrap.querySelector('.dialog__content').appendChild(shortcutsGroup); + this.dialog.querySelector('.dialog__content').appendChild(shortcutsGroup); let heading = document.createElement('h2'); heading.className = 'shortcuts-group-heading'; @@ -268,21 +266,21 @@ shortcutsGroup.appendChild(list); } } - - document.body.appendChild(this.wrap); } open() { this.prevActiveElement = document.activeElement; document.body.overflow = 'hidden'; - this.wrap.hidden = false; - this.wrap.children[0].focus(); + this.backdrop.hidden = false; + this.dialog.hidden = false; + this.dialog.focus(); } close() { document.body.overflow = ''; - this.wrap.hidden = true; + this.backdrop.hidden = true; + this.dialog.hidden = true; if (this.prevActiveElement) { this.prevActiveElement.focus(); @@ -300,39 +298,35 @@ // Global shortcuts work everywhere. let globalShortcuts = new ShortcutHandler(document, false); - globalShortcuts.add('?, ' + (isMac ? 'Meta+/' : 'Ctrl+/'), openShortcutsReference); + globalShortcuts.add('?, ' + (isMac ? 'Meta+/' : 'Ctrl+/'), openHelp); - // Common shortcuts work everywhere except on text fields. - let commonShortcuts = new ShortcutHandler(document, false, notTextField); - - let bindElement = bindElementFactory(commonShortcuts); - let bindLink = bindLinkFactory(commonShortcuts); - let bindCollection = bindCollectionFactory(commonShortcuts); + // Page shortcuts work everywhere except on text fields. + let pageShortcuts = new ShortcutHandler(document, false, notTextField); + pageShortcuts.add('?', openHelp, null, false); // Common shortcuts - commonShortcuts.groupStart('Common'); - bindCollection('g', '.header-links__link', 'First 9 header links', 'Header link'); - bindLink('g h', '/', 'Home'); - bindLink('g l', '/list/', 'List of hyphae'); - bindLink('g r', '/recent-changes/', 'Recent changes'); - bindElement('g u', '.header-links__entry_user .header-links__link', 'Your profile′s hypha'); - commonShortcuts.groupEnd(); + pageShortcuts.group('Common', function () { + this.bindCollection('g', '.header-links__link', 'First 9 header links', 'Header link'); + this.bindLink('g h', '/', 'Home'); + this.bindLink('g l', '/list/', 'List of hyphae'); + this.bindLink('g r', '/recent-changes/', 'Recent changes'); + this.bindElement('g u', '.header-links__entry_user .header-links__link', 'Your profile′s hypha'); + }); if (typeof editTextarea === 'undefined') { // Hypha shortcuts - commonShortcuts.groupStart('Hypha'); - bindCollection('', 'article .wikilink', 'First 9 hypha′s links', 'Hypha link'); - bindElement('p, Alt+ArrowLeft, Ctrl+Alt+ArrowLeft', '.prevnext__prev', 'Next hypha'); - bindElement('n, Alt+ArrowRight, Ctrl+Alt+ArrowRight', '.prevnext__next', 'Previous hypha'); - bindElement('s, Alt+ArrowUp, Ctrl+Alt+ArrowUp', $$('.navi-title a').slice(1, -1).slice(-1)[0], 'Parent hypha'); - bindElement('c, Alt+ArrowDown, Ctrl+Alt+ArrowDown', '.subhyphae__link', 'First child hypha'); - bindElement('e, Ctrl+Enter', '.hypha-tabs__link[href^="/edit/"]', 'Edit this hypha'); - commonShortcuts.groupEnd(); + pageShortcuts.group('Hypha', function () { + this.bindCollection('', 'article .wikilink', 'First 9 hypha′s links', 'Hypha link'); + this.bindElement('p, Alt+ArrowLeft, Ctrl+Alt+ArrowLeft', '.prevnext__prev', 'Next hypha'); + this.bindElement('n, Alt+ArrowRight, Ctrl+Alt+ArrowRight', '.prevnext__next', 'Previous hypha'); + this.bindElement('s, Alt+ArrowUp, Ctrl+Alt+ArrowUp', $$('.navi-title a').slice(1, -1).slice(-1)[0], 'Parent hypha'); + this.bindElement('c, Alt+ArrowDown, Ctrl+Alt+ArrowDown', '.subhyphae__link', 'First child hypha'); + this.bindElement('e, Ctrl+Enter', '.hypha-tabs__link[href^="/edit/"]', 'Edit this hypha'); + }); } else { // Hypha editor shortcuts. These work only on editor's text area. let editorShortcuts = new ShortcutHandler(editTextarea, true); - let bindElement = bindElementFactory(editorShortcuts); let shortcuts = [ // Win+Linux Mac Action Description @@ -346,19 +340,19 @@ ['Ctrl+k', 'Meta+k', wrapLink, 'Format: Link'], ]; - editorShortcuts.groupStart('Editor'); - for (let shortcut of shortcuts) { - if (isMac) { - editorShortcuts.add(shortcut[1], ...shortcut.slice(2)) - } else { - editorShortcuts.add(shortcut[0], ...shortcut.slice(2)) + editorShortcuts.group('Editor', function () { + for (let shortcut of shortcuts) { + if (isMac) { + this.add(shortcut[1], ...shortcut.slice(2)) + } else { + this.add(shortcut[0], ...shortcut.slice(2)) + } } - } - editorShortcuts.groupEnd(); + }); - editorShortcuts.groupStart(); - bindElement(isMac ? 'Meta+Enter' : 'Ctrl+Enter', $('.edit-form__save'), 'Save changes'); - editorShortcuts.groupEnd(); + editorShortcuts.group(function () { + this.bindElement(isMac ? 'Meta+Enter' : 'Ctrl+Enter', $('.edit-form__save'), 'Save changes'); + }); } }); })(); diff --git a/views/stuff.qtpl b/views/stuff.qtpl index 7a27a98..e1fe2d1 100644 --- a/views/stuff.qtpl +++ b/views/stuff.qtpl @@ -29,15 +29,14 @@ {%s= body %} {%= omnipresentScripts() %} diff --git a/views/stuff.qtpl.go b/views/stuff.qtpl.go index 054aab3..14309cc 100644 --- a/views/stuff.qtpl.go +++ b/views/stuff.qtpl.go @@ -94,63 +94,62 @@ func StreamBaseHTML(qw422016 *qt422016.Writer, title, body string, u *user.User, //line views/stuff.qtpl:30 qw422016.N().S(` `) -//line views/stuff.qtpl:43 +//line views/stuff.qtpl:42 streamomnipresentScripts(qw422016) -//line views/stuff.qtpl:43 +//line views/stuff.qtpl:42 qw422016.N().S(` `) -//line views/stuff.qtpl:46 +//line views/stuff.qtpl:45 } -//line views/stuff.qtpl:46 +//line views/stuff.qtpl:45 func WriteBaseHTML(qq422016 qtio422016.Writer, title, body string, u *user.User, headElements ...string) { -//line views/stuff.qtpl:46 +//line views/stuff.qtpl:45 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/stuff.qtpl:46 +//line views/stuff.qtpl:45 StreamBaseHTML(qw422016, title, body, u, headElements...) -//line views/stuff.qtpl:46 +//line views/stuff.qtpl:45 qt422016.ReleaseWriter(qw422016) -//line views/stuff.qtpl:46 +//line views/stuff.qtpl:45 } -//line views/stuff.qtpl:46 +//line views/stuff.qtpl:45 func BaseHTML(title, body string, u *user.User, headElements ...string) string { -//line views/stuff.qtpl:46 +//line views/stuff.qtpl:45 qb422016 := qt422016.AcquireByteBuffer() -//line views/stuff.qtpl:46 +//line views/stuff.qtpl:45 WriteBaseHTML(qb422016, title, body, u, headElements...) -//line views/stuff.qtpl:46 +//line views/stuff.qtpl:45 qs422016 := string(qb422016.B) -//line views/stuff.qtpl:46 +//line views/stuff.qtpl:45 qt422016.ReleaseByteBuffer(qb422016) -//line views/stuff.qtpl:46 +//line views/stuff.qtpl:45 return qs422016 -//line views/stuff.qtpl:46 +//line views/stuff.qtpl:45 } -//line views/stuff.qtpl:48 +//line views/stuff.qtpl:47 func StreamUserListHTML(qw422016 *qt422016.Writer) { -//line views/stuff.qtpl:48 +//line views/stuff.qtpl:47 qw422016.N().S(`

List of users

`) -//line views/stuff.qtpl:53 +//line views/stuff.qtpl:52 var ( admins = make([]string, 0) moderators = make([]string, 0) @@ -167,303 +166,303 @@ func StreamUserListHTML(qw422016 *qt422016.Writer) { } } -//line views/stuff.qtpl:68 +//line views/stuff.qtpl:67 qw422016.N().S(`

Admins

    `) -//line views/stuff.qtpl:71 +//line views/stuff.qtpl:70 for _, name := range admins { -//line views/stuff.qtpl:71 +//line views/stuff.qtpl:70 qw422016.N().S(`
  1. `) -//line views/stuff.qtpl:72 +//line views/stuff.qtpl:71 qw422016.E().S(name) -//line views/stuff.qtpl:72 +//line views/stuff.qtpl:71 qw422016.N().S(`
  2. `) -//line views/stuff.qtpl:73 +//line views/stuff.qtpl:72 } -//line views/stuff.qtpl:73 +//line views/stuff.qtpl:72 qw422016.N().S(`

Moderators

    `) -//line views/stuff.qtpl:77 +//line views/stuff.qtpl:76 for _, name := range moderators { -//line views/stuff.qtpl:77 +//line views/stuff.qtpl:76 qw422016.N().S(`
  1. `) -//line views/stuff.qtpl:78 +//line views/stuff.qtpl:77 qw422016.E().S(name) -//line views/stuff.qtpl:78 +//line views/stuff.qtpl:77 qw422016.N().S(`
  2. `) -//line views/stuff.qtpl:79 +//line views/stuff.qtpl:78 } -//line views/stuff.qtpl:79 +//line views/stuff.qtpl:78 qw422016.N().S(`

Editors

    `) -//line views/stuff.qtpl:83 +//line views/stuff.qtpl:82 for _, name := range editors { -//line views/stuff.qtpl:83 +//line views/stuff.qtpl:82 qw422016.N().S(`
  1. `) -//line views/stuff.qtpl:84 +//line views/stuff.qtpl:83 qw422016.E().S(name) -//line views/stuff.qtpl:84 +//line views/stuff.qtpl:83 qw422016.N().S(`
  2. `) -//line views/stuff.qtpl:85 +//line views/stuff.qtpl:84 } -//line views/stuff.qtpl:85 +//line views/stuff.qtpl:84 qw422016.N().S(`
`) -//line views/stuff.qtpl:89 +//line views/stuff.qtpl:88 } -//line views/stuff.qtpl:89 +//line views/stuff.qtpl:88 func WriteUserListHTML(qq422016 qtio422016.Writer) { -//line views/stuff.qtpl:89 +//line views/stuff.qtpl:88 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/stuff.qtpl:89 +//line views/stuff.qtpl:88 StreamUserListHTML(qw422016) -//line views/stuff.qtpl:89 +//line views/stuff.qtpl:88 qt422016.ReleaseWriter(qw422016) -//line views/stuff.qtpl:89 +//line views/stuff.qtpl:88 } -//line views/stuff.qtpl:89 +//line views/stuff.qtpl:88 func UserListHTML() string { -//line views/stuff.qtpl:89 +//line views/stuff.qtpl:88 qb422016 := qt422016.AcquireByteBuffer() -//line views/stuff.qtpl:89 +//line views/stuff.qtpl:88 WriteUserListHTML(qb422016) -//line views/stuff.qtpl:89 +//line views/stuff.qtpl:88 qs422016 := string(qb422016.B) -//line views/stuff.qtpl:89 +//line views/stuff.qtpl:88 qt422016.ReleaseByteBuffer(qb422016) -//line views/stuff.qtpl:89 +//line views/stuff.qtpl:88 return qs422016 -//line views/stuff.qtpl:89 +//line views/stuff.qtpl:88 } -//line views/stuff.qtpl:91 +//line views/stuff.qtpl:90 func StreamHyphaListHTML(qw422016 *qt422016.Writer) { -//line views/stuff.qtpl:91 +//line views/stuff.qtpl:90 qw422016.N().S(`

List of hyphae

This wiki has `) -//line views/stuff.qtpl:95 +//line views/stuff.qtpl:94 qw422016.N().D(hyphae.Count()) -//line views/stuff.qtpl:95 +//line views/stuff.qtpl:94 qw422016.N().S(` hyphae.

    `) -//line views/stuff.qtpl:97 +//line views/stuff.qtpl:96 for h := range hyphae.YieldExistingHyphae() { -//line views/stuff.qtpl:97 +//line views/stuff.qtpl:96 qw422016.N().S(`
  • `) -//line views/stuff.qtpl:99 +//line views/stuff.qtpl:98 qw422016.E().S(util.BeautifulName(h.Name)) -//line views/stuff.qtpl:99 +//line views/stuff.qtpl:98 qw422016.N().S(` `) -//line views/stuff.qtpl:100 +//line views/stuff.qtpl:99 if h.BinaryPath != "" { -//line views/stuff.qtpl:100 +//line views/stuff.qtpl:99 qw422016.N().S(` `) -//line views/stuff.qtpl:101 +//line views/stuff.qtpl:100 qw422016.E().S(filepath.Ext(h.BinaryPath)[1:]) -//line views/stuff.qtpl:101 +//line views/stuff.qtpl:100 qw422016.N().S(` `) -//line views/stuff.qtpl:102 +//line views/stuff.qtpl:101 } -//line views/stuff.qtpl:102 +//line views/stuff.qtpl:101 qw422016.N().S(`
  • `) -//line views/stuff.qtpl:104 +//line views/stuff.qtpl:103 } -//line views/stuff.qtpl:104 +//line views/stuff.qtpl:103 qw422016.N().S(`
`) -//line views/stuff.qtpl:108 +//line views/stuff.qtpl:107 } -//line views/stuff.qtpl:108 +//line views/stuff.qtpl:107 func WriteHyphaListHTML(qq422016 qtio422016.Writer) { -//line views/stuff.qtpl:108 +//line views/stuff.qtpl:107 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/stuff.qtpl:108 +//line views/stuff.qtpl:107 StreamHyphaListHTML(qw422016) -//line views/stuff.qtpl:108 +//line views/stuff.qtpl:107 qt422016.ReleaseWriter(qw422016) -//line views/stuff.qtpl:108 +//line views/stuff.qtpl:107 } -//line views/stuff.qtpl:108 +//line views/stuff.qtpl:107 func HyphaListHTML() string { -//line views/stuff.qtpl:108 +//line views/stuff.qtpl:107 qb422016 := qt422016.AcquireByteBuffer() -//line views/stuff.qtpl:108 +//line views/stuff.qtpl:107 WriteHyphaListHTML(qb422016) -//line views/stuff.qtpl:108 +//line views/stuff.qtpl:107 qs422016 := string(qb422016.B) -//line views/stuff.qtpl:108 +//line views/stuff.qtpl:107 qt422016.ReleaseByteBuffer(qb422016) -//line views/stuff.qtpl:108 +//line views/stuff.qtpl:107 return qs422016 -//line views/stuff.qtpl:108 +//line views/stuff.qtpl:107 } -//line views/stuff.qtpl:110 +//line views/stuff.qtpl:109 func StreamAboutHTML(qw422016 *qt422016.Writer) { -//line views/stuff.qtpl:110 +//line views/stuff.qtpl:109 qw422016.N().S(`

About `) -//line views/stuff.qtpl:114 +//line views/stuff.qtpl:113 qw422016.E().S(cfg.WikiName) -//line views/stuff.qtpl:114 +//line views/stuff.qtpl:113 qw422016.N().S(`

See /list for information about hyphae on this wiki.

`) -//line views/stuff.qtpl:132 +//line views/stuff.qtpl:131 } -//line views/stuff.qtpl:132 +//line views/stuff.qtpl:131 func WriteAboutHTML(qq422016 qtio422016.Writer) { -//line views/stuff.qtpl:132 +//line views/stuff.qtpl:131 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/stuff.qtpl:132 +//line views/stuff.qtpl:131 StreamAboutHTML(qw422016) -//line views/stuff.qtpl:132 +//line views/stuff.qtpl:131 qt422016.ReleaseWriter(qw422016) -//line views/stuff.qtpl:132 +//line views/stuff.qtpl:131 } -//line views/stuff.qtpl:132 +//line views/stuff.qtpl:131 func AboutHTML() string { -//line views/stuff.qtpl:132 +//line views/stuff.qtpl:131 qb422016 := qt422016.AcquireByteBuffer() -//line views/stuff.qtpl:132 +//line views/stuff.qtpl:131 WriteAboutHTML(qb422016) -//line views/stuff.qtpl:132 +//line views/stuff.qtpl:131 qs422016 := string(qb422016.B) -//line views/stuff.qtpl:132 +//line views/stuff.qtpl:131 qt422016.ReleaseByteBuffer(qb422016) -//line views/stuff.qtpl:132 +//line views/stuff.qtpl:131 return qs422016 -//line views/stuff.qtpl:132 +//line views/stuff.qtpl:131 } -//line views/stuff.qtpl:134 +//line views/stuff.qtpl:133 func StreamAdminPanelHTML(qw422016 *qt422016.Writer) { -//line views/stuff.qtpl:134 +//line views/stuff.qtpl:133 qw422016.N().S(`
@@ -500,80 +499,80 @@ func StreamAdminPanelHTML(qw422016 *qt422016.Writer) {
`) -//line views/stuff.qtpl:169 +//line views/stuff.qtpl:168 } -//line views/stuff.qtpl:169 +//line views/stuff.qtpl:168 func WriteAdminPanelHTML(qq422016 qtio422016.Writer) { -//line views/stuff.qtpl:169 +//line views/stuff.qtpl:168 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/stuff.qtpl:169 +//line views/stuff.qtpl:168 StreamAdminPanelHTML(qw422016) -//line views/stuff.qtpl:169 +//line views/stuff.qtpl:168 qt422016.ReleaseWriter(qw422016) -//line views/stuff.qtpl:169 +//line views/stuff.qtpl:168 } -//line views/stuff.qtpl:169 +//line views/stuff.qtpl:168 func AdminPanelHTML() string { -//line views/stuff.qtpl:169 +//line views/stuff.qtpl:168 qb422016 := qt422016.AcquireByteBuffer() -//line views/stuff.qtpl:169 +//line views/stuff.qtpl:168 WriteAdminPanelHTML(qb422016) -//line views/stuff.qtpl:169 +//line views/stuff.qtpl:168 qs422016 := string(qb422016.B) -//line views/stuff.qtpl:169 +//line views/stuff.qtpl:168 qt422016.ReleaseByteBuffer(qb422016) -//line views/stuff.qtpl:169 +//line views/stuff.qtpl:168 return qs422016 -//line views/stuff.qtpl:169 +//line views/stuff.qtpl:168 } -//line views/stuff.qtpl:171 +//line views/stuff.qtpl:170 func streamomnipresentScripts(qw422016 *qt422016.Writer) { -//line views/stuff.qtpl:171 +//line views/stuff.qtpl:170 qw422016.N().S(` `) -//line views/stuff.qtpl:172 +//line views/stuff.qtpl:171 for _, scriptPath := range cfg.OmnipresentScripts { -//line views/stuff.qtpl:172 +//line views/stuff.qtpl:171 qw422016.N().S(` `) -//line views/stuff.qtpl:174 +//line views/stuff.qtpl:173 } -//line views/stuff.qtpl:174 +//line views/stuff.qtpl:173 qw422016.N().S(` `) -//line views/stuff.qtpl:175 +//line views/stuff.qtpl:174 } -//line views/stuff.qtpl:175 +//line views/stuff.qtpl:174 func writeomnipresentScripts(qq422016 qtio422016.Writer) { -//line views/stuff.qtpl:175 +//line views/stuff.qtpl:174 qw422016 := qt422016.AcquireWriter(qq422016) -//line views/stuff.qtpl:175 +//line views/stuff.qtpl:174 streamomnipresentScripts(qw422016) -//line views/stuff.qtpl:175 +//line views/stuff.qtpl:174 qt422016.ReleaseWriter(qw422016) -//line views/stuff.qtpl:175 +//line views/stuff.qtpl:174 } -//line views/stuff.qtpl:175 +//line views/stuff.qtpl:174 func omnipresentScripts() string { -//line views/stuff.qtpl:175 +//line views/stuff.qtpl:174 qb422016 := qt422016.AcquireByteBuffer() -//line views/stuff.qtpl:175 +//line views/stuff.qtpl:174 writeomnipresentScripts(qb422016) -//line views/stuff.qtpl:175 +//line views/stuff.qtpl:174 qs422016 := string(qb422016.B) -//line views/stuff.qtpl:175 +//line views/stuff.qtpl:174 qt422016.ReleaseByteBuffer(qb422016) -//line views/stuff.qtpl:175 +//line views/stuff.qtpl:174 return qs422016 -//line views/stuff.qtpl:175 +//line views/stuff.qtpl:174 } From 4c471c579d8fe8246a7ac128496c5950fd110eb5 Mon Sep 17 00:00:00 2001 From: handlerug Date: Mon, 14 Jun 2021 14:03:31 +0700 Subject: [PATCH 10/12] Revert shortcuts for super/subscript back for Macs --- static/shortcuts.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/static/shortcuts.js b/static/shortcuts.js index 841ce12..eab052c 100644 --- a/static/shortcuts.js +++ b/static/shortcuts.js @@ -334,8 +334,8 @@ ['Ctrl+i', 'Meta+i', wrapItalic, 'Format: Italic'], ['Ctrl+M', 'Meta+Shift+m', wrapMonospace, 'Format: Monospaced'], ['Ctrl+I', 'Meta+Shift+i', wrapHighlighted, 'Format: Highlight'], - ['Ctrl+.', 'Meta+Shift+.', wrapLifted, 'Format: Superscript'], - ['Ctrl+Comma', 'Meta+Shift+Comma', wrapLowered, 'Format: Subscript'], + ['Ctrl+.', 'Meta+.', wrapLifted, 'Format: Superscript'], + ['Ctrl+Comma', 'Meta+Comma', wrapLowered, 'Format: Subscript'], ['Ctrl+X', 'Meta+Shift+x', wrapStrikethrough, 'Format: Strikethrough'], ['Ctrl+k', 'Meta+k', wrapLink, 'Format: Link'], ]; From 9dde11aa409a8cba59168cb68dcf279e51972202 Mon Sep 17 00:00:00 2001 From: handlerug Date: Mon, 14 Jun 2021 14:11:33 +0700 Subject: [PATCH 11/12] Shortcuts for hypha tabs --- static/shortcuts.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/static/shortcuts.js b/static/shortcuts.js index eab052c..4eaedcd 100644 --- a/static/shortcuts.js +++ b/static/shortcuts.js @@ -296,6 +296,8 @@ helpDialog.open(); }; + let onEditPage = typeof editTextarea !== 'undefined'; + // Global shortcuts work everywhere. let globalShortcuts = new ShortcutHandler(document, false); globalShortcuts.add('?, ' + (isMac ? 'Meta+/' : 'Ctrl+/'), openHelp); @@ -313,7 +315,7 @@ this.bindElement('g u', '.header-links__entry_user .header-links__link', 'Your profile′s hypha'); }); - if (typeof editTextarea === 'undefined') { + if (!onEditPage) { // Hypha shortcuts pageShortcuts.group('Hypha', function () { this.bindCollection('', 'article .wikilink', 'First 9 hypha′s links', 'Hypha link'); @@ -321,7 +323,12 @@ this.bindElement('n, Alt+ArrowRight, Ctrl+Alt+ArrowRight', '.prevnext__next', 'Previous hypha'); this.bindElement('s, Alt+ArrowUp, Ctrl+Alt+ArrowUp', $$('.navi-title a').slice(1, -1).slice(-1)[0], 'Parent hypha'); this.bindElement('c, Alt+ArrowDown, Ctrl+Alt+ArrowDown', '.subhyphae__link', 'First child hypha'); + + this.bindElement('v', '.hypha-tabs__link[href^="/hypha/"]', 'Go to hypha′s page'); this.bindElement('e, Ctrl+Enter', '.hypha-tabs__link[href^="/edit/"]', 'Edit this hypha'); + this.bindElement('a', '.hypha-tabs__link[href^="/attachment/"]', 'Go to attachment'); + this.bindElement('h', '.hypha-tabs__link[href^="/history/"]', 'Go to history'); + this.bindElement('r', '.hypha-tabs__link[href^="/rename-ask/"]', 'Rename this hypha'); }); } else { From eefa797097c8785f93659f935aa6d2251b67d83e Mon Sep 17 00:00:00 2001 From: handlerug Date: Mon, 14 Jun 2021 14:13:29 +0700 Subject: [PATCH 12/12] Replace /page/ with /hypha/ everywhere --- history/information.go | 2 +- views/mutators.qtpl | 4 ++-- views/mutators.qtpl.go | 4 ++-- views/nav.qtpl | 2 +- views/nav.qtpl.go | 2 +- views/readers.qtpl | 2 +- views/readers.qtpl.go | 2 +- views/stuff.qtpl | 8 ++++---- views/stuff.qtpl.go | 8 ++++---- web/web.go | 2 +- 10 files changed, 18 insertions(+), 18 deletions(-) diff --git a/history/information.go b/history/information.go index 5c39cbf..3d8342e 100644 --- a/history/information.go +++ b/history/information.go @@ -141,7 +141,7 @@ func (rev *Revision) asHistoryEntry(hyphaName string) (html string) { author := "" if rev.Username != "anon" { author = fmt.Sprintf(` -
  • Cancel + Cancel {%s= Toolbar(user.FromRequest(rq)) %} @@ -100,7 +100,7 @@
    - Cancel + Cancel

    Note that the hypha is not saved yet. You can preview the changes ↓

    {%s= renderedPage %}
    diff --git a/views/mutators.qtpl.go b/views/mutators.qtpl.go index ade7926..7664ce6 100644 --- a/views/mutators.qtpl.go +++ b/views/mutators.qtpl.go @@ -207,7 +207,7 @@ func StreamEditHTML(qw422016 *qt422016.Writer, rq *http.Request, hyphaName, text
    - -
    diff --git a/views/readers.qtpl.go b/views/readers.qtpl.go index fd58941..ef8d7d1 100644 --- a/views/readers.qtpl.go +++ b/views/readers.qtpl.go @@ -241,7 +241,7 @@ func StreamHyphaHTML(qw422016 *qt422016.Writer, rq *http.Request, h *hyphae.Hyph qw422016.N().S(` `) //line views/readers.qtpl:83 - StreamNavHTML(qw422016, rq, h.Name, "page") + StreamNavHTML(qw422016, rq, h.Name, "hypha") //line views/readers.qtpl:83 qw422016.N().S(`
    @@ -119,7 +119,7 @@ for u := range user.YieldUsers() {
  • Administrators: {%- for i, username := range user.ListUsersWithGroup("admin") -%} {%- if i > 0 -%} {%- endif -%} - {%s username %}{%- endfor -%}
  • + {%s username %}{%- endfor -%} {%- else -%}
  • This wiki does not use authorization
  • {%- endif -%} diff --git a/views/stuff.qtpl.go b/views/stuff.qtpl.go index 14309cc..3696e10 100644 --- a/views/stuff.qtpl.go +++ b/views/stuff.qtpl.go @@ -175,7 +175,7 @@ func StreamUserListHTML(qw422016 *qt422016.Writer) { for _, name := range admins { //line views/stuff.qtpl:70 qw422016.N().S(` -
  • %s. Go back to the hypha.

    `, + `

    %s. Go back to the hypha.

    `, errMsg, name, ),