chrome-devtools-frontend 1.0.1697595 → 1.0.1698733
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/.agents/skills/version-control/SKILL.md +21 -9
- package/.stylelintignore +2 -0
- package/front_end/core/common/VersionController.ts +5 -1
- package/front_end/core/platform/HostRuntime.ts +12 -0
- package/front_end/core/platform/api/HostRuntime.ts +13 -0
- package/front_end/core/platform/browser/HostRuntime.ts +34 -0
- package/front_end/core/platform/node/HostRuntime.ts +40 -0
- package/front_end/core/sdk/AnimationModel.ts +21 -99
- package/front_end/core/sdk/CSSModel.ts +4 -2
- package/front_end/core/sdk/CSSPropertyParser.ts +4 -4
- package/front_end/core/sdk/CSSPropertyParserMatchers.ts +4 -44
- package/front_end/core/sdk/Connections.ts +6 -1
- package/front_end/core/sdk/ConsoleModel.ts +1 -12
- package/front_end/core/sdk/DOMModel.ts +3 -51
- package/front_end/core/sdk/DebuggerModel.ts +9 -8
- package/front_end/core/sdk/NetworkRequest.ts +1 -1
- package/front_end/core/sdk/PageFunctions.ts +187 -0
- package/front_end/core/sdk/Resource.ts +1 -1
- package/front_end/core/sdk/RuntimeModel.ts +1 -20
- package/front_end/core/sdk/Script.ts +21 -0
- package/front_end/core/sdk/SourceMap.ts +15 -2
- package/front_end/core/sdk/SourceMapCache.ts +13 -10
- package/front_end/core/sdk/SourceMapManager.ts +11 -9
- package/front_end/core/sdk/SourceMapScopeChainEntry.ts +59 -17
- package/front_end/core/sdk/SourceMapScopesInfo.ts +8 -2
- package/front_end/entrypoints/heap_snapshot_worker/ContextAnalyzer.ts +635 -0
- package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshot.ts +26 -12
- package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshotLoader.ts +16 -2
- package/front_end/entrypoints/heap_snapshot_worker/HeapSnapshotWorkerDispatcher.ts +4 -4
- package/front_end/entrypoints/heap_snapshot_worker/heap_snapshot_worker.ts +2 -0
- package/front_end/entrypoints/shell/shell.ts +1 -1
- package/front_end/generated/InspectorBackendCommands.ts +1 -1
- package/front_end/generated/protocol.ts +8 -2
- package/front_end/models/ai_assistance/DOMHelpers.ts +95 -0
- package/front_end/models/ai_assistance/EvaluateAction.ts +5 -42
- package/front_end/models/ai_assistance/ExtensionScope.ts +2 -31
- package/front_end/models/ai_assistance/agents/AiAgent.ts +2 -1
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +27 -2
- package/front_end/models/ai_assistance/ai_assistance.ts +6 -4
- package/front_end/models/ai_assistance/contexts/DOMNodeContext.ts +10 -7
- package/front_end/models/ai_assistance/contexts/FileContext.ts +2 -10
- package/front_end/models/ai_assistance/skills/performance.md +4 -3
- package/front_end/models/ai_assistance/tools/GetSourceContent.ts +3 -2
- package/front_end/models/ai_assistance/tools/{GetFunctionCode.ts → GetTraceFunctionCode.ts} +26 -13
- package/front_end/models/ai_assistance/tools/{GetResourceContent.ts → GetTraceResourceContent.ts} +31 -11
- package/front_end/models/ai_assistance/tools/ListSources.ts +21 -14
- package/front_end/models/ai_assistance/tools/Tool.ts +2 -2
- package/front_end/models/ai_assistance/tools/ToolRegistry.ts +6 -6
- package/front_end/models/bindings/CompilerScriptMapping.ts +3 -10
- package/front_end/models/bindings/DebuggerLanguagePlugins.ts +48 -17
- package/front_end/models/bindings/ResourceScriptMapping.ts +2 -2
- package/front_end/models/bindings/StylesSourceMapping.ts +1 -1
- package/front_end/models/comment_manager/CD4ABridge.ts +55 -12
- package/front_end/models/comment_manager/CommentManager.ts +46 -91
- package/front_end/models/comment_manager/CommentThread.ts +145 -0
- package/front_end/models/comment_manager/comment_manager.ts +2 -0
- package/front_end/models/elements/DOMChanges.ts +238 -0
- package/front_end/models/elements/elements.ts +2 -0
- package/front_end/models/emulation/DeviceModeModel.ts +53 -0
- package/front_end/models/extensions/ExtensionAPI.ts +8 -6
- package/front_end/models/extensions/ExtensionEndpoint.ts +11 -8
- package/front_end/models/extensions/HostUrlPattern.ts +4 -3
- package/front_end/models/extensions/LanguageExtensionEndpoint.ts +3 -2
- package/front_end/models/extensions/RecorderExtensionEndpoint.ts +2 -1
- package/front_end/models/formatter/FormatterWorkerPool.ts +4 -6
- package/front_end/models/heap_snapshot/HeapSnapshotModel.ts +55 -0
- package/front_end/models/heap_snapshot/HeapSnapshotProxy.ts +18 -14
- package/front_end/models/issues_manager/IssuesManager.ts +5 -0
- package/front_end/models/issues_manager/WebInstallIssue.ts +63 -0
- package/front_end/models/issues_manager/descriptions/webInstallManifestMissingId.md +3 -0
- package/front_end/models/issues_manager/descriptions/webInstallManifestMissingNameOrShortName.md +3 -0
- package/front_end/models/issues_manager/descriptions/webInstallManifestParsingOrNetworkError.md +3 -0
- package/front_end/models/issues_manager/descriptions/webInstallNoManifest.md +3 -0
- package/front_end/models/issues_manager/descriptions/webInstallStartUrlInvalid.md +3 -0
- package/front_end/models/issues_manager/issues_manager.ts +2 -0
- package/front_end/models/workspace/UISourceCode.ts +20 -0
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +7 -7
- package/front_end/panels/ai_assistance/components/AIv2MarkdownRenderer.ts +4 -10
- package/front_end/panels/ai_assistance/components/MarkdownRendererWithCodeBlock.ts +25 -5
- package/front_end/panels/browser_debugger/ObjectEventListenersSidebarPane.ts +2 -3
- package/front_end/panels/common/CommentThreadWidget.ts +221 -0
- package/front_end/{ui/comments → panels/common}/CommentsOverlayWidget.ts +117 -28
- package/front_end/{ui/comments → panels/common}/CommentsStatusBarPill.ts +5 -5
- package/front_end/panels/common/ExtensionServer.ts +2 -1
- package/front_end/panels/common/commentThreadWidget.css +173 -0
- package/front_end/{ui/comments → panels/common}/commentsOverlay.css +8 -1
- package/front_end/{ui/comments/comments-meta.ts → panels/common/common-meta.ts} +11 -11
- package/front_end/panels/common/common.ts +3 -0
- package/front_end/panels/elements/AdoptedStyleSheetTreeElement.ts +3 -3
- package/front_end/panels/elements/ElementsPanel.ts +5 -1
- package/front_end/panels/elements/ElementsTreeElement.ts +102 -21
- package/front_end/panels/elements/ElementsTreeOutline.ts +326 -91
- package/front_end/panels/elements/EventListenersWidget.ts +0 -1
- package/front_end/panels/elements/PropertiesWidget.ts +11 -10
- package/front_end/panels/elements/PropertyRenderer.ts +29 -25
- package/front_end/panels/elements/StylePropertyTreeElement.ts +6 -6
- package/front_end/panels/elements/elementsTreeOutline.css +7 -1
- package/front_end/panels/emulation/DeviceModeToolbar.ts +2 -3
- package/front_end/panels/event_listeners/EventListenersView.ts +235 -302
- package/front_end/panels/linear_memory_inspector/LinearMemoryInspectorController.ts +6 -7
- package/front_end/panels/linear_memory_inspector/components/linearMemoryInspector.css +5 -1
- package/front_end/panels/linear_memory_inspector/linear_memory_inspector-meta.ts +1 -1
- package/front_end/panels/mobile_throttling/ThrottlingSettingsTab.ts +10 -2
- package/front_end/panels/network/NetworkConfigView.ts +141 -116
- package/front_end/panels/network/NetworkPanel.ts +7 -4
- package/front_end/panels/network/RequestHeadersView.ts +1 -1
- package/front_end/panels/network/forward/BackendLinking.ts +5 -2
- package/front_end/panels/recorder/stepView.css +1 -0
- package/front_end/panels/security/SecurityPanel.ts +5 -5
- package/front_end/panels/security/SecurityPanelSidebar.ts +2 -11
- package/front_end/panels/settings/BackendLinkingSettingsTab.ts +7 -2
- package/front_end/panels/sources/DebuggerPlugin.ts +1 -1
- package/front_end/panels/sources/WatchExpressionsSidebarPane.ts +11 -16
- package/front_end/panels/sources/sources-meta.ts +1 -1
- package/front_end/panels/timeline/TimelineTreeView.ts +11 -1
- package/front_end/panels/timeline/overlays/OverlaysImpl.ts +0 -3
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/ui/comments/CommentOverlayManager.ts +89 -42
- package/front_end/ui/comments/comments.ts +0 -4
- package/front_end/ui/legacy/Treeoutline.ts +4 -0
- package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +15 -8
- package/front_end/ui/legacy/components/perf_ui/FlameChart.ts +4 -0
- package/front_end/ui/visual_logging/KnownContextValues.ts +1 -0
- package/package.json +5 -5
|
@@ -39,6 +39,7 @@ import * as Host from '../../core/host/host.js';
|
|
|
39
39
|
import * as i18n from '../../core/i18n/i18n.js';
|
|
40
40
|
import * as SDK from '../../core/sdk/sdk.js';
|
|
41
41
|
import * as Badges from '../../models/badges/badges.js';
|
|
42
|
+
import * as ChangeTracker from '../../models/change_tracker/change_tracker.js';
|
|
42
43
|
import * as Elements from '../../models/elements/elements.js';
|
|
43
44
|
import * as Buttons from '../../ui/components/buttons/buttons.js';
|
|
44
45
|
import * as CodeHighlighter from '../../ui/components/code_highlighter/code_highlighter.js';
|
|
@@ -60,6 +61,7 @@ import {showContextMenu} from './DOMTreeContextMenu.js';
|
|
|
60
61
|
import {getElementIssueDetails} from './ElementIssueUtils.js';
|
|
61
62
|
import {
|
|
62
63
|
adornerRef,
|
|
64
|
+
buildChangeSelector,
|
|
63
65
|
ElementsTreeElement,
|
|
64
66
|
ElementsTreeWidget,
|
|
65
67
|
ForbiddenClosingTagElements,
|
|
@@ -73,7 +75,7 @@ import {ImagePreviewPopover} from './ImagePreviewPopover.js';
|
|
|
73
75
|
import {ShortcutTreeElement} from './ShortcutTreeElement.js';
|
|
74
76
|
import {TopLayerContainer} from './TopLayerContainer.js';
|
|
75
77
|
|
|
76
|
-
const {html, nothing, render, Directives: {classMap, styleMap}} = Lit;
|
|
78
|
+
const {html, nothing, render, Directives: {classMap, repeat, styleMap}} = Lit;
|
|
77
79
|
|
|
78
80
|
const UIStrings = {
|
|
79
81
|
/**
|
|
@@ -148,7 +150,7 @@ interface ViewInput {
|
|
|
148
150
|
onClearMaxRows?: () => void;
|
|
149
151
|
onHoverNode?: (node: SDK.DOMModel.DOMNode|null, showInfo?: boolean, isClosingTag?: boolean) => void;
|
|
150
152
|
onLeave?: () => void;
|
|
151
|
-
onToggleHideElement?: (node: SDK.DOMModel.DOMNode) => void
|
|
153
|
+
onToggleHideElement?: (node: SDK.DOMModel.DOMNode) => Promise<void>;
|
|
152
154
|
onKeyDown?: (event: KeyboardEvent) => void;
|
|
153
155
|
isToggledToHidden?: (node: SDK.DOMModel.DOMNode) => boolean;
|
|
154
156
|
onDuplicateNode?: (node: SDK.DOMModel.DOMNode) => void;
|
|
@@ -521,6 +523,13 @@ export const DECLARATIVE_VIEW: View = (input: ViewInput, _output: ViewOutput, ta
|
|
|
521
523
|
}
|
|
522
524
|
|
|
523
525
|
const on = Lit.Directive.directive(Lit.CustomDirectives.InterceptBindingDirective);
|
|
526
|
+
const treeItemJslog = (context?: string, drag?: boolean): ReturnType<typeof VisualLogging.treeItem> =>
|
|
527
|
+
VisualLogging.treeItem(context).parent('elementsTreeOutline').track({
|
|
528
|
+
keydown: 'ArrowUp|ArrowDown|ArrowLeft|ArrowRight|Backspace|Delete|Enter|Space|Home|End',
|
|
529
|
+
resize: true,
|
|
530
|
+
...(drag ? {drag: true} : {}),
|
|
531
|
+
click: true,
|
|
532
|
+
});
|
|
524
533
|
|
|
525
534
|
const renderShortcut = (shortcut: SDK.DOMModel.DOMNodeShortcut, shortcutDepth: number): Lit.LitTemplate => {
|
|
526
535
|
const hasShortcutChildren = shortcut.childShortcuts.length > 0;
|
|
@@ -556,12 +565,11 @@ export const DECLARATIVE_VIEW: View = (input: ViewInput, _output: ViewOutput, ta
|
|
|
556
565
|
?open=${isShortcutExpanded}
|
|
557
566
|
class="elements-tree-shortcut"
|
|
558
567
|
style=${styleMap({'--indent': `${computeLeftIndent(shortcutDepth, hasShortcutChildren)}px`})}
|
|
559
|
-
@select=${onShortcutSelect}
|
|
560
|
-
@expand=${onShortcutExpand}
|
|
568
|
+
@select=${on(onShortcutSelect)}
|
|
569
|
+
@expand=${on(onShortcutExpand)}
|
|
561
570
|
@mousemove=${on(onShortcutMouseMove)}
|
|
562
571
|
@mouseleave=${on(onShortcutMouseLeave)}
|
|
563
|
-
jslog=${
|
|
564
|
-
<div class="selection fill"></div>
|
|
572
|
+
jslog=${treeItemJslog()}>
|
|
565
573
|
<span class="elements-tree-shortcut-title">\u21AA ${title}</span>
|
|
566
574
|
<devtools-adorner
|
|
567
575
|
.name=${ElementsComponents.AdornerManager.RegisteredAdorners.REVEAL}
|
|
@@ -581,9 +589,7 @@ export const DECLARATIVE_VIEW: View = (input: ViewInput, _output: ViewOutput, ta
|
|
|
581
589
|
</devtools-adorner>
|
|
582
590
|
${hasShortcutChildren ? html`
|
|
583
591
|
<ul role="group">
|
|
584
|
-
${
|
|
585
|
-
${shortcut.childShortcuts.map(child => renderShortcut(child, shortcutDepth + 1))}
|
|
586
|
-
`)}
|
|
592
|
+
${shortcut.childShortcuts.map(child => renderShortcut(child, shortcutDepth + 1))}
|
|
587
593
|
</ul>
|
|
588
594
|
` : nothing}
|
|
589
595
|
</li>
|
|
@@ -611,15 +617,12 @@ export const DECLARATIVE_VIEW: View = (input: ViewInput, _output: ViewOutput, ta
|
|
|
611
617
|
?open=${isTopLayerExpanded}
|
|
612
618
|
class="elements-tree-top-layer-container"
|
|
613
619
|
style=${styleMap({'--indent': `${computeLeftIndent(containerDepth, true)}px`})}
|
|
614
|
-
@select=${onTopLayerSelect}
|
|
615
|
-
@expand=${onTopLayerExpand}
|
|
616
|
-
jslog=${
|
|
617
|
-
<div class="selection fill"></div>
|
|
620
|
+
@select=${on(onTopLayerSelect)}
|
|
621
|
+
@expand=${on(onTopLayerExpand)}
|
|
622
|
+
jslog=${treeItemJslog()}>
|
|
618
623
|
<span class="elements-tree-shortcut-title">#top-layer</span>
|
|
619
624
|
<ul role="group">
|
|
620
|
-
${
|
|
621
|
-
${shortcuts.map(sc => renderShortcut(sc, containerDepth + 1))}
|
|
622
|
-
`)}
|
|
625
|
+
${shortcuts.map(sc => renderShortcut(sc, containerDepth + 1))}
|
|
623
626
|
</ul>
|
|
624
627
|
</li>
|
|
625
628
|
`;
|
|
@@ -645,10 +648,9 @@ export const DECLARATIVE_VIEW: View = (input: ViewInput, _output: ViewOutput, ta
|
|
|
645
648
|
?open=${isExpanded}
|
|
646
649
|
class="elements-tree-adopted-style-sheet"
|
|
647
650
|
style=${styleMap({'--indent': `${computeLeftIndent(depth, true)}px`})}
|
|
648
|
-
@select=${onSelect}
|
|
649
|
-
@expand=${onExpand}
|
|
650
|
-
jslog=${
|
|
651
|
-
<div class="selection fill"></div>
|
|
651
|
+
@select=${on(onSelect)}
|
|
652
|
+
@expand=${on(onExpand)}
|
|
653
|
+
jslog=${treeItemJslog('adopted-style-sheet')}>
|
|
652
654
|
<span class="elements-tree-shortcut-title">#adopted-style-sheet${linkText ? html` (${UIComponentUtils.Linkifier.Linkifier.linkifyURL(linkText, {
|
|
653
655
|
text: linkText,
|
|
654
656
|
preventClick: true,
|
|
@@ -660,8 +662,7 @@ export const DECLARATIVE_VIEW: View = (input: ViewInput, _output: ViewOutput, ta
|
|
|
660
662
|
<li role="treeitem"
|
|
661
663
|
class="elements-tree-adopted-style-sheet-contents"
|
|
662
664
|
style=${styleMap({'--indent': `${computeLeftIndent(depth + 1, false)}px`})}
|
|
663
|
-
jslog=${
|
|
664
|
-
<div class="selection fill"></div>
|
|
665
|
+
jslog=${treeItemJslog('adopted-style-sheet-contents')}>
|
|
665
666
|
${UI.Widget.widget(AdoptedStyleSheetContentsWidget, {styleSheetHeader: header})}
|
|
666
667
|
</li>
|
|
667
668
|
` : nothing}
|
|
@@ -691,10 +692,9 @@ export const DECLARATIVE_VIEW: View = (input: ViewInput, _output: ViewOutput, ta
|
|
|
691
692
|
?open=${isExpanded}
|
|
692
693
|
class="elements-tree-adopted-style-sheets"
|
|
693
694
|
style=${styleMap({'--indent': `${computeLeftIndent(depth, true)}px`})}
|
|
694
|
-
@select=${onSelect}
|
|
695
|
-
@expand=${onExpand}
|
|
696
|
-
jslog=${
|
|
697
|
-
<div class="selection fill"></div>
|
|
695
|
+
@select=${on(onSelect)}
|
|
696
|
+
@expand=${on(onExpand)}
|
|
697
|
+
jslog=${treeItemJslog('adopted-style-sheets')}>
|
|
698
698
|
<span class="elements-tree-shortcut-title">#adopted-style-sheets</span>
|
|
699
699
|
<ul role="group">
|
|
700
700
|
${UI.TreeOutline.ifExpanded(html`
|
|
@@ -809,7 +809,8 @@ export const DECLARATIVE_VIEW: View = (input: ViewInput, _output: ViewOutput, ta
|
|
|
809
809
|
};
|
|
810
810
|
|
|
811
811
|
const renderNode = (node: SDK.DOMModel.DOMNode, depth = 0): Lit.LitTemplate => {
|
|
812
|
-
const
|
|
812
|
+
const isDOMNodeSelected = input.selectedNode === node;
|
|
813
|
+
const isSelected = Boolean(input.selectEnabled) && isDOMNodeSelected;
|
|
813
814
|
const isOpeningHovered =
|
|
814
815
|
(input.currentHighlightedNode === node) || (input.hoveredNode === node && !input.hoveredClosingTag);
|
|
815
816
|
const isClosingHovered = input.hoveredNode === node && Boolean(input.hoveredClosingTag);
|
|
@@ -832,12 +833,12 @@ export const DECLARATIVE_VIEW: View = (input: ViewInput, _output: ViewOutput, ta
|
|
|
832
833
|
|
|
833
834
|
const on = Lit.Directive.directive(Lit.CustomDirectives.InterceptBindingDirective);
|
|
834
835
|
|
|
835
|
-
const onSelect = (isClosingTag = false): void => {
|
|
836
|
-
input.onSelect?.(node, isClosingTag,
|
|
836
|
+
const onSelect = (isClosingTag = false, selectedByUser = false): void => {
|
|
837
|
+
input.onSelect?.(node, isClosingTag, selectedByUser);
|
|
837
838
|
};
|
|
838
839
|
|
|
839
840
|
const onExpand = (event: UI.TreeOutline.TreeViewElement.ExpandEvent): void => {
|
|
840
|
-
if (isEditingAsHTML) {
|
|
841
|
+
if (isEditingAsHTML || !isCollapsible) {
|
|
841
842
|
return;
|
|
842
843
|
}
|
|
843
844
|
input.onExpand?.(node, event.detail.expanded);
|
|
@@ -848,6 +849,7 @@ export const DECLARATIVE_VIEW: View = (input: ViewInput, _output: ViewOutput, ta
|
|
|
848
849
|
const isDraggable = !input.disableEdits && Boolean(input.isValidDragSource?.(node));
|
|
849
850
|
|
|
850
851
|
const classes = classMap({
|
|
852
|
+
selected: isSelected && !input.selectedClosingTag,
|
|
851
853
|
hovered: isOpeningHovered,
|
|
852
854
|
'in-clipboard': Boolean(input.isNodeInClipboard?.(node)),
|
|
853
855
|
'elements-drag-over': isDragOver,
|
|
@@ -855,13 +857,19 @@ export const DECLARATIVE_VIEW: View = (input: ViewInput, _output: ViewOutput, ta
|
|
|
855
857
|
});
|
|
856
858
|
|
|
857
859
|
const onOpeningMouseMove = (event: MouseEvent): void => {
|
|
858
|
-
event.
|
|
860
|
+
const currentTarget = event.currentTarget as Element | null;
|
|
861
|
+
if (currentTarget && (event.target as Element).closest('li[role="treeitem"]') !== currentTarget) {
|
|
862
|
+
return;
|
|
863
|
+
}
|
|
859
864
|
const showInfo = !UI.KeyboardShortcut.KeyboardShortcut.eventHasEitherCtrlOrMeta(event);
|
|
860
865
|
input.onHoverNode?.(node, showInfo, /* isClosingTag= */ false);
|
|
861
866
|
};
|
|
862
867
|
|
|
863
868
|
const onClosingMouseMove = (event: MouseEvent): void => {
|
|
864
|
-
event.
|
|
869
|
+
const currentTarget = event.currentTarget as Element | null;
|
|
870
|
+
if (currentTarget && (event.target as Element).closest('li[role="treeitem"]') !== currentTarget) {
|
|
871
|
+
return;
|
|
872
|
+
}
|
|
865
873
|
const showInfo = !UI.KeyboardShortcut.KeyboardShortcut.eventHasEitherCtrlOrMeta(event);
|
|
866
874
|
input.onHoverNode?.(node, showInfo, /* isClosingTag= */ true);
|
|
867
875
|
};
|
|
@@ -914,10 +922,10 @@ export const DECLARATIVE_VIEW: View = (input: ViewInput, _output: ViewOutput, ta
|
|
|
914
922
|
?selected=${isSelected && !input.selectedClosingTag}
|
|
915
923
|
class=${classes}
|
|
916
924
|
style=${styleMap({'--indent': `${computeLeftIndent(depth, isExpandable)}px`})}
|
|
917
|
-
?open=${isExpanded && !isEditingAsHTML}
|
|
925
|
+
?open=${hasChildren && isExpanded && !isEditingAsHTML}
|
|
918
926
|
draggable=${isDraggable ? 'true' : 'false'}
|
|
919
|
-
@select=${on(() => onSelect(false))}
|
|
920
|
-
@expand=${onExpand}
|
|
927
|
+
@select=${on((event: UI.TreeOutline.TreeViewElement.SelectEvent) => onSelect(false, Boolean(event.detail?.selectedByUser)))}
|
|
928
|
+
@expand=${on(onExpand)}
|
|
921
929
|
@mousemove=${on(onOpeningMouseMove)}
|
|
922
930
|
@contextmenu=${on(onContextMenu)}
|
|
923
931
|
@dragstart=${on(onDragStart)}
|
|
@@ -925,19 +933,15 @@ export const DECLARATIVE_VIEW: View = (input: ViewInput, _output: ViewOutput, ta
|
|
|
925
933
|
@dragleave=${on(onDragLeave)}
|
|
926
934
|
@drop=${on(onDrop)}
|
|
927
935
|
@dragend=${on(onDragEnd)}
|
|
928
|
-
jslog=${
|
|
929
|
-
keydown: 'ArrowUp|ArrowDown|ArrowLeft|ArrowRight|Backspace|Delete|Enter|Space|Home|End',
|
|
930
|
-
resize: true,
|
|
931
|
-
drag: true,
|
|
932
|
-
click: true,
|
|
933
|
-
})}>
|
|
936
|
+
jslog=${treeItemJslog(undefined, true)}>
|
|
934
937
|
${UI.Widget.widget(ElementsTreeWidget, {
|
|
935
938
|
node,
|
|
936
939
|
isClosingTag: false,
|
|
940
|
+
renderSelection: false,
|
|
937
941
|
expanded: isExpanded && !isEditingAsHTML,
|
|
938
942
|
isExpandable: hasChildren,
|
|
939
943
|
selected: isSelected && !input.selectedClosingTag,
|
|
940
|
-
isDOMNodeSelected
|
|
944
|
+
isDOMNodeSelected,
|
|
941
945
|
hovered: isOpeningHovered,
|
|
942
946
|
searchQuery: input.searchMatchNode === node ? (input.searchMatchQuery ?? null) : null,
|
|
943
947
|
inClipboard: input.isNodeInClipboard?.(node) ?? false,
|
|
@@ -963,8 +967,7 @@ export const DECLARATIVE_VIEW: View = (input: ViewInput, _output: ViewOutput, ta
|
|
|
963
967
|
input.onSelectNodeAfterEdit?.(wasExpanded, error, newNode, moveDirection);
|
|
964
968
|
},
|
|
965
969
|
toggleHideElement: (n: SDK.DOMModel.DOMNode) => {
|
|
966
|
-
input.onToggleHideElement?.(n);
|
|
967
|
-
return Promise.resolve();
|
|
970
|
+
return input.onToggleHideElement?.(n) ?? Promise.resolve();
|
|
968
971
|
},
|
|
969
972
|
isToggledToHidden: (n: SDK.DOMModel.DOMNode) => input.isToggledToHidden?.(n) ?? false,
|
|
970
973
|
showContextMenu: (event: Event) => {
|
|
@@ -978,12 +981,12 @@ export const DECLARATIVE_VIEW: View = (input: ViewInput, _output: ViewOutput, ta
|
|
|
978
981
|
<ul role="group">
|
|
979
982
|
${UI.TreeOutline.ifExpanded(html`
|
|
980
983
|
${node.adoptedStyleSheetsForNode.length > 0 ? renderAdoptedStyleSheets(node, depth + 1) : nothing}
|
|
981
|
-
${children.
|
|
984
|
+
${repeat(children, child => child.id, child => renderNode(child, depth + 1))}
|
|
982
985
|
${remainingChildrenCount > 0 ? html`
|
|
983
986
|
<li role="treeitem"
|
|
984
987
|
class="elements-tree-expand-all"
|
|
985
988
|
style=${styleMap({'--indent': `${computeLeftIndent(depth + 1, false)}px`})}
|
|
986
|
-
jslog=${
|
|
989
|
+
jslog=${treeItemJslog('show-all-nodes')}>
|
|
987
990
|
<devtools-button
|
|
988
991
|
.variant=${Buttons.Button.Variant.OUTLINED}
|
|
989
992
|
title=${i18nString(UIStrings.showAllNodesDMore, {PH1: remainingChildrenCount})}
|
|
@@ -995,15 +998,21 @@ export const DECLARATIVE_VIEW: View = (input: ViewInput, _output: ViewOutput, ta
|
|
|
995
998
|
</devtools-button>
|
|
996
999
|
</li>
|
|
997
1000
|
` : nothing}
|
|
1001
|
+
${node.isInsertionPoint() ? node.distributedNodes().map(distributedNode => renderShortcut(distributedNode, depth + 1)) : nothing}
|
|
998
1002
|
${node instanceof SDK.DOMModel.DOMDocument ? renderTopLayerContainer(node, depth + 1) : nothing}
|
|
999
1003
|
${needsClosingTag ? html`
|
|
1000
1004
|
<li role="treeitem"
|
|
1001
1005
|
?selected=${isSelected && Boolean(input.selectedClosingTag)}
|
|
1002
|
-
class=${classMap({
|
|
1006
|
+
class=${classMap({
|
|
1007
|
+
selected: isSelected && Boolean(input.selectedClosingTag),
|
|
1008
|
+
hovered: isClosingHovered,
|
|
1009
|
+
'elements-drag-over': isClosingTagDragOver,
|
|
1010
|
+
})}
|
|
1003
1011
|
style=${styleMap({'--indent': `${computeLeftIndent(depth + 1, false)}px`})}
|
|
1004
1012
|
draggable=${isDraggable ? 'true' : 'false'}
|
|
1005
|
-
jslog=${
|
|
1006
|
-
@select=${on(() => onSelect(true))}
|
|
1013
|
+
jslog=${treeItemJslog(undefined, true)}
|
|
1014
|
+
@select=${on((event: UI.TreeOutline.TreeViewElement.SelectEvent) => onSelect(true, Boolean(event.detail?.selectedByUser)))}
|
|
1015
|
+
@contextmenu=${on(onContextMenu)}
|
|
1007
1016
|
@mousemove=${on(onClosingMouseMove)}
|
|
1008
1017
|
@dragstart=${on(onDragStart)}
|
|
1009
1018
|
@dragover=${on(onClosingTagDragOver)}
|
|
@@ -1013,10 +1022,11 @@ export const DECLARATIVE_VIEW: View = (input: ViewInput, _output: ViewOutput, ta
|
|
|
1013
1022
|
${UI.Widget.widget(ElementsTreeWidget, {
|
|
1014
1023
|
node,
|
|
1015
1024
|
isClosingTag: true,
|
|
1025
|
+
renderSelection: false,
|
|
1016
1026
|
expanded: false,
|
|
1017
1027
|
isExpandable: false,
|
|
1018
1028
|
selected: isSelected && Boolean(input.selectedClosingTag),
|
|
1019
|
-
isDOMNodeSelected
|
|
1029
|
+
isDOMNodeSelected,
|
|
1020
1030
|
hovered: isClosingHovered,
|
|
1021
1031
|
computeLeftIndent: computeLeftIndent(depth + 1, false),
|
|
1022
1032
|
disableEdits: input.disableEdits ?? false,
|
|
@@ -1062,7 +1072,6 @@ export const DECLARATIVE_VIEW: View = (input: ViewInput, _output: ViewOutput, ta
|
|
|
1062
1072
|
<devtools-tree
|
|
1063
1073
|
class="elements-tree-outline source-code ${input.wrap ? '' : 'elements-tree-nowrap'} ${input.hideGutter ? 'elements-hide-gutter' : ''} ${isSingleNode ? 'single-node' : ''}"
|
|
1064
1074
|
disclosure-class="elements-disclosure ${isSingleNode ? 'single-node' : ''} ${input.maxRowsShown ? 'elements-tree-truncated' : ''}"
|
|
1065
|
-
aria-label=${i18nString(UIStrings.pageDom)}
|
|
1066
1075
|
jslog=${VisualLogging.tree('elements')}
|
|
1067
1076
|
?show-selection-on-keyboard-focus=${input.showSelectionOnKeyboardFocus}
|
|
1068
1077
|
@enter=${(event: Event) => event.preventDefault()}
|
|
@@ -1075,10 +1084,10 @@ export const DECLARATIVE_VIEW: View = (input: ViewInput, _output: ViewOutput, ta
|
|
|
1075
1084
|
<style>${UI.inspectorCommonStyles}</style>
|
|
1076
1085
|
<style>${elementsTreeOutlineStyles}</style>
|
|
1077
1086
|
<style>${CodeHighlighter.codeHighlighterStyles}</style>
|
|
1078
|
-
<ul role="tree">
|
|
1087
|
+
<ul role="tree" class="elements-tree-outline source-code ${input.wrap ? '' : 'elements-tree-nowrap'} ${input.hideGutter ? 'elements-hide-gutter' : ''} ${isSingleNode ? 'single-node' : ''}" aria-label=${i18nString(UIStrings.pageDom)}>
|
|
1079
1088
|
${input.omitRootDOMNode && input.rootDOMNode && input.rootDOMNode.adoptedStyleSheetsForNode.length > 0 ?
|
|
1080
1089
|
renderAdoptedStyleSheets(input.rootDOMNode, 0) : nothing}
|
|
1081
|
-
${rootNodes.
|
|
1090
|
+
${repeat(rootNodes, node => node.id, node => renderNode(node))}
|
|
1082
1091
|
${input.omitRootDOMNode && input.rootDOMNode ? (() => {
|
|
1083
1092
|
const remaining = allRootNodes.length - rootNodes.length;
|
|
1084
1093
|
if (remaining <= 0) {
|
|
@@ -1089,14 +1098,14 @@ export const DECLARATIVE_VIEW: View = (input: ViewInput, _output: ViewOutput, ta
|
|
|
1089
1098
|
<li role="treeitem"
|
|
1090
1099
|
class="elements-tree-expand-all"
|
|
1091
1100
|
style=${styleMap({'--indent': `${computeLeftIndent(0, false)}px`})}
|
|
1092
|
-
jslog=${
|
|
1101
|
+
jslog=${treeItemJslog('show-all-nodes')}>
|
|
1093
1102
|
<devtools-button
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1103
|
+
.variant=${Buttons.Button.Variant.OUTLINED}
|
|
1104
|
+
title=${i18nString(UIStrings.showAllNodesDMore, {PH1: remaining})}
|
|
1105
|
+
@click=${on((event: Event) => {
|
|
1106
|
+
event.stopPropagation();
|
|
1107
|
+
input.onExpandAllChildren?.(root);
|
|
1108
|
+
})}>
|
|
1100
1109
|
${i18nString(UIStrings.showAllNodesDMore, {PH1: remaining})}
|
|
1101
1110
|
</devtools-button>
|
|
1102
1111
|
</li>
|
|
@@ -1154,6 +1163,8 @@ function getElementsTreeWidgetAndNode(element: Element): {node?: SDK.DOMModel.DO
|
|
|
1154
1163
|
* to DOMTreeWidget.ts.
|
|
1155
1164
|
*/
|
|
1156
1165
|
export class DOMTreeWidget extends UI.Widget.Widget {
|
|
1166
|
+
static override readonly INJECT: readonly[typeof ChangeTracker.ChangeTracker.ChangeTracker] =
|
|
1167
|
+
[ChangeTracker.ChangeTracker.ChangeTracker] as const;
|
|
1157
1168
|
omitRootDOMNode = false;
|
|
1158
1169
|
selectEnabled = false;
|
|
1159
1170
|
hideGutter = false;
|
|
@@ -1179,6 +1190,7 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
1179
1190
|
#visibleWidth?: number;
|
|
1180
1191
|
#wrap = false;
|
|
1181
1192
|
#maxRows?: number;
|
|
1193
|
+
#changeTracker?: ChangeTracker.ChangeTracker.ChangeTracker;
|
|
1182
1194
|
|
|
1183
1195
|
// If maxRows is undefined, all rows are shown. If it is set to a number, only that many rows are shown.
|
|
1184
1196
|
set maxRows(maxRows: number|undefined) {
|
|
@@ -1210,9 +1222,11 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
1210
1222
|
}
|
|
1211
1223
|
this.#expandedNodes.add(node);
|
|
1212
1224
|
const expandChildren = (): void => {
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1225
|
+
for (const child of node.children() ?? []) {
|
|
1226
|
+
const isNotCollapsible = child.nodeType() === Node.ELEMENT_NODE &&
|
|
1227
|
+
child.parentNode?.nodeType() === Node.DOCUMENT_NODE && !child.parentNode.parentNode;
|
|
1228
|
+
if (isNotCollapsible || (this.#expandRoot && this.omitRootDOMNode)) {
|
|
1229
|
+
this.setNodeExpanded(child, true);
|
|
1216
1230
|
}
|
|
1217
1231
|
}
|
|
1218
1232
|
};
|
|
@@ -1275,6 +1289,7 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
1275
1289
|
|
|
1276
1290
|
set showComments(showComments: boolean) {
|
|
1277
1291
|
this.#showComments = showComments;
|
|
1292
|
+
this.#validateSelectedNode();
|
|
1278
1293
|
this.performUpdate();
|
|
1279
1294
|
}
|
|
1280
1295
|
|
|
@@ -1330,8 +1345,20 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
1330
1345
|
};
|
|
1331
1346
|
#highlightThrottler = new Common.Throttler.Throttler(100);
|
|
1332
1347
|
|
|
1348
|
+
get changeTracker(): ChangeTracker.ChangeTracker.ChangeTracker|undefined {
|
|
1349
|
+
// The widget is also created without dependency injection (e.g. by
|
|
1350
|
+
// ElementsPanel), so the changeTracker can be empty, relying on the manual
|
|
1351
|
+
// resolution. Note that this only works once the widget is attached to the
|
|
1352
|
+
// DOM.
|
|
1353
|
+
this.#changeTracker ??=
|
|
1354
|
+
UI.Widget.lookupUniverseForElement(this.contentElement)?.get(ChangeTracker.ChangeTracker.ChangeTracker);
|
|
1355
|
+
return this.#changeTracker;
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1333
1358
|
constructor(
|
|
1334
1359
|
element?: HTMLElement,
|
|
1360
|
+
[changeTracker]:
|
|
1361
|
+
UI.Widget.WidgetDependencies<typeof DOMTreeWidget>|[ChangeTracker.ChangeTracker.ChangeTracker?] = [],
|
|
1335
1362
|
view: View = DEFAULT_VIEW,
|
|
1336
1363
|
) {
|
|
1337
1364
|
super(element, {
|
|
@@ -1339,6 +1366,7 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
1339
1366
|
delegatesFocus: false,
|
|
1340
1367
|
});
|
|
1341
1368
|
this.#view = view;
|
|
1369
|
+
this.#changeTracker = changeTracker;
|
|
1342
1370
|
this.#showHTMLCommentsSetting.addChangeListener(this.#onShowHTMLCommentsChange, this);
|
|
1343
1371
|
if (Common.Settings.Settings.instance().moduleSetting('highlight-node-on-hover-in-overlay').get()) {
|
|
1344
1372
|
SDK.TargetManager.TargetManager.instance().addModelListener(
|
|
@@ -1470,10 +1498,40 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
1470
1498
|
this.#updateModifiedNodesSoon();
|
|
1471
1499
|
}
|
|
1472
1500
|
|
|
1501
|
+
#findNextNodeOnRemoval(node: SDK.DOMModel.DOMNode, parent: SDK.DOMModel.DOMNode|null): SDK.DOMModel.DOMNode|null {
|
|
1502
|
+
const visibleChildren = parent ? getVisibleChildren(parent, this.#showComments) : [];
|
|
1503
|
+
if (visibleChildren.length > 0) {
|
|
1504
|
+
let candidate: SDK.DOMModel.DOMNode|null = node.nextSibling;
|
|
1505
|
+
while (candidate) {
|
|
1506
|
+
if (visibleChildren.includes(candidate)) {
|
|
1507
|
+
return candidate;
|
|
1508
|
+
}
|
|
1509
|
+
candidate = candidate.nextSibling;
|
|
1510
|
+
}
|
|
1511
|
+
candidate = node.previousSibling;
|
|
1512
|
+
while (candidate) {
|
|
1513
|
+
if (visibleChildren.includes(candidate)) {
|
|
1514
|
+
return candidate;
|
|
1515
|
+
}
|
|
1516
|
+
candidate = candidate.previousSibling;
|
|
1517
|
+
}
|
|
1518
|
+
}
|
|
1519
|
+
if (parent) {
|
|
1520
|
+
if (parent.nodeType() === Node.DOCUMENT_NODE) {
|
|
1521
|
+
return parent.parentNode;
|
|
1522
|
+
}
|
|
1523
|
+
return parent;
|
|
1524
|
+
}
|
|
1525
|
+
return null;
|
|
1526
|
+
}
|
|
1527
|
+
|
|
1473
1528
|
#onNodeRemoved(
|
|
1474
1529
|
event: Common.EventTarget.EventTargetEvent<{node: SDK.DOMModel.DOMNode, parent: SDK.DOMModel.DOMNode}>): void {
|
|
1475
1530
|
const {node, parent} = event.data;
|
|
1476
1531
|
this.resetClipboardIfNeeded(node);
|
|
1532
|
+
if (this.#selectedDOMNode && (this.#selectedDOMNode === node || node.isAncestor(this.#selectedDOMNode))) {
|
|
1533
|
+
this.selectDOMNode(this.#findNextNodeOnRemoval(node, parent), true);
|
|
1534
|
+
}
|
|
1477
1535
|
if (parent) {
|
|
1478
1536
|
this.#addUpdateRecord(parent).nodeRemoved(node);
|
|
1479
1537
|
}
|
|
@@ -1524,8 +1582,12 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
1524
1582
|
this.#updateModifiedNodesSoon();
|
|
1525
1583
|
}
|
|
1526
1584
|
|
|
1527
|
-
#onMarkersChanged(): void {
|
|
1528
|
-
|
|
1585
|
+
#onMarkersChanged(event: Common.EventTarget.EventTargetEvent<SDK.DOMModel.DOMNode>): void {
|
|
1586
|
+
const node = event.data;
|
|
1587
|
+
if (node) {
|
|
1588
|
+
this.#addUpdateRecord(node);
|
|
1589
|
+
}
|
|
1590
|
+
this.performUpdate();
|
|
1529
1591
|
}
|
|
1530
1592
|
|
|
1531
1593
|
updateModifiedNodes(): void {
|
|
@@ -1534,6 +1596,7 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
1534
1596
|
this.#updateModifiedNodesTimeout = undefined;
|
|
1535
1597
|
}
|
|
1536
1598
|
if (this.#view === DECLARATIVE_VIEW) {
|
|
1599
|
+
this.#validateSelectedNode();
|
|
1537
1600
|
this.performUpdate();
|
|
1538
1601
|
return;
|
|
1539
1602
|
}
|
|
@@ -1554,9 +1617,17 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
1554
1617
|
domModel.addEventListener(SDK.DOMModel.Events.DistributedNodesChanged, this.#onDistributedNodesChanged, this);
|
|
1555
1618
|
domModel.addEventListener(SDK.DOMModel.Events.DocumentURLChanged, this.#onDocumentURLChanged, this);
|
|
1556
1619
|
domModel.addEventListener(SDK.DOMModel.Events.AffectedByStartingStylesFlagUpdated, this.requestUpdate, this);
|
|
1620
|
+
const cssModel = domModel.target().model(SDK.CSSModel.CSSModel);
|
|
1621
|
+
if (cssModel) {
|
|
1622
|
+
cssModel.addEventListener(SDK.CSSModel.Events.StyleSheetAdded, this.requestUpdate, this);
|
|
1623
|
+
}
|
|
1557
1624
|
}
|
|
1558
1625
|
|
|
1559
1626
|
#unwireDOMModel(domModel: SDK.DOMModel.DOMModel): void {
|
|
1627
|
+
const cssModel = domModel.target().model(SDK.CSSModel.CSSModel);
|
|
1628
|
+
if (cssModel) {
|
|
1629
|
+
cssModel.removeEventListener(SDK.CSSModel.Events.StyleSheetAdded, this.requestUpdate, this);
|
|
1630
|
+
}
|
|
1560
1631
|
domModel.removeEventListener(SDK.DOMModel.Events.DocumentUpdated, this.#onDocumentUpdated, this);
|
|
1561
1632
|
domModel.removeEventListener(SDK.DOMModel.Events.NodeInserted, this.#onNodeInserted, this);
|
|
1562
1633
|
domModel.removeEventListener(SDK.DOMModel.Events.NodeRemoved, this.#onNodeRemoved, this);
|
|
@@ -1575,6 +1646,7 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
1575
1646
|
|
|
1576
1647
|
#onShowHTMLCommentsChange(): void {
|
|
1577
1648
|
this.#showComments = this.#showHTMLCommentsSetting.get();
|
|
1649
|
+
this.#validateSelectedNode();
|
|
1578
1650
|
const selectedNode = this.selectedDOMNode();
|
|
1579
1651
|
if (selectedNode && selectedNode.nodeType() === Node.COMMENT_NODE && !this.#showComments) {
|
|
1580
1652
|
this.selectDOMNode(selectedNode.parentNode);
|
|
@@ -1601,7 +1673,7 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
1601
1673
|
}
|
|
1602
1674
|
|
|
1603
1675
|
selectDOMNode(node: SDK.DOMModel.DOMNode|SDK.DOMModel.AdoptedStyleSheet|null, focus?: boolean,
|
|
1604
|
-
isClosingTag
|
|
1676
|
+
isClosingTag?: boolean): void {
|
|
1605
1677
|
this.#imagePreviewPopover?.hide();
|
|
1606
1678
|
this.#issuePopoverHelper?.hidePopover();
|
|
1607
1679
|
if (node instanceof SDK.DOMModel.AdoptedStyleSheet) {
|
|
@@ -1610,9 +1682,9 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
1610
1682
|
}
|
|
1611
1683
|
this.#selectedAdoptedStyleSheet = null;
|
|
1612
1684
|
if (this.#view === DECLARATIVE_VIEW) {
|
|
1613
|
-
this.#selectedClosingTag
|
|
1614
|
-
const isSameNode = this.#selectedDOMNode === node;
|
|
1685
|
+
const isSameNode = this.#selectedDOMNode === node && this.#selectedClosingTag === Boolean(isClosingTag);
|
|
1615
1686
|
this.#selectedDOMNode = node;
|
|
1687
|
+
this.#selectedClosingTag = Boolean(isClosingTag);
|
|
1616
1688
|
if (node) {
|
|
1617
1689
|
const ancestors: SDK.DOMModel.DOMNode[] = [];
|
|
1618
1690
|
for (let current: (SDK.DOMModel.DOMNode|null) = node.parentNode; current; current = current.parentNode) {
|
|
@@ -1646,6 +1718,15 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
1646
1718
|
Common.EventTarget.EventTargetEvent<{node: SDK.DOMModel.DOMNode | null, focus: boolean}>);
|
|
1647
1719
|
}
|
|
1648
1720
|
this.performUpdate();
|
|
1721
|
+
if (focus) {
|
|
1722
|
+
this.focus();
|
|
1723
|
+
}
|
|
1724
|
+
return;
|
|
1725
|
+
}
|
|
1726
|
+
if (isClosingTag && node) {
|
|
1727
|
+
const rootTreeElement = this.#viewOutput?.elementsTreeOutline?.findTreeElement(node);
|
|
1728
|
+
const closingTreeElement = rootTreeElement?.childAt(rootTreeElement.childCount() - 1);
|
|
1729
|
+
closingTreeElement?.select(!focus, true);
|
|
1649
1730
|
return;
|
|
1650
1731
|
}
|
|
1651
1732
|
this.#viewOutput?.elementsTreeOutline?.selectDOMNode(node, focus);
|
|
@@ -1684,7 +1765,7 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
1684
1765
|
if (this.#view === DECLARATIVE_VIEW) {
|
|
1685
1766
|
if (expanded) {
|
|
1686
1767
|
this.#expandedNodes.add(node);
|
|
1687
|
-
if (!node.children() && node.childNodeCount()) {
|
|
1768
|
+
if (!node.children() && (node.childNodeCount() || node.isIframe() || node.nodeType() === Node.DOCUMENT_NODE)) {
|
|
1688
1769
|
void node.getChildNodes(() => {
|
|
1689
1770
|
this.performUpdate();
|
|
1690
1771
|
});
|
|
@@ -1710,6 +1791,11 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
1710
1791
|
|
|
1711
1792
|
isNodeExpanded(node: SDK.DOMModel.DOMNode): boolean {
|
|
1712
1793
|
if (this.#view === DECLARATIVE_VIEW) {
|
|
1794
|
+
const isNotCollapsible = node.nodeType() === Node.ELEMENT_NODE &&
|
|
1795
|
+
node.parentNode?.nodeType() === Node.DOCUMENT_NODE && !node.parentNode.parentNode;
|
|
1796
|
+
if (isNotCollapsible) {
|
|
1797
|
+
return true;
|
|
1798
|
+
}
|
|
1713
1799
|
return this.#expandedNodes.has(node);
|
|
1714
1800
|
}
|
|
1715
1801
|
return Boolean(this.#viewOutput.elementsTreeOutline?.findTreeElement(node)?.expanded);
|
|
@@ -1741,22 +1827,26 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
1741
1827
|
|
|
1742
1828
|
async expandRecursively(node: SDK.DOMModel.DOMNode, maxDepth: number = Number.MAX_VALUE): Promise<void> {
|
|
1743
1829
|
if (this.#view === DECLARATIVE_VIEW) {
|
|
1744
|
-
await node.getSubtree(100, true);
|
|
1745
1830
|
const expand = async(n: SDK.DOMModel.DOMNode, depth: number): Promise<void> => {
|
|
1746
1831
|
if (depth > maxDepth) {
|
|
1747
1832
|
return;
|
|
1748
1833
|
}
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1834
|
+
if (n.childDocumentPromiseForTesting) {
|
|
1835
|
+
await n.childDocumentPromiseForTesting;
|
|
1836
|
+
}
|
|
1837
|
+
if (!n.children() && !n.contentDocument() &&
|
|
1838
|
+
(n === node || n.childNodeCount() || n.isIframe() || n.nodeType() === Node.DOCUMENT_NODE)) {
|
|
1839
|
+
await n.getSubtree(100, true);
|
|
1755
1840
|
}
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1841
|
+
if (nodeHasVisibleChildren(n, this.rootDOMNode, this.maxTreeDepth, this.omitRootDOMNode)) {
|
|
1842
|
+
this.#expandedNodes.add(n);
|
|
1843
|
+
}
|
|
1844
|
+
const visibleChildren = getVisibleChildren(n, this.#showComments);
|
|
1845
|
+
if (visibleChildren.length) {
|
|
1846
|
+
if (visibleChildren.length > this.expandedChildrenLimit(n)) {
|
|
1847
|
+
this.setExpandedChildrenLimit(n, visibleChildren.length);
|
|
1848
|
+
}
|
|
1849
|
+
await Promise.all(visibleChildren.map(child => expand(child, depth + 1)));
|
|
1760
1850
|
}
|
|
1761
1851
|
};
|
|
1762
1852
|
await expand(node, 0);
|
|
@@ -1812,7 +1902,6 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
1812
1902
|
treeElementForNode(node: SDK.DOMModel.DOMNode): ElementsTreeElement|null {
|
|
1813
1903
|
return this.#viewOutput.elementsTreeOutline?.findTreeElement(node) || null;
|
|
1814
1904
|
}
|
|
1815
|
-
|
|
1816
1905
|
#hoveredDOMNode: SDK.DOMModel.DOMNode|null = null;
|
|
1817
1906
|
#hoveredClosingTag = false;
|
|
1818
1907
|
#selectedClosingTag = false;
|
|
@@ -1827,6 +1916,7 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
1827
1916
|
#draggedNode: SDK.DOMModel.DOMNode|null = null;
|
|
1828
1917
|
#draggedNodeWasExpanded = false;
|
|
1829
1918
|
#dragOverNode: {node: SDK.DOMModel.DOMNode, isClosingTag: boolean}|null = null;
|
|
1919
|
+
#isFocusing = false;
|
|
1830
1920
|
|
|
1831
1921
|
hoveredDOMNode(): SDK.DOMModel.DOMNode|null {
|
|
1832
1922
|
if (this.#view === DECLARATIVE_VIEW) {
|
|
@@ -1871,16 +1961,83 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
1871
1961
|
if (this.#view === DECLARATIVE_VIEW) {
|
|
1872
1962
|
this.performUpdate();
|
|
1873
1963
|
} else {
|
|
1874
|
-
|
|
1964
|
+
let treeElement = node ? this.treeElementForNode(node) : null;
|
|
1965
|
+
if (isClosingTag && treeElement) {
|
|
1966
|
+
treeElement = treeElement.childAt(treeElement.childCount() - 1) as ElementsTreeElement | null;
|
|
1967
|
+
}
|
|
1875
1968
|
this.#viewOutput.elementsTreeOutline?.setHoverEffect(treeElement);
|
|
1876
1969
|
}
|
|
1877
1970
|
}
|
|
1878
1971
|
|
|
1972
|
+
#findValidSelectedNode(selectedNode: SDK.DOMModel.DOMNode): SDK.DOMModel.DOMNode|null {
|
|
1973
|
+
if (!this.#rootDOMNode) {
|
|
1974
|
+
return null;
|
|
1975
|
+
}
|
|
1976
|
+
if (selectedNode === this.#rootDOMNode) {
|
|
1977
|
+
return selectedNode;
|
|
1978
|
+
}
|
|
1979
|
+
let current: SDK.DOMModel.DOMNode|null = selectedNode;
|
|
1980
|
+
let fallback: SDK.DOMModel.DOMNode|null = null;
|
|
1981
|
+
while (current && current !== this.#rootDOMNode) {
|
|
1982
|
+
const parent: SDK.DOMModel.DOMNode|null = current.parentNode;
|
|
1983
|
+
if (!parent) {
|
|
1984
|
+
return fallback ?? this.#rootDOMNode;
|
|
1985
|
+
}
|
|
1986
|
+
if (parent.children() !== null || parent.childNodeCount() === 0 || parent.isIframe()) {
|
|
1987
|
+
const visibleChildren = getVisibleChildren(parent, this.#showComments);
|
|
1988
|
+
if (!visibleChildren.includes(current)) {
|
|
1989
|
+
let sibling: SDK.DOMModel.DOMNode|null = null;
|
|
1990
|
+
let candidate: SDK.DOMModel.DOMNode|null = current.nextSibling;
|
|
1991
|
+
while (candidate) {
|
|
1992
|
+
if (visibleChildren.includes(candidate)) {
|
|
1993
|
+
sibling = candidate;
|
|
1994
|
+
break;
|
|
1995
|
+
}
|
|
1996
|
+
candidate = candidate.nextSibling;
|
|
1997
|
+
}
|
|
1998
|
+
if (!sibling) {
|
|
1999
|
+
candidate = current.previousSibling;
|
|
2000
|
+
while (candidate) {
|
|
2001
|
+
if (visibleChildren.includes(candidate)) {
|
|
2002
|
+
sibling = candidate;
|
|
2003
|
+
break;
|
|
2004
|
+
}
|
|
2005
|
+
candidate = candidate.previousSibling;
|
|
2006
|
+
}
|
|
2007
|
+
}
|
|
2008
|
+
if (sibling) {
|
|
2009
|
+
return this.#findValidSelectedNode(sibling);
|
|
2010
|
+
}
|
|
2011
|
+
return this.#findValidSelectedNode(parent);
|
|
2012
|
+
}
|
|
2013
|
+
}
|
|
2014
|
+
fallback = parent;
|
|
2015
|
+
current = parent;
|
|
2016
|
+
}
|
|
2017
|
+
return current === this.#rootDOMNode ? selectedNode : (fallback ?? this.#rootDOMNode);
|
|
2018
|
+
}
|
|
2019
|
+
|
|
2020
|
+
#validateSelectedNode(): void {
|
|
2021
|
+
if (!this.#selectedDOMNode) {
|
|
2022
|
+
return;
|
|
2023
|
+
}
|
|
2024
|
+
const validNode = this.#findValidSelectedNode(this.#selectedDOMNode);
|
|
2025
|
+
if (validNode !== this.#selectedDOMNode) {
|
|
2026
|
+
this.#selectedDOMNode = validNode;
|
|
2027
|
+
this.#selectedClosingTag = false;
|
|
2028
|
+
this.#clearHighlightedNode();
|
|
2029
|
+
this.onSelectedNodeChanged(
|
|
2030
|
+
{data: {node: validNode, focus: false}} as
|
|
2031
|
+
Common.EventTarget.EventTargetEvent<{node: SDK.DOMModel.DOMNode | null, focus: boolean}>);
|
|
2032
|
+
}
|
|
2033
|
+
}
|
|
2034
|
+
|
|
1879
2035
|
override performUpdate(): void {
|
|
1880
2036
|
if (this.#updateModifiedNodesTimeout) {
|
|
1881
2037
|
clearTimeout(this.#updateModifiedNodesTimeout);
|
|
1882
2038
|
this.#updateModifiedNodesTimeout = undefined;
|
|
1883
2039
|
}
|
|
2040
|
+
this.#validateSelectedNode();
|
|
1884
2041
|
const firstRender = !this.#viewOutput.elementsTreeOutline;
|
|
1885
2042
|
const updatedNodes = this.#view === DECLARATIVE_VIEW ? [...this.#updateRecords.keys()] : [];
|
|
1886
2043
|
this.#view({
|
|
@@ -1931,6 +2088,9 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
1931
2088
|
this.setHoveredNode(null);
|
|
1932
2089
|
},
|
|
1933
2090
|
onSelect: (node: SDK.DOMModel.DOMNode, isClosingTag = false, selectedByUser?: boolean) => {
|
|
2091
|
+
if (!selectedByUser) {
|
|
2092
|
+
return;
|
|
2093
|
+
}
|
|
1934
2094
|
this.selectDOMNode(node, selectedByUser, isClosingTag);
|
|
1935
2095
|
},
|
|
1936
2096
|
onExpand: (node: SDK.DOMModel.DOMNode, expanded: boolean) => {
|
|
@@ -1940,7 +2100,7 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
1940
2100
|
void this.showContextMenu(node, event);
|
|
1941
2101
|
},
|
|
1942
2102
|
onToggleHideElement: (node: SDK.DOMModel.DOMNode) => {
|
|
1943
|
-
this.toggleHideElement(node);
|
|
2103
|
+
return this.toggleHideElement(node);
|
|
1944
2104
|
},
|
|
1945
2105
|
onKeyDown: (event: KeyboardEvent) => {
|
|
1946
2106
|
this.onKeyDown(event);
|
|
@@ -2134,6 +2294,20 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
2134
2294
|
* FIXME: which node is selected should be part of the view input.
|
|
2135
2295
|
*/
|
|
2136
2296
|
selectDOMNodeWithoutReveal(node: SDK.DOMModel.DOMNode): void {
|
|
2297
|
+
if (this.#view === DECLARATIVE_VIEW) {
|
|
2298
|
+
const isSameNode = this.#selectedDOMNode === node && !this.#selectedClosingTag;
|
|
2299
|
+
if (isSameNode) {
|
|
2300
|
+
return;
|
|
2301
|
+
}
|
|
2302
|
+
this.#selectedDOMNode = node;
|
|
2303
|
+
this.#selectedClosingTag = false;
|
|
2304
|
+
this.#clearHighlightedNode();
|
|
2305
|
+
this.onSelectedNodeChanged(
|
|
2306
|
+
{data: {node, focus: false}} as
|
|
2307
|
+
Common.EventTarget.EventTargetEvent<{node: SDK.DOMModel.DOMNode | null, focus: boolean}>);
|
|
2308
|
+
this.performUpdate();
|
|
2309
|
+
return;
|
|
2310
|
+
}
|
|
2137
2311
|
this.#viewOutput.elementsTreeOutline?.findTreeElement(node)?.select();
|
|
2138
2312
|
}
|
|
2139
2313
|
|
|
@@ -2165,8 +2339,11 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
2165
2339
|
}
|
|
2166
2340
|
}
|
|
2167
2341
|
|
|
2168
|
-
toggleHideElement(node: SDK.DOMModel.DOMNode): void {
|
|
2169
|
-
|
|
2342
|
+
async toggleHideElement(node: SDK.DOMModel.DOMNode): Promise<void> {
|
|
2343
|
+
const changeTracker = this.changeTracker;
|
|
2344
|
+
Elements.DOMChanges.trackVisibilityToggle(changeTracker, node, buildChangeSelector(changeTracker, node),
|
|
2345
|
+
!this.isToggledToHidden(node));
|
|
2346
|
+
await node.toggleHideElement();
|
|
2170
2347
|
}
|
|
2171
2348
|
|
|
2172
2349
|
async removeNode(node: SDK.DOMModel.DOMNode): Promise<void> {
|
|
@@ -2180,7 +2357,14 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
2180
2357
|
if (!node.parentNode || node.parentNode.nodeType() === Node.DOCUMENT_NODE) {
|
|
2181
2358
|
return;
|
|
2182
2359
|
}
|
|
2183
|
-
|
|
2360
|
+
// The selector has to be resolved before the node is detached from the tree.
|
|
2361
|
+
const changeTracker = this.changeTracker;
|
|
2362
|
+
const selector = buildChangeSelector(changeTracker, node);
|
|
2363
|
+
await node.removeNode((err: string|null) => {
|
|
2364
|
+
if (!err) {
|
|
2365
|
+
Elements.DOMChanges.trackNodeRemoval(changeTracker, node, selector);
|
|
2366
|
+
}
|
|
2367
|
+
});
|
|
2184
2368
|
}
|
|
2185
2369
|
|
|
2186
2370
|
isToggledToHidden(node: SDK.DOMModel.DOMNode): boolean {
|
|
@@ -2292,7 +2476,14 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
2292
2476
|
}
|
|
2293
2477
|
|
|
2294
2478
|
duplicateNode(node: SDK.DOMModel.DOMNode): void {
|
|
2295
|
-
void node.duplicate()
|
|
2479
|
+
void node.duplicate().then(({error, node: newNode}) => {
|
|
2480
|
+
if (!error) {
|
|
2481
|
+
const duplicatedNode = newNode ?? node;
|
|
2482
|
+
const changeTracker = this.changeTracker;
|
|
2483
|
+
Elements.DOMChanges.trackNodeDuplication(changeTracker, duplicatedNode,
|
|
2484
|
+
buildChangeSelector(changeTracker, duplicatedNode));
|
|
2485
|
+
}
|
|
2486
|
+
});
|
|
2296
2487
|
}
|
|
2297
2488
|
|
|
2298
2489
|
nodeBeingDragged(): SDK.DOMModel.DOMNode|null {
|
|
@@ -2431,6 +2622,11 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
2431
2622
|
}
|
|
2432
2623
|
const wasExpanded = this.#draggedNodeWasExpanded;
|
|
2433
2624
|
draggedNode.moveTo(parentNode, anchorNode, (error, newNode) => {
|
|
2625
|
+
if (!error) {
|
|
2626
|
+
const movedNode = newNode ?? draggedNode;
|
|
2627
|
+
const changeTracker = this.changeTracker;
|
|
2628
|
+
Elements.DOMChanges.trackNodeDrop(changeTracker, movedNode, buildChangeSelector(changeTracker, movedNode));
|
|
2629
|
+
}
|
|
2434
2630
|
this.selectNodeAfterEdit(wasExpanded, error, newNode);
|
|
2435
2631
|
});
|
|
2436
2632
|
}
|
|
@@ -2595,7 +2791,8 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
2595
2791
|
}
|
|
2596
2792
|
this.performUpdate();
|
|
2597
2793
|
} else if (nodeType === Node.TEXT_NODE) {
|
|
2598
|
-
this
|
|
2794
|
+
this.#nodeToEdit = {node, isTextNode: true};
|
|
2795
|
+
this.performUpdate();
|
|
2599
2796
|
} else if (nodeType === Node.PROCESSING_INSTRUCTION_NODE) {
|
|
2600
2797
|
this.#nodeToEdit = {node, isProcessingInstruction: true};
|
|
2601
2798
|
this.performUpdate();
|
|
@@ -2615,6 +2812,12 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
2615
2812
|
const wasExpanded = this.isNodeExpanded(node);
|
|
2616
2813
|
if (event.key === 'ArrowUp' && node.previousSibling) {
|
|
2617
2814
|
node.moveTo(node.parentNode, node.previousSibling, (error, newNode) => {
|
|
2815
|
+
if (!error) {
|
|
2816
|
+
const movedNode = newNode ?? node;
|
|
2817
|
+
const changeTracker = this.changeTracker;
|
|
2818
|
+
Elements.DOMChanges.trackNodeMove(changeTracker, movedNode, buildChangeSelector(changeTracker, movedNode),
|
|
2819
|
+
/* directionUp= */ true);
|
|
2820
|
+
}
|
|
2618
2821
|
this.selectNodeAfterEdit(wasExpanded, error, newNode);
|
|
2619
2822
|
});
|
|
2620
2823
|
event.consume(true);
|
|
@@ -2622,6 +2825,12 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
2622
2825
|
}
|
|
2623
2826
|
if (event.key === 'ArrowDown' && node.nextSibling) {
|
|
2624
2827
|
node.moveTo(node.parentNode, node.nextSibling.nextSibling, (error, newNode) => {
|
|
2828
|
+
if (!error) {
|
|
2829
|
+
const movedNode = newNode ?? node;
|
|
2830
|
+
const changeTracker = this.changeTracker;
|
|
2831
|
+
Elements.DOMChanges.trackNodeMove(changeTracker, movedNode, buildChangeSelector(changeTracker, movedNode),
|
|
2832
|
+
/* directionUp= */ false);
|
|
2833
|
+
}
|
|
2625
2834
|
this.selectNodeAfterEdit(wasExpanded, error, newNode);
|
|
2626
2835
|
});
|
|
2627
2836
|
event.consume(true);
|
|
@@ -2648,7 +2857,7 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
2648
2857
|
}
|
|
2649
2858
|
|
|
2650
2859
|
if (event.key === 'h' || event.key === 'H') {
|
|
2651
|
-
this.toggleHideElement(node);
|
|
2860
|
+
void this.toggleHideElement(node);
|
|
2652
2861
|
event.consume(true);
|
|
2653
2862
|
return true;
|
|
2654
2863
|
}
|
|
@@ -2783,11 +2992,23 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
2783
2992
|
const clipboardNode = this.#clipboardData.node;
|
|
2784
2993
|
if (this.#clipboardData.isCut) {
|
|
2785
2994
|
clipboardNode.moveTo(targetNode, null, (error, newNode) => {
|
|
2995
|
+
if (!error) {
|
|
2996
|
+
const movedNode = newNode ?? clipboardNode;
|
|
2997
|
+
const changeTracker = this.changeTracker;
|
|
2998
|
+
Elements.DOMChanges.trackNodePaste(changeTracker, movedNode, buildChangeSelector(changeTracker, movedNode),
|
|
2999
|
+
/* isCut= */ true);
|
|
3000
|
+
}
|
|
2786
3001
|
this.selectNodeAfterEdit(wasExpanded, error, newNode);
|
|
2787
3002
|
});
|
|
2788
3003
|
this.setClipboardData(null);
|
|
2789
3004
|
} else {
|
|
2790
3005
|
clipboardNode.copyTo(targetNode, null, (error, newNode) => {
|
|
3006
|
+
if (!error) {
|
|
3007
|
+
const addedNode = newNode ?? clipboardNode;
|
|
3008
|
+
const changeTracker = this.changeTracker;
|
|
3009
|
+
Elements.DOMChanges.trackNodePaste(changeTracker, addedNode, buildChangeSelector(changeTracker, addedNode),
|
|
3010
|
+
/* isCut= */ false);
|
|
3011
|
+
}
|
|
2791
3012
|
this.selectNodeAfterEdit(wasExpanded, error, newNode);
|
|
2792
3013
|
});
|
|
2793
3014
|
}
|
|
@@ -2852,8 +3073,20 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
2852
3073
|
}
|
|
2853
3074
|
|
|
2854
3075
|
override focus(): void {
|
|
2855
|
-
|
|
2856
|
-
|
|
3076
|
+
if (this.#isFocusing) {
|
|
3077
|
+
return;
|
|
3078
|
+
}
|
|
3079
|
+
this.#isFocusing = true;
|
|
3080
|
+
try {
|
|
3081
|
+
super.focus();
|
|
3082
|
+
if (this.#view === DECLARATIVE_VIEW) {
|
|
3083
|
+
this.contentElement.querySelector('devtools-tree')?.focus();
|
|
3084
|
+
} else {
|
|
3085
|
+
this.#viewOutput.elementsTreeOutline?.focus();
|
|
3086
|
+
}
|
|
3087
|
+
} finally {
|
|
3088
|
+
this.#isFocusing = false;
|
|
3089
|
+
}
|
|
2857
3090
|
}
|
|
2858
3091
|
|
|
2859
3092
|
override wasShown(): void {
|
|
@@ -2871,6 +3104,7 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
2871
3104
|
}
|
|
2872
3105
|
if (this.#view === DECLARATIVE_VIEW) {
|
|
2873
3106
|
this.#updateRecords.clear();
|
|
3107
|
+
return;
|
|
2874
3108
|
}
|
|
2875
3109
|
this.performUpdate();
|
|
2876
3110
|
}
|
|
@@ -2885,6 +3119,7 @@ export class DOMTreeWidget extends UI.Widget.Widget {
|
|
|
2885
3119
|
}
|
|
2886
3120
|
if (this.#view === DECLARATIVE_VIEW) {
|
|
2887
3121
|
this.#updateRecords.clear();
|
|
3122
|
+
return;
|
|
2888
3123
|
}
|
|
2889
3124
|
this.performUpdate();
|
|
2890
3125
|
}
|