X-Git-Url: http://source.bookstackapp.com/bookstack/blobdiff_plain/1fc994177f92ade173d43c30be735cf11cb40f88..refs/heads/development:/resources/js/components/shortcuts.js diff --git a/resources/js/components/shortcuts.js b/resources/js/components/shortcuts.js index a3cca5ddc..8bf26fbb5 100644 --- a/resources/js/components/shortcuts.js +++ b/resources/js/components/shortcuts.js @@ -1,34 +1,4 @@ -/** - * The default mapping of unique id to shortcut key. - * @type {Object} - */ -const defaultMap = { - // Header actions - "home": "1", - "shelves_view": "2", - "books_view": "3", - "settings_view": "4", - "favorites_view": "5", - "profile_view": "6", - "global_search": "/", - "logout": "0", - - // Generic actions - "edit": "e", - "new": "n", - "copy": "c", - "delete": "d", - "favorite": "f", - "export": "x", - "sort": "s", - "permissions": "p", - "move": "m", - "revisions": "r", - - // Navigation - "next": "ArrowRight", - "prev": "ArrowLeft", -}; +import {Component} from './component'; function reverseMap(map) { const reversed = {}; @@ -38,46 +8,59 @@ function reverseMap(map) { return reversed; } -/** - * @extends {Component} - */ -class Shortcuts { +export class Shortcuts extends Component { setup() { this.container = this.$el; - this.mapById = defaultMap; + this.mapById = JSON.parse(this.$opts.keyMap); this.mapByShortcut = reverseMap(this.mapById); this.hintsShowing = false; this.hideHints = this.hideHints.bind(this); - // TODO - Allow custom key maps - // TODO - Allow turning off shortcuts + this.hintAbortController = null; this.setupListeners(); } setupListeners() { window.addEventListener('keydown', event => { - - if (event.target.closest('input, select, textarea')) { + if (event.target.closest('input, select, textarea, .cm-editor, .editor-container')) { return; } - const shortcutId = this.mapByShortcut[event.key]; - if (shortcutId) { - const wasHandled = this.runShortcut(shortcutId); - if (wasHandled) { - event.preventDefault(); + if (event.key === '?') { + if (this.hintsShowing) { + this.hideHints(); + } else { + this.showHints(); } + return; } + + this.handleShortcutPress(event); }); + } - window.addEventListener('keydown', event => { - if (event.key === '?') { - this.hintsShowing ? this.hideHints() : this.showHints(); + /** + * @param {KeyboardEvent} event + */ + handleShortcutPress(event) { + const keys = [ + event.ctrlKey ? 'Ctrl' : '', + event.metaKey ? 'Cmd' : '', + event.key, + ]; + + const combo = keys.filter(s => Boolean(s)).join(' + '); + + const shortcutId = this.mapByShortcut[combo]; + if (shortcutId) { + const wasHandled = this.runShortcut(shortcutId); + if (wasHandled) { + event.preventDefault(); } - }); + } } /** @@ -88,7 +71,6 @@ class Shortcuts { */ runShortcut(id) { const el = this.container.querySelector(`[data-shortcut="${id}"]`); - console.info('Shortcut run', el); if (!el) { return false; } @@ -109,7 +91,7 @@ class Shortcuts { return true; } - console.error(`Shortcut attempted to be ran for element type that does not have handling setup`, el); + console.error('Shortcut attempted to be ran for element type that does not have handling setup', el); return false; } @@ -132,10 +114,12 @@ class Shortcuts { displayedIds.add(id); } - window.addEventListener('scroll', this.hideHints); - window.addEventListener('focus', this.hideHints); - window.addEventListener('blur', this.hideHints); - window.addEventListener('click', this.hideHints); + this.hintAbortController = new AbortController(); + const signal = this.hintAbortController.signal; + window.addEventListener('scroll', this.hideHints, {signal}); + window.addEventListener('focus', this.hideHints, {signal}); + window.addEventListener('blur', this.hideHints, {signal}); + window.addEventListener('click', this.hideHints, {signal}); this.hintsShowing = true; } @@ -154,10 +138,10 @@ class Shortcuts { const linkage = document.createElement('div'); linkage.classList.add('shortcut-linkage'); - linkage.style.left = targetBounds.x + 'px'; - linkage.style.top = targetBounds.y + 'px'; - linkage.style.width = targetBounds.width + 'px'; - linkage.style.height = targetBounds.height + 'px'; + linkage.style.left = `${targetBounds.x}px`; + linkage.style.top = `${targetBounds.y}px`; + linkage.style.width = `${targetBounds.width}px`; + linkage.style.height = `${targetBounds.height}px`; wrapper.append(label, linkage); @@ -170,14 +154,8 @@ class Shortcuts { hideHints() { const wrapper = this.container.querySelector('.shortcut-container'); wrapper.remove(); - - window.removeEventListener('scroll', this.hideHints); - window.removeEventListener('focus', this.hideHints); - window.removeEventListener('blur', this.hideHints); - window.removeEventListener('click', this.hideHints); - + this.hintAbortController?.abort(); this.hintsShowing = false; } -} -export default Shortcuts; \ No newline at end of file +}