chrome-devtools-frontend 1.0.1679704 → 1.0.1681091
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AUTHORS +1 -0
- package/front_end/core/platform/TypescriptUtilities.ts +0 -9
- package/front_end/core/platform/platform.ts +1 -1
- package/front_end/core/sdk/ConsoleModel.ts +6 -3
- package/front_end/core/sdk/DOMModel.ts +102 -0
- package/front_end/core/sdk/EmulationModel.ts +4 -2
- package/front_end/core/sdk/NetworkManager.ts +7 -6
- package/front_end/core/sdk/PageResourceLoader.ts +4 -3
- package/front_end/core/sdk/RuntimeModel.ts +5 -3
- package/front_end/core/sdk/SDKSettings.ts +47 -0
- package/front_end/core/sdk/sdk-meta.ts +0 -138
- package/front_end/entrypoints/inspector_main/RenderingOptions.ts +4 -2
- package/front_end/entrypoints/inspector_main/inspector_main-meta.ts +32 -0
- package/front_end/entrypoints/main/MainImpl.ts +1 -1
- package/front_end/generated/InspectorBackendCommands.ts +3 -1
- package/front_end/generated/SupportedCSSProperties.ts +20 -0
- package/front_end/generated/protocol-mapping.d.ts +7 -0
- package/front_end/generated/protocol-proxy-api.d.ts +5 -0
- package/front_end/generated/protocol.ts +15 -3
- package/front_end/panels/console/ConsoleView.ts +2 -1
- package/front_end/panels/console/console-meta.ts +10 -5
- package/front_end/panels/elements/DOMTreeContextMenu.ts +541 -0
- package/front_end/panels/elements/ElementsTreeElement.ts +27 -494
- package/front_end/panels/elements/ElementsTreeOutline.ts +173 -287
- package/front_end/panels/elements/StylesSidebarPane.ts +2 -1
- package/front_end/panels/elements/elements.ts +3 -0
- package/front_end/panels/issues/CorsIssueDetailsView.ts +13 -9
- package/front_end/panels/mobile_throttling/NetworkPanelIndicator.ts +3 -1
- package/front_end/panels/network/NetworkConfigView.ts +2 -1
- package/front_end/panels/network/NetworkPanel.ts +1 -1
- package/front_end/panels/network/network-meta.ts +60 -0
- package/front_end/panels/profiler/HeapDetachedElementsDataGrid.ts +2 -1
- package/front_end/panels/profiler/ProfileLauncherView.ts +19 -16
- package/front_end/panels/profiler/ProfileSidebarTreeElement.ts +1 -1
- package/front_end/panels/security/security.ts +6 -0
- package/front_end/panels/sources/SourcesView.ts +8 -107
- package/front_end/panels/sources/TabbedEditorContainer.ts +110 -7
- package/front_end/panels/sources/sources-meta.ts +16 -0
- package/front_end/panels/timeline/TimelineLoader.ts +1 -1
- package/front_end/panels/timeline/TimelineUIUtils.ts +6 -0
- package/front_end/panels/timeline/components/LayoutShiftDetails.ts +4 -3
- package/front_end/panels/timeline/components/LiveMetricsView.ts +1 -1
- package/front_end/panels/timeline/components/MetricCard.ts +4 -3
- package/front_end/panels/timeline/components/NetworkRequestDetails.ts +5 -2
- package/front_end/panels/timeline/components/TimelineRangeSummaryView.ts +1 -1
- package/front_end/panels/timeline/components/TimelineSummary.ts +8 -5
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/ui/legacy/TabbedPane.ts +34 -2
- package/front_end/ui/legacy/components/quick_open/CommandMenu.ts +5 -5
- package/front_end/ui/legacy/components/quick_open/FilteredListWidget.ts +7 -7
- package/front_end/ui/legacy/components/quick_open/QuickOpen.ts +1 -1
- package/front_end/ui/legacy/components/quick_open/quick_open-meta.ts +2 -2
- package/front_end/ui/visual_logging/KnownContextValues.ts +29 -0
- package/package.json +1 -1
|
@@ -49,8 +49,8 @@ import {html, nothing, render} from '../../ui/lit/lit.js';
|
|
|
49
49
|
import * as VisualLogging from '../../ui/visual_logging/visual_logging.js';
|
|
50
50
|
|
|
51
51
|
import {AdoptedStyleSheetSetTreeElement, AdoptedStyleSheetTreeElement} from './AdoptedStyleSheetTreeElement.js';
|
|
52
|
+
import {showContextMenu} from './DOMTreeContextMenu.js';
|
|
52
53
|
import {getElementIssueDetails} from './ElementIssueUtils.js';
|
|
53
|
-
import {ElementsPanel} from './ElementsPanel.js';
|
|
54
54
|
import {ElementsTreeElement, InitialChildrenLimit, isOpeningTag} from './ElementsTreeElement.js';
|
|
55
55
|
import elementsTreeOutlineStyles from './elementsTreeOutline.css.js';
|
|
56
56
|
import {ImagePreviewPopover} from './ImagePreviewPopover.js';
|
|
@@ -63,10 +63,6 @@ const UIStrings = {
|
|
|
63
63
|
* @description ARIA accessible name in Elements Tree Outline of the Elements panel
|
|
64
64
|
*/
|
|
65
65
|
pageDom: 'Page DOM',
|
|
66
|
-
/**
|
|
67
|
-
* @description A context menu item to store a value as a global variable the Elements Panel
|
|
68
|
-
*/
|
|
69
|
-
storeAsGlobalVariable: 'Store as global variable',
|
|
70
66
|
/**
|
|
71
67
|
* @description Tree element expand all button element button text content in Elements Tree Outline of the Elements panel
|
|
72
68
|
* @example {3} PH1
|
|
@@ -117,10 +113,12 @@ interface ViewInput {
|
|
|
117
113
|
onElementsTreeUpdated: (event: Common.EventTarget.EventTargetEvent<SDK.DOMModel.DOMNode[]>) => void;
|
|
118
114
|
onElementCollapsed: () => void;
|
|
119
115
|
onElementExpanded: () => void;
|
|
116
|
+
onSaveNodeToTempVariable?: (node: SDK.DOMModel.DOMNode) => void;
|
|
120
117
|
}
|
|
121
118
|
|
|
122
119
|
interface ViewOutput {
|
|
123
120
|
elementsTreeOutline?: ElementsTreeOutline;
|
|
121
|
+
imagePreviewPopover?: ImagePreviewPopover;
|
|
124
122
|
highlightedTreeElement: ElementsTreeElement|null;
|
|
125
123
|
isUpdatingHighlights: boolean;
|
|
126
124
|
alreadyExpandedParentTreeElement: ElementsTreeElement|null;
|
|
@@ -131,27 +129,102 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
|
|
|
131
129
|
// FIXME: this is basically a ref to existing imperative
|
|
132
130
|
// implementation. Once this is declarative the ref should not be
|
|
133
131
|
// needed.
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
output.elementsTreeOutline
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
132
|
+
const elementsTreeOutline = new ElementsTreeOutline(input.omitRootDOMNode, input.selectEnabled, input.hideGutter,
|
|
133
|
+
input.maxTreeDepth, input.enableContextMenu, input.showComments,
|
|
134
|
+
input.showAIButton, input.disableEdits, input.expandRoot);
|
|
135
|
+
output.elementsTreeOutline = elementsTreeOutline;
|
|
136
|
+
elementsTreeOutline.addEventListener(ElementsTreeOutline.Events.SelectedNodeChanged, input.onSelectedNodeChanged,
|
|
137
|
+
this);
|
|
138
|
+
elementsTreeOutline.addEventListener(ElementsTreeOutline.Events.ElementsTreeUpdated, input.onElementsTreeUpdated,
|
|
139
|
+
this);
|
|
140
|
+
elementsTreeOutline.addEventListener(UI.TreeOutline.Events.ElementExpanded, input.onElementExpanded, this);
|
|
141
|
+
elementsTreeOutline.addEventListener(UI.TreeOutline.Events.ElementCollapsed, input.onElementCollapsed, this);
|
|
142
|
+
elementsTreeOutline.addEventListener(ElementsTreeOutline.Events.ShowAllRows, () => {
|
|
143
|
+
if (elementsTreeOutline.maxRowsShown) {
|
|
145
144
|
// Set max to undefined to show all rows
|
|
146
|
-
|
|
145
|
+
elementsTreeOutline.maxRowsShown = undefined;
|
|
147
146
|
}
|
|
148
147
|
}, this);
|
|
149
|
-
|
|
148
|
+
elementsTreeOutline.elementInternal.addEventListener('contextmenu', (event: MouseEvent) => {
|
|
149
|
+
const treeElement = elementsTreeOutline.treeElementFromEventInternal(event);
|
|
150
|
+
if (treeElement instanceof ElementsTreeElement) {
|
|
151
|
+
output.elementsTreeOutline?.showContextMenu(treeElement, event);
|
|
152
|
+
}
|
|
153
|
+
}, false);
|
|
154
|
+
output.imagePreviewPopover = new ImagePreviewPopover(
|
|
155
|
+
elementsTreeOutline.contentElement,
|
|
156
|
+
event => {
|
|
157
|
+
let link: (Element|null) = (event.target as Element | null);
|
|
158
|
+
while (link && !ImagePreviewPopover.getImageURL(link)) {
|
|
159
|
+
link = link.parentElementOrShadowHost();
|
|
160
|
+
}
|
|
161
|
+
return link;
|
|
162
|
+
},
|
|
163
|
+
async link => {
|
|
164
|
+
const listItem = UI.UIUtils.enclosingNodeOrSelfWithNodeName(link, 'li');
|
|
165
|
+
if (!listItem) {
|
|
166
|
+
return undefined;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const treeElement =
|
|
170
|
+
(UI.TreeOutline.TreeElement.getTreeElementBylistItemNode(listItem) as ElementsTreeElement | undefined);
|
|
171
|
+
return await UIComponentUtils.ImagePreview.loadPrecomputedFeatures(treeElement?.node());
|
|
172
|
+
});
|
|
173
|
+
// TODO(changhaohan): refactor the popover to use tooltip component.
|
|
174
|
+
const popupHelper = new UI.PopoverHelper.PopoverHelper(elementsTreeOutline.elementInternal, event => {
|
|
175
|
+
const hoveredNode = event.composedPath()[0];
|
|
176
|
+
if (!(hoveredNode instanceof Element) || !hoveredNode.matches('.violating-element')) {
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const issues = elementsTreeOutline.issuesByNodeElement(hoveredNode);
|
|
181
|
+
if (!issues) {
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
return {
|
|
186
|
+
box: hoveredNode.boxInWindow(),
|
|
187
|
+
show: async (popover: UI.GlassPane.GlassPane) => {
|
|
188
|
+
popover.setIgnoreLeftMargin(true);
|
|
189
|
+
// clang-format off
|
|
190
|
+
render(html`
|
|
191
|
+
<div class="squiggles-content">
|
|
192
|
+
${issues.map(issue => {
|
|
193
|
+
const elementIssueDetails = getElementIssueDetails(issue);
|
|
194
|
+
if (!elementIssueDetails) {
|
|
195
|
+
// This shouldn't happen, but add this if check to pass ts check.
|
|
196
|
+
return nothing;
|
|
197
|
+
}
|
|
198
|
+
const issueKindIconName = IssueCounter.IssueCounter.getIssueKindIconName(issue.getKind());
|
|
199
|
+
const openIssueEvent = (): Promise<void> => Common.Revealer.reveal(issue);
|
|
200
|
+
return html`
|
|
201
|
+
<div class="squiggles-content-item">
|
|
202
|
+
<devtools-icon .name=${issueKindIconName} @click=${openIssueEvent}></devtools-icon>
|
|
203
|
+
<devtools-link class="link" @click=${openIssueEvent}>${i18nString(UIStrings.viewIssue)}</devtools-link>
|
|
204
|
+
<span>${elementIssueDetails.tooltip}</span>
|
|
205
|
+
</div>`;
|
|
206
|
+
})}
|
|
207
|
+
</div>`, popover.contentElement);
|
|
208
|
+
// clang-format on
|
|
209
|
+
return true;
|
|
210
|
+
},
|
|
211
|
+
};
|
|
212
|
+
}, 'elements.issue');
|
|
213
|
+
popupHelper.setTimeout(300);
|
|
214
|
+
target.appendChild(elementsTreeOutline.element);
|
|
150
215
|
}
|
|
151
216
|
|
|
152
217
|
output.elementsTreeOutline.maxTreeDepth = input.maxTreeDepth;
|
|
153
218
|
output.elementsTreeOutline.enableContextMenu = input.enableContextMenu ?? true;
|
|
154
|
-
output.elementsTreeOutline.
|
|
219
|
+
output.elementsTreeOutline.showContextMenu = (treeElement, event) => {
|
|
220
|
+
void showContextMenu(treeElement, event, input.onSaveNodeToTempVariable);
|
|
221
|
+
};
|
|
222
|
+
let needsUpdate = false;
|
|
223
|
+
const showComments = input.showComments ?? true;
|
|
224
|
+
if (output.elementsTreeOutline.showComments !== showComments) {
|
|
225
|
+
output.elementsTreeOutline.showComments = showComments;
|
|
226
|
+
needsUpdate = true;
|
|
227
|
+
}
|
|
155
228
|
output.elementsTreeOutline.showAIButton = input.showAIButton ?? true;
|
|
156
229
|
output.elementsTreeOutline.disableEdits = input.disableEdits ?? false;
|
|
157
230
|
output.elementsTreeOutline.expandRoot = input.expandRoot ?? false;
|
|
@@ -161,6 +234,9 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
|
|
|
161
234
|
}
|
|
162
235
|
if (input.visible !== undefined) {
|
|
163
236
|
output.elementsTreeOutline.setVisible(input.visible);
|
|
237
|
+
if (!input.visible) {
|
|
238
|
+
output.imagePreviewPopover?.hide();
|
|
239
|
+
}
|
|
164
240
|
}
|
|
165
241
|
output.elementsTreeOutline.maxRowsShown = input.maxRowsShown;
|
|
166
242
|
output.elementsTreeOutline.setWordWrap(input.wrap);
|
|
@@ -168,6 +244,9 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
|
|
|
168
244
|
if (input.deindentSingleNode) {
|
|
169
245
|
output.elementsTreeOutline.deindentSingleNode();
|
|
170
246
|
}
|
|
247
|
+
if (needsUpdate) {
|
|
248
|
+
output.elementsTreeOutline.update();
|
|
249
|
+
}
|
|
171
250
|
// Node highlighting logic. FIXME: express as a lit template.
|
|
172
251
|
const previousHighlightedNode = output.highlightedTreeElement?.node() ?? null;
|
|
173
252
|
if (previousHighlightedNode !== input.currentHighlightedNode) {
|
|
@@ -238,7 +317,8 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
238
317
|
|
|
239
318
|
#maxTreeDepth?: number;
|
|
240
319
|
#enableContextMenu = true;
|
|
241
|
-
#
|
|
320
|
+
#showHTMLCommentsSetting = Common.Settings.Settings.instance().moduleSetting('show-html-comments');
|
|
321
|
+
#showComments = this.#showHTMLCommentsSetting.get();
|
|
242
322
|
#showAIButton = true;
|
|
243
323
|
#disableEdits = false;
|
|
244
324
|
#expandRoot = false;
|
|
@@ -346,6 +426,7 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
346
426
|
delegatesFocus: false,
|
|
347
427
|
});
|
|
348
428
|
this.#view = view ?? DEFAULT_VIEW;
|
|
429
|
+
this.#showHTMLCommentsSetting.addChangeListener(this.#onShowHTMLCommentsChange, this);
|
|
349
430
|
if (Common.Settings.Settings.instance().moduleSetting('highlight-node-on-hover-in-overlay').get()) {
|
|
350
431
|
SDK.TargetManager.TargetManager.instance().addModelListener(
|
|
351
432
|
SDK.OverlayModel.OverlayModel, SDK.OverlayModel.Events.HIGHLIGHT_NODE_REQUESTED, this.#highlightNode, this,
|
|
@@ -356,6 +437,15 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
356
437
|
}
|
|
357
438
|
}
|
|
358
439
|
|
|
440
|
+
#onShowHTMLCommentsChange(): void {
|
|
441
|
+
this.#showComments = this.#showHTMLCommentsSetting.get();
|
|
442
|
+
const selectedNode = this.selectedDOMNode();
|
|
443
|
+
if (selectedNode && selectedNode.nodeType() === Node.COMMENT_NODE && !this.#showComments) {
|
|
444
|
+
this.selectDOMNode(selectedNode.parentNode);
|
|
445
|
+
}
|
|
446
|
+
this.performUpdate();
|
|
447
|
+
}
|
|
448
|
+
|
|
359
449
|
#highlightNode(event: Common.EventTarget.EventTargetEvent<SDK.DOMModel.DOMNode>): void {
|
|
360
450
|
void this.#highlightThrottler.schedule(() => {
|
|
361
451
|
this.#currentHighlightedNode = event.data;
|
|
@@ -425,40 +515,42 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
425
515
|
|
|
426
516
|
override performUpdate(): void {
|
|
427
517
|
const firstRender = !this.#viewOutput.elementsTreeOutline;
|
|
428
|
-
this.#view(
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
518
|
+
this.#view({
|
|
519
|
+
omitRootDOMNode: this.omitRootDOMNode,
|
|
520
|
+
selectEnabled: this.selectEnabled,
|
|
521
|
+
hideGutter: this.hideGutter,
|
|
522
|
+
maxTreeDepth: this.#maxTreeDepth,
|
|
523
|
+
enableContextMenu: this.#enableContextMenu,
|
|
524
|
+
showComments: this.#showComments,
|
|
525
|
+
showAIButton: this.#showAIButton,
|
|
526
|
+
disableEdits: this.#disableEdits,
|
|
527
|
+
expandRoot: this.#expandRoot,
|
|
528
|
+
visibleWidth: this.#visibleWidth,
|
|
529
|
+
visible: this.#visible,
|
|
530
|
+
wrap: this.#wrap,
|
|
531
|
+
maxRowsShown: this.#maxRows,
|
|
532
|
+
showSelectionOnKeyboardFocus: this.showSelectionOnKeyboardFocus,
|
|
533
|
+
preventTabOrder: this.preventTabOrder,
|
|
534
|
+
deindentSingleNode: this.deindentSingleNode,
|
|
535
|
+
|
|
536
|
+
currentHighlightedNode: this.#currentHighlightedNode,
|
|
537
|
+
selectedNode: this.selectedDOMNode(),
|
|
538
|
+
onElementsTreeUpdated: this.onElementsTreeUpdated.bind(this),
|
|
539
|
+
onSelectedNodeChanged: event => {
|
|
540
|
+
this.#clearHighlightedNode();
|
|
541
|
+
this.onSelectedNodeChanged(event);
|
|
542
|
+
},
|
|
543
|
+
onElementCollapsed: () => {
|
|
544
|
+
this.#clearHighlightedNode();
|
|
545
|
+
},
|
|
546
|
+
onElementExpanded: () => {
|
|
547
|
+
this.#clearHighlightedNode();
|
|
548
|
+
},
|
|
549
|
+
onSaveNodeToTempVariable: node => {
|
|
550
|
+
void this.saveNodeToTempVariable(node);
|
|
551
|
+
},
|
|
552
|
+
},
|
|
553
|
+
this.#viewOutput, this.contentElement);
|
|
462
554
|
if (firstRender && this.#viewOutput.elementsTreeOutline) {
|
|
463
555
|
this.#viewOutput.elementsTreeOutline.addEventListener(ElementsTreeOutline.Events.ShowAllRows, () => {
|
|
464
556
|
this.maxRows = undefined;
|
|
@@ -529,7 +621,11 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
529
621
|
}
|
|
530
622
|
|
|
531
623
|
toggleHideElement(node: SDK.DOMModel.DOMNode): void {
|
|
532
|
-
void
|
|
624
|
+
void node.toggleHideElement();
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
isToggledToHidden(node: SDK.DOMModel.DOMNode): boolean {
|
|
628
|
+
return node.isToggledToHidden();
|
|
533
629
|
}
|
|
534
630
|
|
|
535
631
|
toggleEditAsHTML(node: SDK.DOMModel.DOMNode): void {
|
|
@@ -537,13 +633,17 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
537
633
|
}
|
|
538
634
|
|
|
539
635
|
duplicateNode(node: SDK.DOMModel.DOMNode): void {
|
|
540
|
-
|
|
636
|
+
node.duplicate();
|
|
541
637
|
}
|
|
542
638
|
|
|
543
639
|
copyStyles(node: SDK.DOMModel.DOMNode): void {
|
|
544
640
|
void this.#viewOutput.elementsTreeOutline?.findTreeElement(node)?.copyStyles();
|
|
545
641
|
}
|
|
546
642
|
|
|
643
|
+
async saveNodeToTempVariable(node: SDK.DOMModel.DOMNode): Promise<void> {
|
|
644
|
+
await this.#viewOutput.elementsTreeOutline?.saveNodeToTempVariable(node);
|
|
645
|
+
}
|
|
646
|
+
|
|
547
647
|
/**
|
|
548
648
|
* FIXME: used to determine focus state, probably we can have a better
|
|
549
649
|
* way to do it.
|
|
@@ -563,9 +663,18 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
563
663
|
this.performUpdate();
|
|
564
664
|
}
|
|
565
665
|
|
|
666
|
+
override wasHidden(): void {
|
|
667
|
+
super.wasHidden();
|
|
668
|
+
this.#visible = false;
|
|
669
|
+
this.#viewOutput.imagePreviewPopover?.hide();
|
|
670
|
+
this.performUpdate();
|
|
671
|
+
}
|
|
672
|
+
|
|
566
673
|
override detach(overrideHideOnDetach?: boolean): void {
|
|
567
674
|
super.detach(overrideHideOnDetach);
|
|
568
675
|
this.#visible = false;
|
|
676
|
+
this.#showHTMLCommentsSetting.removeChangeListener(this.#onShowHTMLCommentsChange, this);
|
|
677
|
+
this.#viewOutput.imagePreviewPopover?.hide();
|
|
569
678
|
this.performUpdate();
|
|
570
679
|
}
|
|
571
680
|
|
|
@@ -600,11 +709,9 @@ export class ElementsTreeOutline extends
|
|
|
600
709
|
private rootDOMNodeInternal: SDK.DOMModel.DOMNode|null;
|
|
601
710
|
selectedDOMNodeInternal: SDK.DOMModel.DOMNode|null;
|
|
602
711
|
private visible: boolean;
|
|
603
|
-
private readonly imagePreviewPopover: ImagePreviewPopover;
|
|
604
712
|
private updateRecords: Map<SDK.DOMModel.DOMNode, Elements.ElementUpdateRecord.ElementUpdateRecord>;
|
|
605
713
|
private treeElementsBeingUpdated: Set<ElementsTreeElement>;
|
|
606
714
|
decoratorExtensions: MarkerDecoratorRegistration[]|null;
|
|
607
|
-
private showHTMLCommentsSetting: Common.Settings.Setting<boolean>;
|
|
608
715
|
private multilineEditing?: MultilineEditorController|null;
|
|
609
716
|
private visibleWidthInternal?: number;
|
|
610
717
|
private clipboardNodeData?: ClipboardData;
|
|
@@ -616,7 +723,6 @@ export class ElementsTreeOutline extends
|
|
|
616
723
|
private updateModifiedNodesTimeout?: number;
|
|
617
724
|
#topLayerContainerByDocument = new WeakMap<SDK.DOMModel.DOMDocument, TopLayerContainer>();
|
|
618
725
|
#issuesManager?: IssuesManager.IssuesManager.IssuesManager;
|
|
619
|
-
#popupHelper?: UI.PopoverHelper.PopoverHelper;
|
|
620
726
|
#nodeElementToIssues = new Map<Element, IssuesManager.Issue.Issue[]>();
|
|
621
727
|
maxTreeDepth?: number;
|
|
622
728
|
enableContextMenu: boolean;
|
|
@@ -671,9 +777,6 @@ export class ElementsTreeOutline extends
|
|
|
671
777
|
this.elementInternal.addEventListener('clipboard-cut', this.onCopyOrCut.bind(this, true), false);
|
|
672
778
|
this.elementInternal.addEventListener('clipboard-paste', this.onPaste.bind(this), false);
|
|
673
779
|
}
|
|
674
|
-
if (this.enableContextMenu) {
|
|
675
|
-
this.elementInternal.addEventListener('contextmenu', this.contextMenuEventFired.bind(this), false);
|
|
676
|
-
}
|
|
677
780
|
|
|
678
781
|
outlineDisclosureElement.appendChild(this.elementInternal);
|
|
679
782
|
this.element = shadowContainer;
|
|
@@ -686,82 +789,11 @@ export class ElementsTreeOutline extends
|
|
|
686
789
|
|
|
687
790
|
this.visible = false;
|
|
688
791
|
|
|
689
|
-
this.imagePreviewPopover = new ImagePreviewPopover(
|
|
690
|
-
this.contentElement,
|
|
691
|
-
event => {
|
|
692
|
-
let link: (Element|null) = (event.target as Element | null);
|
|
693
|
-
while (link && !ImagePreviewPopover.getImageURL(link)) {
|
|
694
|
-
link = link.parentElementOrShadowHost();
|
|
695
|
-
}
|
|
696
|
-
return link;
|
|
697
|
-
},
|
|
698
|
-
async link => {
|
|
699
|
-
const listItem = UI.UIUtils.enclosingNodeOrSelfWithNodeName(link, 'li');
|
|
700
|
-
if (!listItem) {
|
|
701
|
-
return undefined;
|
|
702
|
-
}
|
|
703
|
-
|
|
704
|
-
const treeElement =
|
|
705
|
-
(UI.TreeOutline.TreeElement.getTreeElementBylistItemNode(listItem) as ElementsTreeElement | undefined);
|
|
706
|
-
return await UIComponentUtils.ImagePreview.loadPrecomputedFeatures(treeElement?.node());
|
|
707
|
-
});
|
|
708
|
-
|
|
709
792
|
this.updateRecords = new Map();
|
|
710
793
|
this.treeElementsBeingUpdated = new Set();
|
|
711
794
|
|
|
712
795
|
this.decoratorExtensions = null;
|
|
713
|
-
if (this.showComments) {
|
|
714
|
-
this.showHTMLCommentsSetting = Common.Settings.Settings.instance().moduleSetting('show-html-comments');
|
|
715
|
-
this.showHTMLCommentsSetting.addChangeListener(this.onShowHTMLCommentsChange.bind(this));
|
|
716
|
-
} else {
|
|
717
|
-
this.showHTMLCommentsSetting = {
|
|
718
|
-
get: () => false,
|
|
719
|
-
addChangeListener: () => {},
|
|
720
|
-
removeChangeListener: () => {},
|
|
721
|
-
} as unknown as Common.Settings.Setting<boolean>;
|
|
722
|
-
}
|
|
723
796
|
this.setUseLightSelectionColor(true);
|
|
724
|
-
// TODO(changhaohan): refactor the popover to use tooltip component.
|
|
725
|
-
this.#popupHelper = new UI.PopoverHelper.PopoverHelper(this.elementInternal, event => {
|
|
726
|
-
const hoveredNode = event.composedPath()[0] as Element;
|
|
727
|
-
if (!hoveredNode?.matches('.violating-element')) {
|
|
728
|
-
return null;
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
const issues = this.#nodeElementToIssues.get(hoveredNode);
|
|
732
|
-
if (!issues) {
|
|
733
|
-
return null;
|
|
734
|
-
}
|
|
735
|
-
|
|
736
|
-
return {
|
|
737
|
-
box: hoveredNode.boxInWindow(),
|
|
738
|
-
show: async (popover: UI.GlassPane.GlassPane) => {
|
|
739
|
-
popover.setIgnoreLeftMargin(true);
|
|
740
|
-
// clang-format off
|
|
741
|
-
render(html`
|
|
742
|
-
<div class="squiggles-content">
|
|
743
|
-
${issues.map(issue => {
|
|
744
|
-
const elementIssueDetails = getElementIssueDetails(issue);
|
|
745
|
-
if (!elementIssueDetails) {
|
|
746
|
-
// This shouldn't happen, but add this if check to pass ts check.
|
|
747
|
-
return nothing;
|
|
748
|
-
}
|
|
749
|
-
const issueKindIconName = IssueCounter.IssueCounter.getIssueKindIconName(issue.getKind());
|
|
750
|
-
const openIssueEvent = (): Promise<void> => Common.Revealer.reveal(issue);
|
|
751
|
-
return html`
|
|
752
|
-
<div class="squiggles-content-item">
|
|
753
|
-
<devtools-icon .name=${issueKindIconName} @click=${openIssueEvent}></devtools-icon>
|
|
754
|
-
<devtools-link class="link" @click=${openIssueEvent}>${i18nString(UIStrings.viewIssue)}</devtools-link>
|
|
755
|
-
<span>${elementIssueDetails.tooltip}</span>
|
|
756
|
-
</div>`;
|
|
757
|
-
})}
|
|
758
|
-
</div>`, popover.contentElement);
|
|
759
|
-
// clang-format on
|
|
760
|
-
return true;
|
|
761
|
-
},
|
|
762
|
-
};
|
|
763
|
-
}, 'elements.issue');
|
|
764
|
-
this.#popupHelper.setTimeout(300);
|
|
765
797
|
}
|
|
766
798
|
|
|
767
799
|
static forDOMModel(domModel: SDK.DOMModel.DOMModel): ElementsTreeOutline|null {
|
|
@@ -863,12 +895,8 @@ export class ElementsTreeOutline extends
|
|
|
863
895
|
this.#nodeElementToIssues.set(element, issues);
|
|
864
896
|
}
|
|
865
897
|
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
if (selectedNode && selectedNode.nodeType() === Node.COMMENT_NODE && !this.showHTMLCommentsSetting.get()) {
|
|
869
|
-
this.selectDOMNode(selectedNode.parentNode);
|
|
870
|
-
}
|
|
871
|
-
this.update();
|
|
898
|
+
issuesByNodeElement(element: Element): IssuesManager.Issue.Issue[]|undefined {
|
|
899
|
+
return this.#nodeElementToIssues.get(element);
|
|
872
900
|
}
|
|
873
901
|
|
|
874
902
|
setWordWrap(wrap: boolean): void {
|
|
@@ -993,7 +1021,7 @@ export class ElementsTreeOutline extends
|
|
|
993
1021
|
}
|
|
994
1022
|
|
|
995
1023
|
duplicateNode(targetNode: SDK.DOMModel.DOMNode): void {
|
|
996
|
-
|
|
1024
|
+
targetNode.duplicate();
|
|
997
1025
|
}
|
|
998
1026
|
|
|
999
1027
|
private onPaste(event: Event): void {
|
|
@@ -1031,26 +1059,12 @@ export class ElementsTreeOutline extends
|
|
|
1031
1059
|
}
|
|
1032
1060
|
}
|
|
1033
1061
|
|
|
1034
|
-
private performDuplicate(targetNode: SDK.DOMModel.DOMNode): void {
|
|
1035
|
-
if (targetNode.isInShadowTree()) {
|
|
1036
|
-
return;
|
|
1037
|
-
}
|
|
1038
|
-
|
|
1039
|
-
const parentNode = targetNode.parentNode ? targetNode.parentNode : targetNode;
|
|
1040
|
-
if (parentNode.nodeName() === '#document') {
|
|
1041
|
-
return;
|
|
1042
|
-
}
|
|
1043
|
-
|
|
1044
|
-
targetNode.copyTo(parentNode, targetNode.nextSibling);
|
|
1045
|
-
}
|
|
1046
|
-
|
|
1047
1062
|
setVisible(visible: boolean): void {
|
|
1048
1063
|
if (visible === this.visible) {
|
|
1049
1064
|
return;
|
|
1050
1065
|
}
|
|
1051
1066
|
this.visible = visible;
|
|
1052
1067
|
if (!this.visible) {
|
|
1053
|
-
this.imagePreviewPopover.hide();
|
|
1054
1068
|
if (this.multilineEditing) {
|
|
1055
1069
|
this.multilineEditing.cancel();
|
|
1056
1070
|
}
|
|
@@ -1534,60 +1548,9 @@ export class ElementsTreeOutline extends
|
|
|
1534
1548
|
}
|
|
1535
1549
|
}
|
|
1536
1550
|
|
|
1537
|
-
|
|
1538
|
-
const treeElement = this.treeElementFromEventInternal(event);
|
|
1539
|
-
if (treeElement instanceof ElementsTreeElement) {
|
|
1540
|
-
void this.showContextMenu(treeElement, event);
|
|
1541
|
-
}
|
|
1542
|
-
}
|
|
1543
|
-
|
|
1544
|
-
async showContextMenu(treeElement: ElementsTreeElement, event: Event): Promise<void> {
|
|
1545
|
-
if (UI.UIUtils.isEditing() || !this.enableContextMenu) {
|
|
1546
|
-
return;
|
|
1547
|
-
}
|
|
1548
|
-
|
|
1549
|
-
const node = (event.target as Node | null);
|
|
1550
|
-
if (!node) {
|
|
1551
|
-
return;
|
|
1552
|
-
}
|
|
1553
|
-
|
|
1554
|
-
// The context menu construction may be async. In order to
|
|
1555
|
-
// make sure that no other (default) context menu shows up, we need
|
|
1556
|
-
// to stop propagating and prevent the default action.
|
|
1557
|
-
event.stopPropagation();
|
|
1558
|
-
event.preventDefault();
|
|
1559
|
-
|
|
1560
|
-
const contextMenu = new UI.ContextMenu.ContextMenu(event);
|
|
1561
|
-
const isPseudoElement = Boolean(treeElement.node().pseudoType());
|
|
1562
|
-
const isTag = treeElement.node().nodeType() === Node.ELEMENT_NODE && !isPseudoElement;
|
|
1563
|
-
|
|
1564
|
-
let textNode: Element|null = node.enclosingNodeOrSelfWithClass('webkit-html-text-node');
|
|
1565
|
-
if (textNode?.classList.contains('bogus')) {
|
|
1566
|
-
textNode = null;
|
|
1567
|
-
}
|
|
1568
|
-
const commentNode = node.enclosingNodeOrSelfWithClass('webkit-html-comment');
|
|
1569
|
-
contextMenu.saveSection().appendItem(
|
|
1570
|
-
i18nString(UIStrings.storeAsGlobalVariable), this.saveNodeToTempVariable.bind(this, treeElement.node()),
|
|
1571
|
-
{jslogContext: 'store-as-global-variable'});
|
|
1572
|
-
if (textNode) {
|
|
1573
|
-
await treeElement.populateTextContextMenu(contextMenu, textNode);
|
|
1574
|
-
} else if (isTag) {
|
|
1575
|
-
await treeElement.populateTagContextMenu(contextMenu, event);
|
|
1576
|
-
} else if (commentNode) {
|
|
1577
|
-
await treeElement.populateNodeContextMenu(contextMenu);
|
|
1578
|
-
} else if (isPseudoElement) {
|
|
1579
|
-
treeElement.populatePseudoElementContextMenu(contextMenu);
|
|
1580
|
-
} else if (treeElement.node().nodeType() === Node.PROCESSING_INSTRUCTION_NODE) {
|
|
1581
|
-
await treeElement.populateProcessingElementContextMenu(contextMenu);
|
|
1582
|
-
}
|
|
1583
|
-
|
|
1584
|
-
ElementsPanel.instance().populateAdornerSettingsContextMenu(contextMenu);
|
|
1551
|
+
showContextMenu: (treeElement: ElementsTreeElement, event: Event) => void = () => {};
|
|
1585
1552
|
|
|
1586
|
-
|
|
1587
|
-
void contextMenu.show();
|
|
1588
|
-
}
|
|
1589
|
-
|
|
1590
|
-
private async saveNodeToTempVariable(node: SDK.DOMModel.DOMNode): Promise<void> {
|
|
1553
|
+
async saveNodeToTempVariable(node: SDK.DOMModel.DOMNode): Promise<void> {
|
|
1591
1554
|
const remoteObjectForConsole = await node.resolveToObject();
|
|
1592
1555
|
const consoleModel = remoteObjectForConsole?.runtimeModel().target()?.model(SDK.ConsoleModel.ConsoleModel);
|
|
1593
1556
|
await consoleModel?.saveToTempVariable(
|
|
@@ -1701,94 +1664,17 @@ export class ElementsTreeOutline extends
|
|
|
1701
1664
|
return newTreeItem;
|
|
1702
1665
|
}
|
|
1703
1666
|
|
|
1704
|
-
/**
|
|
1705
|
-
* Runs a script on the node's remote object that toggles a class name on
|
|
1706
|
-
* the node and injects a stylesheet into the head of the node's document
|
|
1707
|
-
* containing a rule to set "visibility: hidden" on the class and all it's
|
|
1708
|
-
* ancestors.
|
|
1709
|
-
*/
|
|
1710
1667
|
async toggleHideElement(node: SDK.DOMModel.DOMNode): Promise<void> {
|
|
1711
|
-
|
|
1712
|
-
if (pseudoElementName && node.pseudoIdentifier()) {
|
|
1713
|
-
pseudoElementName += `(${node.pseudoIdentifier()})`;
|
|
1714
|
-
}
|
|
1715
|
-
|
|
1716
|
-
let effectiveNode: SDK.DOMModel.DOMNode|null = node;
|
|
1717
|
-
while (effectiveNode?.pseudoType()) {
|
|
1718
|
-
if (effectiveNode !== node && effectiveNode.pseudoType() === 'column') {
|
|
1719
|
-
// Ideally we would select the specific column pseudo element, but
|
|
1720
|
-
// we don't have a way to do that at the moment.
|
|
1721
|
-
pseudoElementName = '::column' + pseudoElementName;
|
|
1722
|
-
}
|
|
1723
|
-
effectiveNode = effectiveNode.parentNode;
|
|
1724
|
-
}
|
|
1725
|
-
if (!effectiveNode) {
|
|
1726
|
-
return;
|
|
1727
|
-
}
|
|
1728
|
-
|
|
1729
|
-
const hidden = node.marker('hidden-marker');
|
|
1730
|
-
const object = await effectiveNode.resolveToObject('');
|
|
1731
|
-
|
|
1732
|
-
if (!object) {
|
|
1733
|
-
return;
|
|
1734
|
-
}
|
|
1735
|
-
|
|
1736
|
-
await object.callFunction(
|
|
1737
|
-
(toggleClassAndInjectStyleRule as (this: Object, ...arg1: unknown[]) => void),
|
|
1738
|
-
[{value: pseudoElementName}, {value: !hidden}]);
|
|
1739
|
-
object.release();
|
|
1740
|
-
node.setMarker('hidden-marker', hidden ? null : true);
|
|
1741
|
-
|
|
1742
|
-
function toggleClassAndInjectStyleRule(this: Element, pseudoElementName: string|null, hidden: boolean): void {
|
|
1743
|
-
const classNamePrefix = '__web-inspector-hide';
|
|
1744
|
-
const classNameSuffix = '-shortcut__';
|
|
1745
|
-
const styleTagId = '__web-inspector-hide-shortcut-style__';
|
|
1746
|
-
const pseudoElementNameEscaped = pseudoElementName ? pseudoElementName.replace(/[\(\)\:]/g, '_') : '';
|
|
1747
|
-
const className = classNamePrefix + pseudoElementNameEscaped + classNameSuffix;
|
|
1748
|
-
this.classList.toggle(className, hidden);
|
|
1749
|
-
|
|
1750
|
-
let localRoot: Element|HTMLHeadElement = this;
|
|
1751
|
-
while (localRoot.parentNode) {
|
|
1752
|
-
localRoot = (localRoot.parentNode as Element);
|
|
1753
|
-
}
|
|
1754
|
-
if (localRoot.nodeType === Node.DOCUMENT_NODE) {
|
|
1755
|
-
localRoot = document.head;
|
|
1756
|
-
}
|
|
1757
|
-
|
|
1758
|
-
let style = localRoot.querySelector('style#' + styleTagId);
|
|
1759
|
-
if (!style) {
|
|
1760
|
-
const selectors = [];
|
|
1761
|
-
selectors.push('.__web-inspector-hide-shortcut__');
|
|
1762
|
-
selectors.push('.__web-inspector-hide-shortcut__ *');
|
|
1763
|
-
const selector = selectors.join(', ');
|
|
1764
|
-
const ruleBody = ' visibility: hidden !important;';
|
|
1765
|
-
const rule = '\n' + selector + '\n{\n' + ruleBody + '\n}\n';
|
|
1766
|
-
|
|
1767
|
-
style = document.createElement('style');
|
|
1768
|
-
style.id = styleTagId;
|
|
1769
|
-
style.textContent = rule;
|
|
1770
|
-
|
|
1771
|
-
localRoot.appendChild(style);
|
|
1772
|
-
}
|
|
1773
|
-
|
|
1774
|
-
// In addition to putting them on the element we want to hide, we will
|
|
1775
|
-
// also add pseudo element classes to the style element to keep track of
|
|
1776
|
-
// which pseudo elements we have style rules for.
|
|
1777
|
-
if (pseudoElementName && !style.classList.contains(className)) {
|
|
1778
|
-
style.classList.add(className);
|
|
1779
|
-
style.textContent = `.${className}${pseudoElementName}, ${style.textContent}`;
|
|
1780
|
-
}
|
|
1781
|
-
}
|
|
1668
|
+
await node.toggleHideElement();
|
|
1782
1669
|
}
|
|
1783
1670
|
|
|
1784
1671
|
isToggledToHidden(node: SDK.DOMModel.DOMNode): boolean {
|
|
1785
|
-
return
|
|
1672
|
+
return node.isToggledToHidden();
|
|
1786
1673
|
}
|
|
1787
1674
|
|
|
1788
1675
|
private reset(): void {
|
|
1789
1676
|
this.rootDOMNode = null;
|
|
1790
1677
|
this.selectDOMNode(null, false);
|
|
1791
|
-
this.imagePreviewPopover.hide();
|
|
1792
1678
|
delete this.clipboardNodeData;
|
|
1793
1679
|
SDK.OverlayModel.OverlayModel.hideDOMNodeHighlight(SDK.TargetManager.TargetManager.instance());
|
|
1794
1680
|
this.updateRecords.clear();
|
|
@@ -2117,7 +2003,7 @@ export class ElementsTreeOutline extends
|
|
|
2117
2003
|
if (node.childNodeCount()) {
|
|
2118
2004
|
// Children may be stale when the outline is not wired to receive DOMModel updates.
|
|
2119
2005
|
let children: SDK.DOMModel.DOMNode[] = node.children() || [];
|
|
2120
|
-
if (!this.
|
|
2006
|
+
if (!this.showComments) {
|
|
2121
2007
|
children = children.filter(n => n.nodeType() !== Node.COMMENT_NODE);
|
|
2122
2008
|
}
|
|
2123
2009
|
visibleChildren.push(...children);
|
|
@@ -1562,7 +1562,8 @@ export class StylesSidebarPane extends Common.ObjectWrapper.eventMixin<EventType
|
|
|
1562
1562
|
private createRenderingShortcuts(): UI.Toolbar.ToolbarButton {
|
|
1563
1563
|
const prefersColorSchemeSetting = Common.Settings.Settings.instance().resolve(
|
|
1564
1564
|
SDK.SDKSettings.emulatedCSSMediaFeaturePrefersColorSchemeSettingDescriptor);
|
|
1565
|
-
const autoDarkModeSetting =
|
|
1565
|
+
const autoDarkModeSetting =
|
|
1566
|
+
Common.Settings.Settings.instance().resolve(SDK.SDKSettings.emulateAutoDarkModeSettingDescriptor);
|
|
1566
1567
|
const decorateStatus = (condition: boolean, title: string): string => `${condition ? '✓ ' : ''}${title}`;
|
|
1567
1568
|
|
|
1568
1569
|
const button = new UI.Toolbar.ToolbarToggle(
|