Skip to content

Commit 3a1b94c

Browse files
authored
Merge pull request #814 from CodinGame/fix-shadowdom-webview-keydown
Use dom manipulation tools everywhere
2 parents 6688db6 + ca22f0a commit 3a1b94c

5 files changed

Lines changed: 197 additions & 25 deletions

vscode-patches/0060-feat-support-shadow-dom.patch

Lines changed: 184 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@ Date: Fri, 2 May 2025 10:13:06 +0200
44
Subject: [PATCH] feat: support shadow dom
55

66
---
7-
src/vs/base/browser/dom.ts | 61 ++++++++++++++++---
8-
src/vs/base/browser/domStylesheets.ts | 22 ++++---
7+
src/vs/base/browser/dom.ts | 65 ++++++++++++++++---
8+
src/vs/base/browser/domStylesheets.ts | 22 +++++--
99
src/vs/base/browser/keyboardEvent.ts | 12 +++-
1010
.../browser/ui/contextview/contextview.ts | 2 +-
1111
src/vs/base/browser/ui/dialog/dialog.ts | 6 +-
1212
src/vs/base/browser/ui/dnd/dnd.ts | 4 +-
1313
src/vs/base/browser/ui/findinput/findInput.ts | 3 +-
1414
.../base/browser/ui/findinput/replaceInput.ts | 3 +-
15-
src/vs/base/browser/ui/inputbox/inputBox.ts | 7 ++-
15+
src/vs/base/browser/ui/inputbox/inputBox.ts | 7 +-
1616
src/vs/base/browser/ui/sash/sash.css | 2 +-
1717
src/vs/base/browser/ui/sash/sash.ts | 2 +-
1818
src/vs/base/browser/ui/splitview/paneview.ts | 6 +-
@@ -32,10 +32,14 @@ Subject: [PATCH] feat: support shadow dom
3232
src/vs/platform/hover/browser/hoverWidget.ts | 2 +-
3333
.../platform/layout/browser/zIndexRegistry.ts | 2 +-
3434
.../platform/theme/browser/iconsStyleSheet.ts | 2 +-
35+
.../agentFeedbackEditorInputContribution.ts | 6 +-
3536
.../browser/actions/developerActions.ts | 4 +-
3637
src/vs/workbench/browser/layout.ts | 3 +
3738
.../browser/parts/editor/editorGroupView.ts | 4 +-
39+
.../browser/parts/editor/modalEditorPart.ts | 4 +-
3840
src/vs/workbench/browser/workbench.ts | 6 +-
41+
.../experiments/agentTitleBarStatusWidget.ts | 4 +-
42+
.../planReviewFeedbackEditorContribution.ts | 6 +-
3943
.../browser/widget/input/chatInputPart.ts | 2 +-
4044
.../files/browser/views/explorerViewer.ts | 4 +-
4145
.../notebook/browser/notebookEditorWidget.ts | 6 +-
@@ -46,19 +50,20 @@ Subject: [PATCH] feat: support shadow dom
4650
.../view/renderers/backLayerWebView.ts | 3 +-
4751
.../browser/preferences.contribution.ts | 3 +-
4852
.../preferences/browser/settingsEditor2.ts | 6 +-
49-
.../terminal/browser/terminalService.ts | 7 +--
53+
.../terminal/browser/terminalService.ts | 7 +-
5054
.../terminal/browser/terminalTabbedView.ts | 2 +-
5155
.../contrib/terminal/browser/terminalView.ts | 2 +-
52-
.../contrib/webview/browser/webviewElement.ts | 12 ++--
56+
.../contrib/webview/browser/webviewElement.ts | 14 ++--
5357
.../browser/gettingStarted.ts | 4 +-
58+
.../browser/onboardingVariationA.ts | 8 +--
5459
.../browser/walkThroughPart.ts | 6 +-
5560
.../browser/auxiliaryWindowService.ts | 6 +-
5661
.../suggest/browser/simpleSuggestWidget.ts | 4 +-
5762
.../themes/browser/workbenchThemeService.ts | 33 +++++++++-
58-
51 files changed, 235 insertions(+), 117 deletions(-)
63+
56 files changed, 252 insertions(+), 134 deletions(-)
5964

