From 1d2b6dbb01b6c8c3f4efec914e9782c2c4dd975b Mon Sep 17 00:00:00 2001 From: Isaac Janzen <50783505+janzenisaac@users.noreply.github.com> Date: Fri, 25 Oct 2024 14:14:04 -0500 Subject: [PATCH] DEV: Add `disableDefaultKeyboardShortcuts` plugin API to disable default keyboard shortcuts (#29401) # Context Add `disableDefaultKeyboardShortcuts` function to the plugin API to allow for disabling [default bindings](https://github.com/discourse/discourse/blob/e4941278b2055285d0e83330732ffb63f285b86e/app/assets/javascripts/discourse/app/lib/keyboard-shortcuts.js#L49). # Details This function is used to disable a "default" keyboard shortcut. You can pass an array of shortcut bindings as strings to disable them. **Please note that this function must be called from a pre-initializer.** Example: ```js api.disableDefaultKeyboardShortcuts(['command+f', 'shift+c']); ``` - Added system spec, displaying intended behavior --- .../discourse/app/lib/keyboard-shortcuts.js | 13 +++++++++ .../discourse/app/lib/plugin-api.gjs | 21 ++++++++++++-- .../discourse/tests/helpers/qunit-helpers.js | 2 ++ docs/CHANGELOG-JAVASCRIPT-PLUGIN-API.md | 5 ++++ spec/system/keyboard_shortcuts_spec.rb | 29 +++++++++++++++++++ 5 files changed, 68 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/discourse/app/lib/keyboard-shortcuts.js b/app/assets/javascripts/discourse/app/lib/keyboard-shortcuts.js index bd3f14c8461..f8cd9280289 100644 --- a/app/assets/javascripts/discourse/app/lib/keyboard-shortcuts.js +++ b/app/assets/javascripts/discourse/app/lib/keyboard-shortcuts.js @@ -13,6 +13,15 @@ import { INPUT_DELAY } from "discourse-common/config/environment"; import discourseLater from "discourse-common/lib/later"; import domUtils from "discourse-common/utils/dom-utils"; +let disabledBindings = []; +export function disableDefaultKeyboardShortcuts(bindings) { + disabledBindings = disabledBindings.concat(bindings); +} + +export function clearDisabledDefaultKeyboardBindings() { + disabledBindings = []; +} + let extraKeyboardShortcutsHelp = {}; function addExtraKeyboardShortcutHelp(help) { const category = help.category; @@ -157,6 +166,10 @@ export default { if (!this.currentUser?.can_send_private_messages) { delete DEFAULT_BINDINGS["g m"]; } + + if (disabledBindings.length) { + disabledBindings.forEach((binding) => delete DEFAULT_BINDINGS[binding]); + } }, bindEvents() { diff --git a/app/assets/javascripts/discourse/app/lib/plugin-api.gjs b/app/assets/javascripts/discourse/app/lib/plugin-api.gjs index fb68689f98a..9b91c2fcce8 100644 --- a/app/assets/javascripts/discourse/app/lib/plugin-api.gjs +++ b/app/assets/javascripts/discourse/app/lib/plugin-api.gjs @@ -3,7 +3,7 @@ // docs/CHANGELOG-JAVASCRIPT-PLUGIN-API.md whenever you change the version // using the format described at https://keepachangelog.com/en/1.0.0/. -export const PLUGIN_API_VERSION = "1.37.2"; +export const PLUGIN_API_VERSION = "1.37.3"; import $ from "jquery"; import { h } from "virtual-dom"; @@ -73,7 +73,9 @@ import { registerHighlightJSLanguage, registerHighlightJSPlugin, } from "discourse/lib/highlight-syntax"; -import KeyboardShortcuts from "discourse/lib/keyboard-shortcuts"; +import KeyboardShortcuts, { + disableDefaultKeyboardShortcuts, +} from "discourse/lib/keyboard-shortcuts"; import { registerModelTransformer } from "discourse/lib/model-transformers"; import { registerNotificationTypeRenderer } from "discourse/lib/notification-types-manager"; import { addGTMPageChangedCallback } from "discourse/lib/page-tracker"; @@ -590,6 +592,21 @@ class PluginApi { KeyboardShortcuts.addShortcut(shortcut, callback, opts); } + /** + * This function is used to disable a "default" keyboard shortcut. You can pass + * an array of shortcut bindings as strings to disable them. + * + * Please note that this function must be called from a pre-initializer. + * + * Example: + * ``` + * api.disableDefaultKeyboardShortcuts(['command+f', 'shift+c']); + * ``` + **/ + disableDefaultKeyboardShortcuts(bindings) { + disableDefaultKeyboardShortcuts(bindings); + } + /** * addPosterIcon(callback) * diff --git a/app/assets/javascripts/discourse/tests/helpers/qunit-helpers.js b/app/assets/javascripts/discourse/tests/helpers/qunit-helpers.js index 6fa80756465..1019af2d4d2 100644 --- a/app/assets/javascripts/discourse/tests/helpers/qunit-helpers.js +++ b/app/assets/javascripts/discourse/tests/helpers/qunit-helpers.js @@ -41,6 +41,7 @@ import { clearPopupMenuOptions } from "discourse/lib/composer/custom-popup-menu- import { clearDesktopNotificationHandlers } from "discourse/lib/desktop-notifications"; import { cleanUpHashtagTypeClasses } from "discourse/lib/hashtag-type-registry"; import { + clearDisabledDefaultKeyboardBindings, clearExtraKeyboardShortcutHelp, PLATFORM_KEY_MODIFIER, } from "discourse/lib/keyboard-shortcuts"; @@ -208,6 +209,7 @@ export function testCleanup(container, app) { resetPostMenuExtraButtons(); resetUserMenuProfileTabItems(); clearExtraKeyboardShortcutHelp(); + clearDisabledDefaultKeyboardBindings(); clearNavItems(); setTopicList(null); _clearSnapshots(); diff --git a/docs/CHANGELOG-JAVASCRIPT-PLUGIN-API.md b/docs/CHANGELOG-JAVASCRIPT-PLUGIN-API.md index b895a5cc099..2efc33b46b7 100644 --- a/docs/CHANGELOG-JAVASCRIPT-PLUGIN-API.md +++ b/docs/CHANGELOG-JAVASCRIPT-PLUGIN-API.md @@ -7,6 +7,11 @@ in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.37.3] - 2024-10-24 + +- Added `disableDefaultKeyboardShortcuts` which allows plugins/TCs to disable default keyboard shortcuts. + + ## [1.37.2] - 2024-10-02 - Fixed comments and text references to Font Awesome 5 in favor of the more generic Font Awesome due to core now having the latest version and no longer needing to specify version 5. diff --git a/spec/system/keyboard_shortcuts_spec.rb b/spec/system/keyboard_shortcuts_spec.rb index 3791817ced3..b3bb56b7a14 100644 --- a/spec/system/keyboard_shortcuts_spec.rb +++ b/spec/system/keyboard_shortcuts_spec.rb @@ -1,6 +1,35 @@ # frozen_string_literal: true RSpec.describe "Keyboard shortcuts", type: :system do + it "can have default keyboard shortcuts disabled by the Plugin API" do + sign_in Fabricate(:admin) + + t = Fabricate(:theme, name: "Theme With Tests") + t.set_field( + target: :extra_js, + type: :js, + name: "discourse/lib/pre-initializers/testing.js", + value: <<~JS, + import { withPluginApi } from "discourse/lib/plugin-api"; + export default { + name: "disable-default-keyboard-shortcuts", + initialize() { + withPluginApi("1.6.0", (api) => { + // disable open shortcut modal + api.disableDefaultKeyboardShortcuts(["?"]) + }) + }, + }; + JS + ) + t.save! + SiteSetting.default_theme_id = t.id + + visit "/" + page.send_keys("?") + expect(page).to have_no_css(".keyboard-shortcuts-modal") + end + describe "" do let(:current_user) { topic.user } let(:topic_page) { PageObjects::Pages::Topic.new }