]> BookStack Code Mirror - bookstack/commitdiff
Added shortcut input controls to make custom shortcuts work
authorDan Brown <redacted>
Wed, 9 Nov 2022 14:40:44 +0000 (14:40 +0000)
committerDan Brown <redacted>
Wed, 9 Nov 2022 14:40:44 +0000 (14:40 +0000)
app/Http/Controllers/UserPreferencesController.php
resources/js/components/index.js
resources/js/components/shortcut-input.js [new file with mode: 0644]
resources/js/components/shortcuts.js
resources/views/users/preferences/parts/shortcut-control.blade.php
resources/views/users/preferences/shortcuts.blade.php

index b8bb31468fef948e8d26bb37573465836d746e08..c4718681a8745a696e2e34ba4280db5822a15230 100644 (file)
@@ -35,7 +35,7 @@ class UserPreferencesController extends Controller
     public function updateShortcuts(Request $request)
     {
         $enabled = $request->get('enabled') === 'true';
-        $providedShortcuts = $request->get('shortcuts', []);
+        $providedShortcuts = $request->get('shortcut', []);
         $shortcuts = new UserShortcutMap($providedShortcuts);
 
         setting()->putUser(user(), 'ui-shortcuts', $shortcuts->toJson());
index 6203d0b74662dadbf98ee300d02c9d315905557d..ee282b1fd7b8094debd638e4feb17ac84a2b5fb3 100644 (file)
@@ -44,6 +44,7 @@ import settingAppColorPicker from "./setting-app-color-picker.js"
 import settingColorPicker from "./setting-color-picker.js"
 import shelfSort from "./shelf-sort.js"
 import shortcuts from "./shortcuts";
+import shortcutInput from "./shortcut-input";
 import sidebar from "./sidebar.js"
 import sortableList from "./sortable-list.js"
 import submitOnChange from "./submit-on-change.js"
@@ -103,6 +104,7 @@ const componentMapping = {
     "setting-color-picker": settingColorPicker,
     "shelf-sort": shelfSort,
     "shortcuts": shortcuts,
+    "shortcut-input": shortcutInput,
     "sidebar": sidebar,
     "sortable-list": sortableList,
     "submit-on-change": submitOnChange,
diff --git a/resources/js/components/shortcut-input.js b/resources/js/components/shortcut-input.js
new file mode 100644 (file)
index 0000000..fa13789
--- /dev/null
@@ -0,0 +1,57 @@
+/**
+ * Keys to ignore when recording shortcuts.
+ * @type {string[]}
+ */
+const ignoreKeys = ['Control', 'Alt', 'Shift', 'Meta', 'Super', ' ', '+', 'Tab', 'Escape'];
+
+/**
+ * @extends {Component}
+ */
+class ShortcutInput {
+
+    setup() {
+        this.input = this.$el;
+
+        this.setupListeners();
+    }
+
+    setupListeners() {
+        this.listenerRecordKey = this.listenerRecordKey.bind(this);
+
+        this.input.addEventListener('focus', () => {
+             this.startListeningForInput();
+        });
+
+        this.input.addEventListener('blur', () => {
+            this.stopListeningForInput();
+        })
+    }
+
+    startListeningForInput() {
+        this.input.addEventListener('keydown', this.listenerRecordKey)
+    }
+
+    /**
+     * @param {KeyboardEvent} event
+     */
+    listenerRecordKey(event) {
+        if (ignoreKeys.includes(event.key)) {
+            return;
+        }
+
+        const keys = [
+            event.ctrlKey ? 'Ctrl' : '',
+            event.metaKey ? 'Cmd' : '',
+            event.key,
+        ];
+
+        this.input.value = keys.filter(s => Boolean(s)).join(' + ');
+    }
+
+    stopListeningForInput() {
+        this.input.removeEventListener('keydown', this.listenerRecordKey);
+    }
+
+}
+
+export default ShortcutInput;
\ No newline at end of file
index ccad00f5d86e3ecc8ea7fdfd656f19e7c1e5cc87..cec8684c80f5b4ccc297fa2e34e3541326c4b15e 100644 (file)
@@ -30,13 +30,7 @@ class Shortcuts {
                 return;
             }
 
-            const shortcutId = this.mapByShortcut[event.key];
-            if (shortcutId) {
-                const wasHandled = this.runShortcut(shortcutId);
-                if (wasHandled) {
-                    event.preventDefault();
-                }
-            }
+            this.handleShortcutPress(event);
         });
 
         window.addEventListener('keydown', event => {
@@ -46,6 +40,28 @@ class Shortcuts {
         });
     }
 
+    /**
+     * @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();
+            }
+        }
+    }
+
     /**
      * Run the given shortcut, and return a boolean to indicate if the event
      * was successfully handled by a shortcut action.
index 47fec3a5e24437a073e469809391838c06708f1f..b85813ce04abb80954657a1ddb4085ef057613c9 100644 (file)
@@ -1,7 +1,8 @@
 <div class="flex-container-row justify-space-between items-center gap-m item-list-row">
-    <label for="shortcut-{{ $label }}" class="bold flex px-m py-xs">{{ $label }}</label>
+    <label for="shortcut-{{ $id }}" class="bold flex px-m py-xs">{{ $label }}</label>
     <div class="px-m py-xs">
         <input type="text"
+               component="shortcut-input"
                class="small flex-none shortcut-input px-s py-xs"
                id="shortcut-{{ $id }}"
                name="shortcut[{{ $id }}]"
index 9bb8e81759738a73924ee0ae53aaf05d7e6d93e9..61c61dcf99e1c5b404f5f415331f12674f52eee3 100644 (file)
                 <div class="flex-container-row items-center gap-m wrap mb-m">
                     <p class="flex mb-none min-width-m text-small text-muted">
                         Here you can enable or disable keyboard system interface shortcuts, used for navigation
-                        and actions. You can customize each of the shortcuts below.
+                        and actions.
+
+                        You can customize each of the shortcuts below. Just press your desired key combination
+                        after selecting the input for a shortcut.
                     </p>
-                    <div class="flex min-width-m text-m-right">
+                    <div class="flex min-width-m text-m-center">
                         @include('form.toggle-switch', [
                             'name' => 'enabled',
                             'value' => $enabled,