Skip to content

Commit 47a0ab6

Browse files
authored
aux window - fix CSS cloning (microsoft#196788)
* aux window - fix CSS cloning * 💄
1 parent df6e1ae commit 47a0ab6

File tree

10 files changed

+40
-40
lines changed

10 files changed

+40
-40
lines changed

src/vs/base/browser/dom.ts

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -798,12 +798,11 @@ export function createStyleSheet(container: HTMLElement = document.head, beforeA
798798
continue; // main window is already tracked
799799
}
800800

801-
const clone = cloneGlobalStyleSheet(style, targetWindow);
802-
clonedGlobalStylesheets.add(clone);
801+
const disposable = cloneGlobalStyleSheet(style, targetWindow);
803802

804803
event.Event.once(onDidUnregisterWindow)(unregisteredWindow => {
805804
if (unregisteredWindow === targetWindow) {
806-
clonedGlobalStylesheets.delete(clone);
805+
disposable.dispose();
807806
}
808807
});
809808
}
@@ -819,25 +818,34 @@ export function isGlobalStylesheet(node: Node): boolean {
819818
export function cloneGlobalStylesheets(targetWindow: Window & typeof globalThis): IDisposable {
820819
const disposables = new DisposableStore();
821820

822-
for (const [globalStylesheet, clonedGlobalStylesheets] of globalStylesheets) {
823-
const clone = cloneGlobalStyleSheet(globalStylesheet, targetWindow);
824-
825-
clonedGlobalStylesheets.add(clone);
826-
disposables.add(toDisposable(() => clonedGlobalStylesheets.delete(clone)));
821+
for (const [globalStylesheet] of globalStylesheets) {
822+
disposables.add(cloneGlobalStyleSheet(globalStylesheet, targetWindow));
827823
}
828824

829825
return disposables;
830826
}
831827

832-
function cloneGlobalStyleSheet(globalStylesheet: HTMLStyleElement, targetWindow: Window & typeof globalThis): HTMLStyleElement {
828+
function cloneGlobalStyleSheet(globalStylesheet: HTMLStyleElement, targetWindow: Window & typeof globalThis): IDisposable {
833829
const clone = globalStylesheet.cloneNode(true) as HTMLStyleElement;
834830
targetWindow.document.head.appendChild(clone);
835831

836832
for (const rule of getDynamicStyleSheetRules(globalStylesheet)) {
837833
clone.sheet?.insertRule(rule.cssText, clone.sheet?.cssRules.length);
838834
}
839835

840-
return clone;
836+
const observer = new MutationObserver(() => {
837+
clone.textContent = globalStylesheet.textContent;
838+
});
839+
observer.observe(globalStylesheet, { childList: true });
840+
841+
globalStylesheets.get(globalStylesheet)?.add(clone);
842+
843+
return toDisposable(() => {
844+
observer.disconnect();
845+
targetWindow.document.head.removeChild(clone);
846+
847+
globalStylesheets.get(globalStylesheet)?.delete(clone);
848+
});
841849
}
842850

843851
export function createMetaElement(container: HTMLElement = document.head): HTMLMetaElement {

src/vs/workbench/contrib/accessibility/browser/unfocusedViewDimmingContribution.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6+
import { createStyleSheet } from 'vs/base/browser/dom';
67
import { Event } from 'vs/base/common/event';
78
import { Disposable, toDisposable } from 'vs/base/common/lifecycle';
89
import { clamp } from 'vs/base/common/numbers';
@@ -73,9 +74,8 @@ export class UnfocusedViewDimmingContribution extends Disposable implements IWor
7374

7475
private _getStyleElement(): HTMLStyleElement {
7576
if (!this._styleElement) {
76-
this._styleElement = document.createElement('style');
77+
this._styleElement = createStyleSheet();
7778
this._styleElement.className = 'accessibilityUnfocusedViewOpacity';
78-
document.head.appendChild(this._styleElement);
7979
}
8080
return this._styleElement;
8181
}

src/vs/workbench/contrib/tasks/browser/taskQuickPick.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import { IThemeService } from 'vs/platform/theme/common/themeService';
1919
import { ThemeIcon } from 'vs/base/common/themables';
2020
import { registerIcon } from 'vs/platform/theme/common/iconRegistry';
2121
import { IDialogService } from 'vs/platform/dialogs/common/dialogs';
22-
import { getColorClass, getColorStyleElement } from 'vs/workbench/contrib/terminal/browser/terminalIcon';
22+
import { getColorClass, createColorStyleElement } from 'vs/workbench/contrib/terminal/browser/terminalIcon';
2323
import { TaskQuickPickEntryType } from 'vs/workbench/contrib/tasks/browser/abstractTaskService';
2424
import { showWithPinnedItems } from 'vs/platform/quickinput/browser/quickPickPin';
2525
import { IStorageService } from 'vs/platform/storage/common/storage';
@@ -93,9 +93,8 @@ export class TaskQuickPick extends Disposable {
9393
public static applyColorStyles(task: Task | ConfiguringTask, entry: TaskQuickPickEntryType | ITaskTwoLevelQuickPickEntry, themeService: IThemeService): void {
9494
if (task.configurationProperties.icon?.color) {
9595
const colorTheme = themeService.getColorTheme();
96-
const styleElement = getColorStyleElement(colorTheme);
96+
createColorStyleElement(colorTheme);
9797
entry.iconClasses = [getColorClass(task.configurationProperties.icon.color)];
98-
document.body.appendChild(styleElement);
9998
}
10099
}
101100

src/vs/workbench/contrib/terminal/browser/terminalIcon.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import { ThemeIcon } from 'vs/base/common/themables';
1414
import { ITerminalInstance } from 'vs/workbench/contrib/terminal/browser/terminal';
1515
import { ITerminalProfileResolverService } from 'vs/workbench/contrib/terminal/common/terminal';
1616
import { ansiColorMap } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry';
17+
import { createStyleSheet } from 'vs/base/browser/dom';
18+
import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
1719

1820

1921
export function getColorClass(colorKey: string): string;
@@ -47,9 +49,9 @@ export function getStandardColors(colorTheme: IColorTheme): string[] {
4749
return standardColors;
4850
}
4951

50-
export function getColorStyleElement(colorTheme: IColorTheme): HTMLElement {
52+
export function createColorStyleElement(colorTheme: IColorTheme): IDisposable {
5153
const standardColors = getStandardColors(colorTheme);
52-
const styleElement = document.createElement('style');
54+
const styleElement = createStyleSheet();
5355
let css = '';
5456
for (const colorKey of standardColors) {
5557
const colorClass = getColorClass(colorKey);
@@ -62,7 +64,7 @@ export function getColorStyleElement(colorTheme: IColorTheme): HTMLElement {
6264
}
6365
}
6466
styleElement.textContent = css;
65-
return styleElement;
67+
return toDisposable(() => styleElement.remove());
6668
}
6769

6870
export function getColorStyleContent(colorTheme: IColorTheme, editor?: boolean): string {

src/vs/workbench/contrib/terminal/browser/terminalInstance.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ import { TerminalLaunchHelpAction } from 'vs/workbench/contrib/terminal/browser/
6363
import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper';
6464
import { TerminalEditorInput } from 'vs/workbench/contrib/terminal/browser/terminalEditorInput';
6565
import { TerminalExtensionsRegistry } from 'vs/workbench/contrib/terminal/browser/terminalExtensions';
66-
import { getColorClass, getColorStyleElement, getStandardColors } from 'vs/workbench/contrib/terminal/browser/terminalIcon';
66+
import { getColorClass, createColorStyleElement, getStandardColors } from 'vs/workbench/contrib/terminal/browser/terminalIcon';
6767
import { TerminalProcessManager } from 'vs/workbench/contrib/terminal/browser/terminalProcessManager';
6868
import { showRunRecentQuickPick } from 'vs/workbench/contrib/terminal/browser/terminalRunRecentQuickPick';
6969
import { ITerminalStatusList, TerminalStatus, TerminalStatusList } from 'vs/workbench/contrib/terminal/browser/terminalStatusList';
@@ -2200,7 +2200,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
22002200
}
22012201
const colorTheme = this._themeService.getColorTheme();
22022202
const standardColors: string[] = getStandardColors(colorTheme);
2203-
const styleElement = getColorStyleElement(colorTheme);
2203+
const colorStyleDisposable = createColorStyleElement(colorTheme);
22042204
const items: QuickPickItem[] = [];
22052205
for (const colorKey of standardColors) {
22062206
const colorClass = getColorClass(colorKey);
@@ -2211,7 +2211,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
22112211
items.push({ type: 'separator' });
22122212
const showAllColorsItem = { label: 'Reset to default' };
22132213
items.push(showAllColorsItem);
2214-
document.body.appendChild(styleElement);
22152214

22162215
const quickPick = this._quickInputService.createQuickPick();
22172216
quickPick.items = items;
@@ -2231,7 +2230,7 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
22312230
}
22322231

22332232
quickPick.hide();
2234-
document.body.removeChild(styleElement);
2233+
colorStyleDisposable.dispose();
22352234
}
22362235

22372236
selectPreviousSuggestion(): void {

src/vs/workbench/contrib/terminal/browser/terminalProfileQuickpick.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import { Codicon } from 'vs/base/common/codicons';
77
import { ConfigurationTarget, IConfigurationService } from 'vs/platform/configuration/common/configuration';
88
import { IQuickInputService, IKeyMods, IPickOptions, IQuickPickSeparator, IQuickInputButton, IQuickPickItem } from 'vs/platform/quickinput/common/quickInput';
99
import { IExtensionTerminalProfile, ITerminalProfile, ITerminalProfileObject, TerminalSettingPrefix } from 'vs/platform/terminal/common/terminal';
10-
import { getUriClasses, getColorClass, getColorStyleElement } from 'vs/workbench/contrib/terminal/browser/terminalIcon';
10+
import { getUriClasses, getColorClass, createColorStyleElement } from 'vs/workbench/contrib/terminal/browser/terminalIcon';
1111
import { configureTerminalProfileIcon } from 'vs/workbench/contrib/terminal/browser/terminalIcons';
1212
import * as nls from 'vs/nls';
1313
import { IThemeService } from 'vs/platform/theme/common/themeService';
@@ -196,11 +196,10 @@ export class TerminalProfileQuickpick {
196196
quickPickItems.push({ type: 'separator', label: nls.localize('terminalProfiles.detected', "detected") });
197197
quickPickItems.push(...this._sortProfileQuickPickItems(autoDetectedProfiles.map(e => this._createProfileQuickPickItem(e)), defaultProfileName!));
198198
}
199-
const styleElement = getColorStyleElement(this._themeService.getColorTheme());
200-
document.body.appendChild(styleElement);
199+
const colorStyleDisposable = createColorStyleElement(this._themeService.getColorTheme());
201200

202201
const result = await this._quickInputService.pick(quickPickItems, options);
203-
document.body.removeChild(styleElement);
202+
colorStyleDisposable.dispose();
204203
if (!result) {
205204
return undefined;
206205
}

src/vs/workbench/contrib/terminal/browser/terminalService.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1195,8 +1195,7 @@ class TerminalEditorStyle extends Themable {
11951195
) {
11961196
super(_themeService);
11971197
this._registerListeners();
1198-
this._styleElement = document.createElement('style');
1199-
container.appendChild(this._styleElement);
1198+
this._styleElement = dom.createStyleSheet(container);
12001199
this._register(toDisposable(() => container.removeChild(this._styleElement)));
12011200
this.updateStyles();
12021201
}

src/vs/workbench/contrib/terminal/browser/terminalView.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ import { IHoverService } from 'vs/workbench/services/hover/browser/hover';
4949
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
5050

5151
export class TerminalViewPane extends ViewPane {
52-
private _fontStyleElement: HTMLElement | undefined;
5352
private _parentDomElement: HTMLElement | undefined;
5453
private _terminalTabbedView?: TerminalTabbedView;
5554
get terminalTabbedView(): TerminalTabbedView | undefined { return this._terminalTabbedView; }
@@ -178,15 +177,13 @@ export class TerminalViewPane extends ViewPane {
178177
}
179178
this._parentDomElement = container;
180179
this._parentDomElement.classList.add('integrated-terminal');
181-
this._fontStyleElement = document.createElement('style');
180+
dom.createStyleSheet(this._parentDomElement);
182181
this._instantiationService.createInstance(TerminalThemeIconStyle, this._parentDomElement);
183182

184183
if (!this.shouldShowWelcome()) {
185184
this._createTabsView();
186185
}
187186

188-
this._parentDomElement.appendChild(this._fontStyleElement);
189-
190187
this._register(this.configurationService.onDidChangeConfiguration(e => {
191188
if (e.affectsConfiguration(TerminalSettingId.FontFamily) || e.affectsConfiguration('editor.fontFamily')) {
192189
const configHelper = this._terminalService.configHelper;
@@ -558,8 +555,7 @@ class TerminalThemeIconStyle extends Themable {
558555
) {
559556
super(_themeService);
560557
this._registerListeners();
561-
this._styleElement = document.createElement('style');
562-
container.appendChild(this._styleElement);
558+
this._styleElement = dom.createStyleSheet(container);
563559
this._register(toDisposable(() => container.removeChild(this._styleElement)));
564560
this.updateStyles();
565561
}

src/vs/workbench/services/auxiliaryWindow/browser/auxiliaryWindowService.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
import { localize } from 'vs/nls';
77
import { Emitter, Event } from 'vs/base/common/event';
8-
import { Dimension, EventHelper, EventType, addDisposableListener, cloneGlobalStylesheets, copyAttributes, getActiveWindow, getClientArea, isGlobalStylesheet, position, registerWindow, size, trackAttributes } from 'vs/base/browser/dom';
8+
import { Dimension, EventHelper, EventType, addDisposableListener, cloneGlobalStylesheets, copyAttributes, createMetaElement, getActiveWindow, getClientArea, isGlobalStylesheet, position, registerWindow, size, trackAttributes } from 'vs/base/browser/dom';
99
import { Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
1010
import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions';
1111
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
@@ -135,12 +135,12 @@ export class BrowserAuxiliaryWindowService extends Disposable implements IAuxili
135135
}
136136

137137
private applyMeta(auxiliaryWindow: AuxiliaryWindow): void {
138-
const metaCharset = auxiliaryWindow.document.head.appendChild(document.createElement('meta'));
138+
const metaCharset = createMetaElement(auxiliaryWindow.document.head);
139139
metaCharset.setAttribute('charset', 'utf-8');
140140

141141
const originalCSPMetaTag = document.querySelector('meta[http-equiv="Content-Security-Policy"]');
142142
if (originalCSPMetaTag) {
143-
const csp = auxiliaryWindow.document.head.appendChild(document.createElement('meta'));
143+
const csp = createMetaElement(auxiliaryWindow.document.head);
144144
copyAttributes(originalCSPMetaTag, csp);
145145

146146
const content = csp.getAttribute('content');

src/vs/workbench/services/themes/browser/workbenchThemeService.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -873,11 +873,9 @@ class ThemeFileWatcher {
873873
function _applyRules(styleSheetContent: string, rulesClassName: string) {
874874
const themeStyles = document.head.getElementsByClassName(rulesClassName);
875875
if (themeStyles.length === 0) {
876-
const elStyle = document.createElement('style');
877-
elStyle.type = 'text/css';
876+
const elStyle = createStyleSheet();
878877
elStyle.className = rulesClassName;
879878
elStyle.textContent = styleSheetContent;
880-
document.head.appendChild(elStyle);
881879
} else {
882880
(<HTMLStyleElement>themeStyles[0]).textContent = styleSheetContent;
883881
}

0 commit comments

Comments
 (0)