diff --git a/CHANGELOG.txt b/CHANGELOG.txt
index 073c032e04..5c94606009 100644
--- a/CHANGELOG.txt
+++ b/CHANGELOG.txt
@@ -48,6 +48,7 @@ Changelog
* Fix: Fix timezone handling in the `timesince_last_update` template tag (Matt Westcott)
* Fix: Fix Postgres phrase search to respect the language set in settings (Ihar Marhitych)
* Fix: Retain query parameters when switching between locales in the page chooser (Abdelrahman Hamada, Sage Abdullah)
+ * Fix: Add `w-kbd-scope-value` with support for `global` so that specific keyboard shortcuts (e.g. ctrl+s/cmd+s) trigger consistently even when focused on fields (Neeraj Yetheendran)
* Docs: Add contributing development documentation on how to work with a fork of Wagtail (Nix Asteri, Dan Braghis)
* Docs: Make sure the settings panel is listed in tabbed interface examples (Tibor Leupold)
* Docs: Update content and page names to their US spelling instead of UK spelling (Victoria Poromon)
diff --git a/client/src/controllers/KeyboardController.test.js b/client/src/controllers/KeyboardController.test.js
index acf8d65d1a..93743c3a77 100644
--- a/client/src/controllers/KeyboardController.test.js
+++ b/client/src/controllers/KeyboardController.test.js
@@ -126,4 +126,34 @@ describe('KeyboardController', () => {
expect(buttonClickMock).toHaveBeenCalledTimes(1);
});
});
+
+ describe('keyboard shortcut with scope value', () => {
+ it('should fail when the scope value is not global', async () => {
+ expect(buttonClickMock).not.toHaveBeenCalled();
+
+ await setup(`
+
+
+ `);
+
+ // Simulate keydown while target is text input
+ simulateKey({ key: 'j' }, document.getElementById('input'));
+
+ expect(buttonClickMock).not.toHaveBeenCalled();
+ });
+
+ it('should set the scope value to global when specified', async () => {
+ expect(buttonClickMock).not.toHaveBeenCalled();
+
+ await setup(`
+
+
+ `);
+
+ // Simulate keydown while target is text input
+ simulateKey({ key: 'j' }, document.getElementById('input'));
+
+ expect(buttonClickMock).toHaveBeenCalledTimes(1);
+ });
+ });
});
diff --git a/client/src/controllers/KeyboardController.ts b/client/src/controllers/KeyboardController.ts
index f8c1b8c0ec..660244d78a 100644
--- a/client/src/controllers/KeyboardController.ts
+++ b/client/src/controllers/KeyboardController.ts
@@ -1,6 +1,9 @@
import { Controller } from '@hotwired/stimulus';
import Mousetrap from 'mousetrap';
+// import with side-effect to add global-bind plugin (see https://github.com/ccampbell/mousetrap/tree/master/plugins/global-bind)
+import 'mousetrap/plugins/global-bind/mousetrap-global-bind';
+
/**
* Adds the ability to trigger a button click event using a
* keyboard shortcut declared on the controlled element.
@@ -21,10 +24,15 @@ import Mousetrap from 'mousetrap';
export class KeyboardController extends Controller<
HTMLButtonElement | HTMLAnchorElement
> {
- static values = { key: { default: '', type: String } };
+ static values = {
+ key: { default: '', type: String },
+ scope: { default: '', type: String },
+ };
/** Keyboard shortcut string. */
declare keyValue: string;
+ /** Scope of the keyboard shortcut, defaults to the normal MouseTrap (non-input) scope. */
+ declare scopeValue: '' | 'global';
initialize() {
this.handleKey = this.handleKey.bind(this);
@@ -50,6 +58,10 @@ export class KeyboardController extends Controller<
Mousetrap.unbind(previousKey);
}
- Mousetrap.bind(key, this.handleKey);
+ if (this.scopeValue === 'global') {
+ Mousetrap.bindGlobal(key, this.handleKey);
+ } else {
+ Mousetrap.bind(key, this.handleKey);
+ }
}
}
diff --git a/docs/releases/6.1.md b/docs/releases/6.1.md
index 741e3365cf..05f06531b8 100644
--- a/docs/releases/6.1.md
+++ b/docs/releases/6.1.md
@@ -63,6 +63,7 @@ depth: 1
* Fix timezone handling in the `timesince_last_update` template tag (Matt Westcott)
* Fix Postgres phrase search to respect the language set in settings (Ihar Marhitych)
* Retain query parameters when switching between locales in the page chooser (Abdelrahman Hamada, Sage Abdullah)
+ * Add `w-kbd-scope-value` with support for `global` so that specific keyboard shortcuts (e.g. ctrl+s/cmd+s) trigger consistently even when focused on fields (Neeraj Yetheendran)
### Documentation
diff --git a/wagtail/admin/templates/wagtailadmin/pages/action_menu/save_draft.html b/wagtail/admin/templates/wagtailadmin/pages/action_menu/save_draft.html
index 71971053a1..b3708b2621 100644
--- a/wagtail/admin/templates/wagtailadmin/pages/action_menu/save_draft.html
+++ b/wagtail/admin/templates/wagtailadmin/pages/action_menu/save_draft.html
@@ -5,6 +5,7 @@
data-controller="w-progress w-kbd"
data-action="w-progress#activate"
data-w-kbd-key-value="mod+s"
+ data-w-kbd-scope-value="global"
data-w-progress-active-value="{% trans 'Saving…' %}"
>
{% icon name="draft" classname="button-longrunning__icon" %}
diff --git a/wagtail/admin/templates/wagtailadmin/panels/publishing/schedule_publishing_panel.html b/wagtail/admin/templates/wagtailadmin/panels/publishing/schedule_publishing_panel.html
index 52ed732c9e..ad0f7f860f 100644
--- a/wagtail/admin/templates/wagtailadmin/panels/publishing/schedule_publishing_panel.html
+++ b/wagtail/admin/templates/wagtailadmin/panels/publishing/schedule_publishing_panel.html
@@ -24,6 +24,7 @@
data-controller="w-progress w-kbd"
data-action="w-progress#activate"
data-w-kbd-key-value="mod+s"
+ data-w-kbd-scope-value="global"
data-w-progress-active-value="{% trans 'Saving…' %}"
>
{% trans 'Save schedule' %}
diff --git a/wagtail/admin/templates/wagtailadmin/shared/side_panel_toggle.html b/wagtail/admin/templates/wagtailadmin/shared/side_panel_toggle.html
index 061ef9e453..842ff8f59b 100644
--- a/wagtail/admin/templates/wagtailadmin/shared/side_panel_toggle.html
+++ b/wagtail/admin/templates/wagtailadmin/shared/side_panel_toggle.html
@@ -6,7 +6,7 @@
aria-expanded="false"
data-controller="w-tooltip{% if toggle.keyboard_shortcut %} w-kbd{% endif %}"
data-side-panel-toggle="{{ panel.name }}"
- {% if toggle.keyboard_shortcut %}data-w-kbd-key-value="{{ toggle.keyboard_shortcut }}"{% endif %}
+ {% if toggle.keyboard_shortcut %}data-w-kbd-key-value="{{ toggle.keyboard_shortcut }}" data-w-kbd-scope-value="global"{% endif %}
data-w-tooltip-content-value="{{ panel.title }}"
data-w-tooltip-offset-value="[0, 0]"
>
diff --git a/wagtail/admin/templates/wagtailadmin/workflows/create.html b/wagtail/admin/templates/wagtailadmin/workflows/create.html
index 1aa2a0680a..b7286d8e22 100644
--- a/wagtail/admin/templates/wagtailadmin/workflows/create.html
+++ b/wagtail/admin/templates/wagtailadmin/workflows/create.html
@@ -29,6 +29,7 @@
data-controller="w-progress w-kbd"
data-action="w-progress#activate"
data-w-kbd-key-value="mod+s"
+ data-w-kbd-scope-value="global"
data-w-progress-active-value="{% trans 'Creating…' %}"
>
{% icon name="spinner" %}
diff --git a/wagtail/admin/templates/wagtailadmin/workflows/create_task.html b/wagtail/admin/templates/wagtailadmin/workflows/create_task.html
index 75c854086c..457817d4c6 100644
--- a/wagtail/admin/templates/wagtailadmin/workflows/create_task.html
+++ b/wagtail/admin/templates/wagtailadmin/workflows/create_task.html
@@ -25,6 +25,7 @@
data-controller="w-progress w-kbd"
data-action="w-progress#activate"
data-w-kbd-key-value="mod+s"
+ data-w-kbd-scope-value="global"
data-w-progress-active-value="{% trans 'Creating…' %}"
>
{% icon name="spinner" %}
diff --git a/wagtail/admin/templates/wagtailadmin/workflows/edit.html b/wagtail/admin/templates/wagtailadmin/workflows/edit.html
index ffff682646..076c2adda9 100644
--- a/wagtail/admin/templates/wagtailadmin/workflows/edit.html
+++ b/wagtail/admin/templates/wagtailadmin/workflows/edit.html
@@ -53,6 +53,7 @@
data-controller="w-progress w-kbd"
data-action="w-progress#activate"
data-w-kbd-key-value="mod+s"
+ data-w-kbd-scope-value="global"
data-w-progress-active-value="{% trans 'Saving…' %}"
>
{% icon name="spinner" %}
diff --git a/wagtail/admin/templates/wagtailadmin/workflows/edit_task.html b/wagtail/admin/templates/wagtailadmin/workflows/edit_task.html
index ee5e3dcebd..30537a34d0 100644
--- a/wagtail/admin/templates/wagtailadmin/workflows/edit_task.html
+++ b/wagtail/admin/templates/wagtailadmin/workflows/edit_task.html
@@ -37,6 +37,7 @@
data-controller="w-progress w-kbd"
data-action="w-progress#activate"
data-w-kbd-key-value="mod+s"
+ data-w-kbd-scope-value="global"
data-w-progress-active-value="{% trans 'Saving…' %}"
>
{% icon name="spinner" %}
diff --git a/wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/publish.html b/wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/publish.html
index 514a021e2d..0d60d2128e 100644
--- a/wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/publish.html
+++ b/wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/publish.html
@@ -7,6 +7,7 @@
data-controller="w-progress w-kbd"
data-action="w-progress#activate"
data-w-kbd-key-value="mod+s"
+ data-w-kbd-scope-value="global"
data-w-progress-active-value="{% trans 'Publishing…' %}"
>
{% icon name=icon_name classname="button-longrunning__icon" %}
diff --git a/wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/save.html b/wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/save.html
index 979fa660c6..4473fe256a 100644
--- a/wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/save.html
+++ b/wagtail/snippets/templates/wagtailsnippets/snippets/action_menu/save.html
@@ -5,6 +5,7 @@
data-controller="w-progress w-kbd"
data-action="w-progress#activate"
data-w-kbd-key-value="mod+s"
+ data-w-kbd-scope-value="global"
data-w-progress-active-value="{% trans 'Saving…' %}"
>
{% if draftstate_enabled %}