6065
diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts
61-
index e943bf0a557..6ebc4568a39 100644
66+
index e943bf0a557..7c7bce3ae00 100644
6267
--- a/src/vs/base/browser/dom.ts
6368
+++ b/src/vs/base/browser/dom.ts
6469
@@ -257,6 +257,39 @@ export function addDisposableListener(node: EventTarget, type: string, handler:
@@ -140,7 +145,7 @@ index e943bf0a557..6ebc4568a39 100644
140145

141146
while (result?.shadowRoot) {
142147
result = result.shadowRoot.activeElement;
143-
@@ -1022,6 +1054,14 @@ export function getActiveElement(): Element | null {
148+
@@ -1022,13 +1054,21 @@ export function getActiveElement(): Element | null {
144149
return result;
145150
}
146151

@@ -155,6 +160,23 @@ index e943bf0a557..6ebc4568a39 100644
155160
/**
156161
* Returns true if the focused window active element matches
157162
* the provided element. Falls back to the main window if no
163+
* window has focus.
164+
*/
165+
export function isActiveElement(element: Element): boolean {
166+
- return getActiveElement() === element;
167+
+ return getActiveElement(element.ownerDocument) === element;
168+
}
169+
170+
/**
171+
@@ -1036,7 +1076,7 @@ export function isActiveElement(element: Element): boolean {
172+
* `ancestor`. Falls back to the main window if no window has focus.
173+
*/
174+
export function isAncestorOfActiveElement(ancestor: Element): boolean {
175+
- return isAncestor(getActiveElement(), ancestor);
176+
+ return isAncestor(getActiveElement(ancestor.ownerDocument), ancestor);
177+
}
178+
179+
/**
158180
@@ -1184,6 +1224,11 @@ export function isHTMLDivElement(e: unknown): e is HTMLDivElement {
159181
return e instanceof HTMLDivElement || e instanceof getWindow(e as Node).HTMLDivElement;
160182
}
@@ -838,6 +860,37 @@ index 7215f066d45..f55ed918b03 100644
838860

839861
return rules.join('\n');
840862
}
863+
diff --git a/src/vs/sessions/contrib/agentFeedback/browser/agentFeedbackEditorInputContribution.ts b/src/vs/sessions/contrib/agentFeedback/browser/agentFeedbackEditorInputContribution.ts
864+
index 0a2baa9cd08..b3a23939373 100644
865+
--- a/src/vs/sessions/contrib/agentFeedback/browser/agentFeedbackEditorInputContribution.ts
866+
+++ b/src/vs/sessions/contrib/agentFeedback/browser/agentFeedbackEditorInputContribution.ts
867+
@@ -11,7 +11,7 @@ import { EditorContributionInstantiation, registerEditorContribution } from '../
868+
import { ICodeEditorService } from '../../../../editor/browser/services/codeEditorService.js';
869+
import { EditorOption } from '../../../../editor/common/config/editorOptions.js';
870+
import { Selection, SelectionDirection } from '../../../../editor/common/core/selection.js';
871+
-import { addStandardDisposableListener, getWindow, ModifierKeyEmitter } from '../../../../base/browser/dom.js';
872+
+import { addStandardDisposableListener, getActiveElement, getWindow, isActiveElement, ModifierKeyEmitter } from '../../../../base/browser/dom.js';
873+
import { KeyCode } from '../../../../base/common/keyCodes.js';
874+
import { IAgentFeedbackService } from './agentFeedbackService.js';
875+
import { createAgentFeedbackContext } from './agentFeedbackEditorUtils.js';
876+
@@ -251,7 +251,7 @@ export class AgentFeedbackEditorInputContribution extends Disposable implements
877+
if (!this._visible) {
878+
return;
879+
}
880+
- if (this._isWidgetTarget(getWindow(this._editor.getDomNode()!).document.activeElement)) {
881+
+ if (this._isWidgetTarget(getActiveElement(this._editor.getDomNode()!.ownerDocument))) {
882+
return;
883+
}
884+
this._autoHide();
885+
@@ -432,7 +432,7 @@ export class AgentFeedbackEditorInputContribution extends Disposable implements
886+
}
887+
888+
// If the input is not focused, focus it and let the keystroke go through
889+
- if (getWindow(widget.inputElement).document.activeElement !== widget.inputElement) {
890+
+ if (!isActiveElement(widget.inputElement)) {
891+
widget.inputElement.focus();
892+
}
893+
}));
841894
diff --git a/src/vs/workbench/browser/actions/developerActions.ts b/src/vs/workbench/browser/actions/developerActions.ts
842895
index cdc59743913..14713c199ce 100644
843896
--- a/src/vs/workbench/browser/actions/developerActions.ts
@@ -903,6 +956,28 @@ index 7b3e372a077..bef32d191c0 100644
903956
return true; // always restore focus if nothing is focused currently
904957
}
905958

959+
diff --git a/src/vs/workbench/browser/parts/editor/modalEditorPart.ts b/src/vs/workbench/browser/parts/editor/modalEditorPart.ts
960+
index 6301ce26e57..0d15376efa3 100644
961+
--- a/src/vs/workbench/browser/parts/editor/modalEditorPart.ts
962+
+++ b/src/vs/workbench/browser/parts/editor/modalEditorPart.ts
963+
@@ -4,7 +4,7 @@
964+
*--------------------------------------------------------------------------------------------*/
965+
966+
import './media/modalEditorPart.css';
967+
-import { $, addDisposableListener, append, Dimension, EventHelper, EventType, hide, IDimension, isHTMLElement, setVisibility, show } from '../../../../base/browser/dom.js';
968+
+import { $, addDisposableListener, append, Dimension, EventHelper, EventType, getActiveElement, hide, IDimension, isHTMLElement, setVisibility, show } from '../../../../base/browser/dom.js';
969+
import { GlobalPointerMoveMonitor } from '../../../../base/browser/globalPointerMoveMonitor.js';
970+
import { StandardKeyboardEvent } from '../../../../base/browser/keyboardEvent.js';
971+
import { ActionBar, prepareActions } from '../../../../base/browser/ui/actionbar/actionbar.js';
972+
@@ -923,7 +923,7 @@ class ModalEditorPartImpl extends EditorPart implements IModalEditorPart {
973+
}
974+
975+
override create(parent: HTMLElement, options?: object): void {
976+
- this.previousMainWindowActiveElement = mainWindow.document.activeElement;
977+
+ this.previousMainWindowActiveElement = getActiveElement(mainWindow.document);
978+
979+
super.create(parent, options);
980+
}
906981
diff --git a/src/vs/workbench/browser/workbench.ts b/src/vs/workbench/browser/workbench.ts
907982
index 7796aae8a15..1c304a11a9e 100644
908983
--- a/src/vs/workbench/browser/workbench.ts
@@ -927,6 +1002,59 @@ index 7796aae8a15..1c304a11a9e 100644
9271002
}
9281003

9291004
private createPart(id: string, role: string, classes: string[]): HTMLElement {
1005+
diff --git a/src/vs/workbench/contrib/chat/browser/agentSessions/experiments/agentTitleBarStatusWidget.ts b/src/vs/workbench/contrib/chat/browser/agentSessions/experiments/agentTitleBarStatusWidget.ts
1006+
index 59d9960e78c..96d5fdc92a9 100644
1007+
--- a/src/vs/workbench/contrib/chat/browser/agentSessions/experiments/agentTitleBarStatusWidget.ts
1008+
+++ b/src/vs/workbench/contrib/chat/browser/agentSessions/experiments/agentTitleBarStatusWidget.ts
1009+
@@ -4,7 +4,7 @@
1010+
*--------------------------------------------------------------------------------------------*/
1011+
1012+
import './media/agenttitlebarstatuswidget.css';
1013+
-import { $, addDisposableListener, EventType, getWindow, isHTMLElement, reset } from '../../../../../../base/browser/dom.js';
1014+
+import { $, addDisposableListener, EventType, getActiveElement, isHTMLElement, reset } from '../../../../../../base/browser/dom.js';
1015+
import { renderIcon } from '../../../../../../base/browser/ui/iconLabel/iconLabels.js';
1016+
import { Disposable, DisposableStore } from '../../../../../../base/common/lifecycle.js';
1017+
import { Codicon } from '../../../../../../base/common/codicons.js';
1018+
@@ -295,7 +295,7 @@ export class AgentTitleBarStatusWidget extends BaseActionViewItem {
1019+
if (!this._container) {
1020+
return;
1021+
}
1022+
- const activeElement = getWindow(this._container).document.activeElement;
1023+
+ const activeElement = getActiveElement(this._container.ownerDocument);
1024+
if (isHTMLElement(activeElement) && this._container.contains(activeElement)) {
1025+
activeElement.blur();
1026+
}
1027+
diff --git a/src/vs/workbench/contrib/chat/browser/planReviewFeedback/planReviewFeedbackEditorContribution.ts b/src/vs/workbench/contrib/chat/browser/planReviewFeedback/planReviewFeedbackEditorContribution.ts
1028+
index 7486d45ae40..b3867ac6a12 100644
1029+
--- a/src/vs/workbench/contrib/chat/browser/planReviewFeedback/planReviewFeedbackEditorContribution.ts
1030+
+++ b/src/vs/workbench/contrib/chat/browser/planReviewFeedback/planReviewFeedbackEditorContribution.ts
1031+
@@ -14,7 +14,7 @@ import { Range } from '../../../../../editor/common/core/range.js';
1032+
import { OverviewRulerLane } from '../../../../../editor/common/model.js';
1033+
import { themeColorFromId } from '../../../../../platform/theme/common/themeService.js';
1034+
import { overviewRulerInfo } from '../../../../../editor/common/core/editorColorRegistry.js';
1035+
-import { addStandardDisposableListener, getWindow } from '../../../../../base/browser/dom.js';
1036+
+import { addStandardDisposableListener, getActiveElement, getWindow, isActiveElement } from '../../../../../base/browser/dom.js';
1037+
import { KeyCode } from '../../../../../base/common/keyCodes.js';
1038+
import { localize } from '../../../../../nls.js';
1039+
import { ActionBar } from '../../../../../base/browser/ui/actionbar/actionbar.js';
1040+
@@ -303,7 +303,7 @@ export class PlanReviewFeedbackEditorContribution extends Disposable implements
1041+
if (!this._visible) {
1042+
return;
1043+
}
1044+
- if (this._isWidgetTarget(getWindow(this._editor.getDomNode()!).document.activeElement)) {
1045+
+ if (this._isWidgetTarget(getActiveElement(this._editor.getDomNode()!.ownerDocument))) {
1046+
return;
1047+
}
1048+
this._hide();
1049+
@@ -452,7 +452,7 @@ export class PlanReviewFeedbackEditorContribution extends Disposable implements
1050+
return;
1051+
}
1052+
1053+
- if (getWindow(widget.inputElement).document.activeElement !== widget.inputElement) {
1054+
+ if (!isActiveElement(widget.inputElement)) {
1055+
widget.inputElement.focus();
1056+
}
1057+
}));
9301058
diff --git a/src/vs/workbench/contrib/chat/browser/widget/input/chatInputPart.ts b/src/vs/workbench/contrib/chat/browser/widget/input/chatInputPart.ts
9311059
index 2c67995e535..f11bf0d7a09 100644
9321060
--- a/src/vs/workbench/contrib/chat/browser/widget/input/chatInputPart.ts
@@ -1236,15 +1364,15 @@ index 9a745727415..32b87509ab3 100644
12361364
const listener = this._register(Event.once(this._terminalService.onDidChangeConnectionState)(() => {
12371365
// Only focus the terminal if the activeElement has not changed since focus() was called
12381366
diff --git a/src/vs/workbench/contrib/webview/browser/webviewElement.ts b/src/vs/workbench/contrib/webview/browser/webviewElement.ts
1239-
index 9f6018c77f5..e065c4bcc81 100644
1367+
index 9f6018c77f5..25085c88cde 100644
12401368
--- a/src/vs/workbench/contrib/webview/browser/webviewElement.ts
12411369
+++ b/src/vs/workbench/contrib/webview/browser/webviewElement.ts
12421370
@@ -4,7 +4,7 @@
12431371
*--------------------------------------------------------------------------------------------*/
12441372

12451373
import { isFirefox } from '../../../../base/browser/browser.js';
12461374
-import { addDisposableListener, EventType, getWindow, getWindowById } from '../../../../base/browser/dom.js';
1247-
+import { addDisposableListener, EventType, getActiveElement, getWindow, getWindowById } from '../../../../base/browser/dom.js';
1375+
+import { addDisposableListener, EventType, getActiveElement, getWindow, getWindowById, isActiveElement } from '../../../../base/browser/dom.js';
12481376
import { parentOriginHash } from '../../../../base/browser/iframe.js';
12491377
import { IMouseWheelEvent } from '../../../../base/browser/mouseEvent.js';
12501378
import { CodeWindow } from '../../../../base/browser/window.js';
@@ -1253,19 +1381,28 @@ index 9f6018c77f5..e065c4bcc81 100644
12531381
}
12541382

12551383
- if (this.window.document.activeElement && this.window.document.activeElement !== this.element) {
1256-
+ const activeElement = getActiveElement(this.window.document)
1384+
+ const activeElement = getActiveElement(this.window.document);
12571385
+ if (activeElement && activeElement !== this.element) {
12581386
// looks like https://github.com/microsoft/vscode/issues/132641
12591387
// where the focus is actually not in the `<iframe>`
12601388
return false;
1389+
@@ -712,7 +713,7 @@ export class WebviewElement extends Disposable implements IWebviewElement, Webvi
1390+
}
1391+
1392+
private isActiveElement(): boolean {
1393+
- return !!this.element && this.window?.document.activeElement === this.element;
1394+
+ return !!this.element && isActiveElement(this.element);
1395+
}
1396+
1397+
private handleKeyEvent(type: 'keydown' | 'keyup', event: KeyEvent) {
12611398
@@ -956,8 +957,11 @@ export class WebviewElement extends Disposable implements IWebviewElement, Webvi
12621399
return;
12631400
}
12641401

12651402
- if (this.window?.document.activeElement && this.window.document.activeElement !== this.element && this.window.document.activeElement?.tagName !== 'BODY') {
12661403
- return;
12671404
+ if (this.window) {
1268-
+ const activeElement = getActiveElement(this.window?.document)
1405+
+ const activeElement = getActiveElement(this.window?.document);
12691406
+ if (activeElement && activeElement !== this.element && activeElement?.tagName !== 'BODY') {
12701407
+ return;
12711408
+ }
@@ -1294,6 +1431,41 @@ index 0cb22b9cf17..64f8a2c27d7 100644
12941431

12951432
let parent = this.container.parentElement;
12961433
while (parent && parent !== active) {
1434+
diff --git a/src/vs/workbench/contrib/welcomeOnboarding/browser/onboardingVariationA.ts b/src/vs/workbench/contrib/welcomeOnboarding/browser/onboardingVariationA.ts
1435+
index ad276fc2c49..84d56dfff12 100644
1436+
--- a/src/vs/workbench/contrib/welcomeOnboarding/browser/onboardingVariationA.ts
1437+
+++ b/src/vs/workbench/contrib/welcomeOnboarding/browser/onboardingVariationA.ts
1438+
@@ -5,7 +5,7 @@
1439+
1440+
import { Disposable, DisposableStore } from '../../../../base/common/lifecycle.js';
1441+
import { Emitter, Event } from '../../../../base/common/event.js';
1442+
-import { $, append, addDisposableListener, EventType, clearNode, getActiveWindow } from '../../../../base/browser/dom.js';
1443+
+import { $, append, addDisposableListener, EventType, clearNode, getActiveWindow, getActiveElement, isActiveElement } from '../../../../base/browser/dom.js';
1444+
import { isCancellationError } from '../../../../base/common/errors.js';
1445+
import { StopWatch } from '../../../../base/common/stopwatch.js';
1446+
import { URI } from '../../../../base/common/uri.js';
1447+
@@ -172,7 +172,7 @@ export class OnboardingVariationA extends Disposable implements IOnboardingServi
1448+
}
1449+
1450+
this._isShowing = true;
1451+
- this.previouslyFocusedElement = getActiveWindow().document.activeElement as HTMLElement | undefined;
1452+
+ this.previouslyFocusedElement = getActiveElement() as HTMLElement | undefined;
1453+
1454+
const container = this.layoutService.activeContainer;
1455+
1456+
@@ -1268,10 +1268,10 @@ export class OnboardingVariationA extends Disposable implements IOnboardingServi
1457+
const first = allFocusable[0];
1458+
const last = allFocusable[allFocusable.length - 1];
1459+
1460+
- if (shiftKey && getActiveWindow().document.activeElement === first) {
1461+
+ if (shiftKey && isActiveElement(first)) {
1462+
e.preventDefault();
1463+
last.focus();
1464+
- } else if (!shiftKey && getActiveWindow().document.activeElement === last) {
1465+
+ } else if (!shiftKey && isActiveElement(last)) {
1466+
e.preventDefault();
1467+
first.focus();
1468+
}
12971469
diff --git a/src/vs/workbench/contrib/welcomeWalkthrough/browser/walkThroughPart.ts b/src/vs/workbench/contrib/welcomeWalkthrough/browser/walkThroughPart.ts
12981470
index c6fb17f8525..8691b2f7a37 100644
12991471
--- a/src/vs/workbench/contrib/welcomeWalkthrough/browser/walkThroughPart.ts

vscode-patches/0066-feat-prevent-IDE-from-entering-fullscreen-if-not-occ.patch

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Subject: [PATCH] feat: prevent IDE from entering fullscreen if not occupying
1212
4 files changed, 41 insertions(+), 16 deletions(-)
1313

1414
diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts
15-
index 6ebc4568a39..cc9e8f332c6 100644
15+
index 7c7bce3ae00..5bb747208c4 100644
1616
--- a/src/vs/base/browser/dom.ts
1717
+++ b/src/vs/base/browser/dom.ts
1818
@@ -1054,6 +1054,28 @@ export function getActiveElement(_document = getActiveDocument()): Element | nul

vscode-patches/0067-feat-support-loading-VSCode-in-an-iframe.patch

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ index d7c129abb27..a2895879194 100644
100100
+ pointerEvents: mainWindow.PointerEvent && ('ontouchstart' in mainWindow || mainWindow.navigator.maxTouchPoints > 0)
101101
};
102102
diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts
103-
index cc9e8f332c6..d06887a7eb2 100644
103+
index 5bb747208c4..56d5f762245 100644
104104
--- a/src/vs/base/browser/dom.ts
105105
+++ b/src/vs/base/browser/dom.ts
106106
@@ -1165,7 +1165,7 @@ export const sharedMutationObserver = new class {

vscode-patches/0068-feat-mark-elements-created-outside-of-the-VSCode-con.patch

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ Subject: [PATCH] feat: mark elements created outside of the VSCode container
99
2 files changed, 2 insertions(+)
1010

1111
diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts
12-
index d06887a7eb2..25103157ef1 100644
12+
index 56d5f762245..5ec342e8b9e 100644
1313
--- a/src/vs/base/browser/dom.ts
1414
+++ b/src/vs/base/browser/dom.ts
1515
@@ -1207,6 +1207,7 @@ export function createLinkElement(container: HTMLElement = mainWindow.document.h

0 commit comments

Comments
 (0)