Skip to content

Commit ef9f14d

Browse files
committed
feat(widget): add keyboard shortcuts for WidgetWindow
1 parent a439d40 commit ef9f14d

File tree

1 file changed

+65
-5
lines changed

1 file changed

+65
-5
lines changed

js/widgets/widgetWindows.js

Lines changed: 65 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,51 @@ Globals location
1717
_, docById
1818
*/
1919

20-
window.widgetWindows = { openWindows: {}, _posCache: {} };
20+
window.widgetWindows = {
21+
openWindows: {},
22+
_posCache: {},
23+
focused: null,
24+
_shortcutsInitialized: false,
25+
_handleGlobalKeyDown(e) {
26+
const focused = window.widgetWindows.focused;
27+
if (!focused || e.repeat) return; // Guard against no focus or rapid-fire repeat
28+
29+
// Ignore shortcuts when focus is inside an input, textarea, or contenteditable element
30+
const activeElement = document.activeElement;
31+
const isInput =
32+
activeElement &&
33+
(activeElement.tagName === "INPUT" ||
34+
activeElement.tagName === "TEXTAREA" ||
35+
activeElement.isContentEditable);
36+
37+
if (isInput) return;
38+
39+
// Handle Escape (Close)
40+
if (e.key === "Escape") {
41+
focused.onclose();
42+
e.preventDefault();
43+
e.stopPropagation();
44+
return;
45+
}
46+
47+
// Handle Maximize (Cmd/Ctrl + Shift + M)
48+
const isModifierActive = e.metaKey || e.ctrlKey;
49+
if (isModifierActive && e.shiftKey && e.code === "KeyM") {
50+
if (focused._fullscreenEnabled) {
51+
if (focused._maximized) {
52+
focused._restore();
53+
focused.sendToCenter();
54+
} else {
55+
focused._maximize();
56+
}
57+
focused.takeFocus();
58+
focused.onmaximize();
59+
e.preventDefault();
60+
e.stopPropagation();
61+
}
62+
}
63+
}
64+
};
2165

2266
class WidgetWindow {
2367
/**
@@ -47,14 +91,18 @@ class WidgetWindow {
4791
this._setupLanguage();
4892

4993
// Global watchers
50-
this._dragTopHandler = this._dragTopHandler.bind(this);
51-
this._docMouseMoveHandler = this._docMouseMoveHandler.bind(this);
52-
this._docMouseDownHandler = this._docMouseDownHandler.bind(this);
53-
5494
document.addEventListener("mouseup", this._dragTopHandler, true);
5595
document.addEventListener("mousemove", this._docMouseMoveHandler, true);
5696
document.addEventListener("mousedown", this._docMouseDownHandler, true);
5797

98+
if (!window.widgetWindows._shortcutsInitialized) {
99+
// Use capture phase (true) to ensure global window control shortcuts are handled
100+
// before individual widgets/blocks can intercept them via stopPropagation().
101+
window.removeEventListener("keydown", window.widgetWindows._handleGlobalKeyDown, true);
102+
window.addEventListener("keydown", window.widgetWindows._handleGlobalKeyDown, true);
103+
window.widgetWindows._shortcutsInitialized = true;
104+
}
105+
58106
if (window.widgetWindows._posCache[this._key]) {
59107
const _pos = window.widgetWindows._posCache[this._key];
60108
this.setPosition(_pos[0], _pos[1]);
@@ -261,9 +309,13 @@ class WidgetWindow {
261309
if (e.target === this._frame || this._frame.contains(e.target) || this._fullscreenEnabled) {
262310
this._frame.style.opacity = "1";
263311
this._frame.style.zIndex = "10000";
312+
window.widgetWindows.focused = this;
264313
} else {
265314
this._frame.style.opacity = ".7";
266315
this._frame.style.zIndex = "0";
316+
if (window.widgetWindows.focused === this) {
317+
window.widgetWindows.focused = null;
318+
}
267319
}
268320
}
269321

@@ -408,6 +460,7 @@ class WidgetWindow {
408460
* @returns {void}
409461
*/
410462
takeFocus() {
463+
window.widgetWindows.focused = this;
411464
const windows = docById("floatingWindows");
412465
const siblings = windows.children;
413466
for (let i = 0; i < siblings.length; i++) {
@@ -556,6 +609,9 @@ class WidgetWindow {
556609
if (this._overlayframe && this._overlayframe.parentElement) {
557610
this._overlayframe.parentElement.removeChild(this._overlayframe);
558611
}
612+
if (window.widgetWindows.focused === this) {
613+
window.widgetWindows.focused = null;
614+
}
559615
window.widgetWindows.openWindows[this._key] = undefined;
560616
}
561617

@@ -696,6 +752,7 @@ window.widgetWindows.hideAllWindows = () => {
696752
Object.values(window.widgetWindows.openWindows).forEach(win => {
697753
if (win !== undefined) win._frame.style.display = "none";
698754
});
755+
window.widgetWindows.focused = null;
699756
};
700757

701758
/**
@@ -706,6 +763,9 @@ window.widgetWindows.hideWindow = name => {
706763
const win = window.widgetWindows.openWindows[name];
707764
if (!win) return;
708765
win._frame.style.display = "none";
766+
if (window.widgetWindows.focused === win) {
767+
window.widgetWindows.focused = null;
768+
}
709769
};
710770

711771
/**

0 commit comments

Comments
 (0)