chrome-devtools-frontend 1.0.1581708 → 1.0.1583146
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/front_end/core/root/Runtime.ts +0 -5
- package/front_end/core/sdk/NetworkManager.ts +63 -115
- package/front_end/core/sdk/RemoteObject.ts +7 -1
- package/front_end/entrypoints/greendev_floaty/FloatyEntrypoint.ts +9 -24
- package/front_end/entrypoints/greendev_floaty/floaty.css +1 -1
- package/front_end/entrypoints/greendev_floaty/greendev_floaty.ts +1 -1
- package/front_end/generated/InspectorBackendCommands.ts +1 -1
- package/front_end/generated/SupportedCSSProperties.js +2 -0
- package/front_end/generated/protocol.ts +0 -6
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.snapshot.txt +6 -6
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +17 -9
- package/front_end/models/ai_assistance/agents/NetworkAgent.ts +2 -6
- package/front_end/models/ai_assistance/data_formatters/NetworkRequestFormatter.ts +66 -2
- package/front_end/models/greendev/Prototypes.ts +1 -10
- package/front_end/models/issues_manager/ConnectionAllowlistIssue.ts +75 -0
- package/front_end/models/issues_manager/FederatedAuthRequestIssue.ts +0 -30
- package/front_end/models/issues_manager/IssuesManager.ts +5 -0
- package/front_end/models/issues_manager/descriptions/connectionAllowlistInvalidAllowlistItemType.md +12 -0
- package/front_end/models/issues_manager/descriptions/connectionAllowlistInvalidHeader.md +12 -0
- package/front_end/models/issues_manager/descriptions/connectionAllowlistInvalidUrlPattern.md +8 -0
- package/front_end/models/issues_manager/descriptions/connectionAllowlistItemNotInnerList.md +12 -0
- package/front_end/models/issues_manager/descriptions/connectionAllowlistMoreThanOneList.md +7 -0
- package/front_end/models/issues_manager/descriptions/connectionAllowlistReportingEndpointNotToken.md +10 -0
- package/front_end/models/issues_manager/issues_manager.ts +2 -0
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +22 -4
- package/front_end/panels/ai_assistance/components/ChatInput.ts +7 -3
- package/front_end/panels/ai_assistance/components/ChatMessage.ts +4 -2
- package/front_end/panels/application/preloading/PreloadingView.ts +8 -1
- package/front_end/panels/application/preloading/components/PreloadingDetailsReportView.ts +4 -1
- package/front_end/panels/application/preloading/components/PreloadingGrid.ts +2 -1
- package/front_end/panels/application/preloading/components/PreloadingString.ts +12 -3
- package/front_end/panels/application/preloading/helper/PreloadingForward.ts +14 -0
- package/front_end/panels/autofill/AutofillView.ts +4 -8
- package/front_end/panels/browser_debugger/CategorizedBreakpointsSidebarPane.ts +37 -3
- package/front_end/panels/changes/ChangesSidebar.ts +2 -6
- package/front_end/panels/common/AiCodeGenerationTeaser.ts +27 -8
- package/front_end/panels/console/ConsoleSidebar.ts +3 -11
- package/front_end/panels/elements/ComputedStyleWidget.ts +41 -29
- package/front_end/panels/elements/ElementStatePaneWidget.ts +1 -1
- package/front_end/panels/elements/ElementsTreeElement.ts +487 -426
- package/front_end/panels/elements/EventListenersWidget.ts +2 -4
- package/front_end/panels/elements/PropertiesWidget.ts +1 -2
- package/front_end/panels/elements/StylePropertyTreeElement.ts +18 -2
- package/front_end/panels/elements/computedStyleWidget.css +30 -0
- package/front_end/panels/lighthouse/LighthouseStartView.ts +3 -5
- package/front_end/panels/lighthouse/lighthouseStartView.css +6 -0
- package/front_end/panels/network/NetworkLogView.ts +67 -108
- package/front_end/panels/network/RequestConditionsDrawer.ts +40 -131
- package/front_end/panels/network/RequestInitiatorView.ts +19 -8
- package/front_end/panels/network/network-meta.ts +4 -27
- package/front_end/panels/settings/AISettingsTab.ts +1 -5
- package/front_end/panels/settings/SettingsScreen.ts +0 -51
- package/front_end/panels/settings/WorkspaceSettingsTab.ts +1 -1
- package/front_end/panels/sources/CallStackSidebarPane.ts +2 -2
- package/front_end/panels/timeline/AnimationsTrackAppender.ts +4 -1
- package/front_end/panels/timeline/InteractionsTrackAppender.ts +1 -1
- package/front_end/panels/timeline/TimelineUIUtils.ts +13 -16
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/ui/components/markdown_view/MarkdownLinksMap.ts +5 -1
- package/front_end/ui/components/text_editor/AiCodeCompletionProvider.ts +8 -0
- package/front_end/ui/components/text_editor/AiCodeGenerationProvider.ts +8 -0
- package/front_end/ui/components/text_editor/config.ts +6 -0
- package/front_end/ui/legacy/Toolbar.ts +16 -8
- package/front_end/ui/legacy/Treeoutline.ts +4 -4
- package/front_end/ui/legacy/UIUtils.ts +35 -4
- package/front_end/ui/legacy/components/utils/JSPresentationUtils.ts +6 -11
- package/front_end/ui/legacy/components/utils/Linkifier.ts +4 -7
- package/front_end/ui/visual_logging/KnownContextValues.ts +1 -0
- package/package.json +1 -1
- package/front_end/models/issues_manager/descriptions/federatedAuthRequestClientMetadataHttpNotFound.md +0 -1
- package/front_end/models/issues_manager/descriptions/federatedAuthRequestClientMetadataInvalidResponse.md +0 -1
- package/front_end/models/issues_manager/descriptions/federatedAuthRequestClientMetadataNoResponse.md +0 -1
- package/front_end/panels/elements/computedStyleSidebarPane.css +0 -18
|
@@ -379,6 +379,15 @@ export function isOpeningTag(context: TagTypeContext): context is OpeningTagCont
|
|
|
379
379
|
}
|
|
380
380
|
|
|
381
381
|
export interface ViewInput {
|
|
382
|
+
node: SDK.DOMModel.DOMNode|null;
|
|
383
|
+
isClosingTag: boolean;
|
|
384
|
+
expanded: boolean;
|
|
385
|
+
isExpandable: boolean;
|
|
386
|
+
isXMLMimeType: boolean;
|
|
387
|
+
updateRecord: Elements.ElementUpdateRecord.ElementUpdateRecord|null;
|
|
388
|
+
onHighlightSearchResults: () => void;
|
|
389
|
+
onExpand: () => void;
|
|
390
|
+
|
|
382
391
|
containerAdornerActive: boolean;
|
|
383
392
|
flexAdornerActive: boolean;
|
|
384
393
|
gridAdornerActive: boolean;
|
|
@@ -398,7 +407,6 @@ export interface ViewInput {
|
|
|
398
407
|
showViewSourceAdorner: boolean;
|
|
399
408
|
showScrollAdorner: boolean;
|
|
400
409
|
showScrollSnapAdorner: boolean;
|
|
401
|
-
nodeInfo?: DocumentFragment;
|
|
402
410
|
topLayerIndex: number;
|
|
403
411
|
scrollSnapAdornerActive: boolean;
|
|
404
412
|
|
|
@@ -436,7 +444,7 @@ export interface ViewOutput {
|
|
|
436
444
|
|
|
437
445
|
export function adornerRef(): DirectiveResult<typeof Lit.Directives.RefDirective> {
|
|
438
446
|
let adorner: Adorners.Adorner.Adorner|undefined;
|
|
439
|
-
return ref(
|
|
447
|
+
return ref(el => {
|
|
440
448
|
if (adorner) {
|
|
441
449
|
ElementsPanel.instance().deregisterAdorner(adorner);
|
|
442
450
|
}
|
|
@@ -467,6 +475,411 @@ function handleAdornerKeydown(cb: (event: Event) => void): (event: KeyboardEvent
|
|
|
467
475
|
};
|
|
468
476
|
}
|
|
469
477
|
|
|
478
|
+
function renderTitle(
|
|
479
|
+
node: SDK.DOMModel.DOMNode,
|
|
480
|
+
isClosingTag: boolean,
|
|
481
|
+
expanded: boolean,
|
|
482
|
+
isExpandable: boolean,
|
|
483
|
+
isXMLMimeType: boolean,
|
|
484
|
+
updateRecord: Elements.ElementUpdateRecord.ElementUpdateRecord|null,
|
|
485
|
+
onUpdateSearchHighlight: () => void,
|
|
486
|
+
onExpand: () => void,
|
|
487
|
+
): Lit.LitTemplate {
|
|
488
|
+
switch (node.nodeType()) {
|
|
489
|
+
case Node.ATTRIBUTE_NODE:
|
|
490
|
+
return renderAttribute({name: node.name as string, value: node.value as string}, updateRecord, true, node);
|
|
491
|
+
|
|
492
|
+
case Node.ELEMENT_NODE: {
|
|
493
|
+
if (node.pseudoType()) {
|
|
494
|
+
let pseudoElementName = node.nodeName();
|
|
495
|
+
const pseudoIdentifier = node.pseudoIdentifier();
|
|
496
|
+
if (pseudoIdentifier) {
|
|
497
|
+
pseudoElementName += `(${pseudoIdentifier})`;
|
|
498
|
+
}
|
|
499
|
+
return html`<span class="webkit-html-pseudo-element">${pseudoElementName}</span>\u200B`;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
const tagName = node.nodeNameInCorrectCase();
|
|
503
|
+
if (isClosingTag) {
|
|
504
|
+
return renderTag(node, tagName, true, expanded, true, updateRecord);
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
const openingTag = renderTag(node, tagName, false, expanded, false, updateRecord);
|
|
508
|
+
|
|
509
|
+
if (isExpandable) {
|
|
510
|
+
if (!expanded) {
|
|
511
|
+
return html`${openingTag}<devtools-elements-tree-expand-button .data=${
|
|
512
|
+
{clickHandler: onExpand} as
|
|
513
|
+
ElementsComponents.ElementsTreeExpandButton
|
|
514
|
+
.ElementsTreeExpandButtonData}></devtools-elements-tree-expand-button><span style="font-size: 0;"
|
|
515
|
+
>…</span>\u200B${renderTag(node, tagName, true, expanded, false, updateRecord)}`;
|
|
516
|
+
}
|
|
517
|
+
return openingTag;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
if (ElementsTreeElement.canShowInlineText(node)) {
|
|
521
|
+
const firstChild = node.firstChild;
|
|
522
|
+
if (!firstChild) {
|
|
523
|
+
throw new Error('ElementsTreeElement._nodeTitleInfo expects node.firstChild to be defined.');
|
|
524
|
+
}
|
|
525
|
+
const result = convertUnicodeCharsToHTMLEntities(firstChild.nodeValue());
|
|
526
|
+
const textContent = Platform.StringUtilities.collapseWhitespace(result.text);
|
|
527
|
+
|
|
528
|
+
const highlightAnimation = (updateRecord?.hasChangedChildren() || updateRecord?.isCharDataModified()) ?
|
|
529
|
+
ref(el => {
|
|
530
|
+
if (el) {
|
|
531
|
+
UI.UIUtils.runCSSAnimationOnce(el, 'dom-update-highlight');
|
|
532
|
+
}
|
|
533
|
+
}) :
|
|
534
|
+
nothing;
|
|
535
|
+
|
|
536
|
+
const renderTextNode = ref(el => {
|
|
537
|
+
if (el) {
|
|
538
|
+
el.textContent = textContent;
|
|
539
|
+
Highlighting.highlightRangesWithStyleClass(el, result.entityRanges, 'webkit-html-entity-value');
|
|
540
|
+
}
|
|
541
|
+
});
|
|
542
|
+
|
|
543
|
+
return html`${openingTag}<span class="webkit-html-text-node" jslog=${
|
|
544
|
+
VisualLogging.value('text-node').track({change: true, dblclick: true})} ${highlightAnimation} ${
|
|
545
|
+
renderTextNode}></span>\u200B${renderTag(node, tagName, true, expanded, false, updateRecord)}`;
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
if (isXMLMimeType || !ForbiddenClosingTagElements.has(tagName)) {
|
|
549
|
+
return html`${openingTag}${renderTag(node, tagName, true, expanded, false, updateRecord)}`;
|
|
550
|
+
}
|
|
551
|
+
return openingTag;
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
case Node.TEXT_NODE: {
|
|
555
|
+
if (node.parentNode && node.parentNode.nodeName().toLowerCase() === 'script') {
|
|
556
|
+
const text = node.nodeValue();
|
|
557
|
+
const highlightNode = ref(el => {
|
|
558
|
+
if (el) {
|
|
559
|
+
el.textContent = text.replace(/^[\n\r]+|\s+$/g, '');
|
|
560
|
+
void CodeHighlighter.CodeHighlighter.highlightNode(el, 'text/javascript').then(onUpdateSearchHighlight);
|
|
561
|
+
}
|
|
562
|
+
});
|
|
563
|
+
return html`<span class="webkit-html-text-node webkit-html-js-node" jslog=${
|
|
564
|
+
VisualLogging.value('script-text-node').track({change: true, dblclick: true})} ${highlightNode}></span>`;
|
|
565
|
+
}
|
|
566
|
+
if (node.parentNode && node.parentNode.nodeName().toLowerCase() === 'style') {
|
|
567
|
+
const text = node.nodeValue();
|
|
568
|
+
const highlightNode = ref(el => {
|
|
569
|
+
if (el) {
|
|
570
|
+
el.textContent = text.replace(/^[\n\r]+|\s+$/g, '');
|
|
571
|
+
void CodeHighlighter.CodeHighlighter.highlightNode(el, 'text/css').then(onUpdateSearchHighlight);
|
|
572
|
+
}
|
|
573
|
+
});
|
|
574
|
+
return html`<span class="webkit-html-text-node webkit-html-css-node" jslog=${
|
|
575
|
+
VisualLogging.value('css-text-node').track({change: true, dblclick: true})} ${highlightNode}></span>`;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
const result = convertUnicodeCharsToHTMLEntities(node.nodeValue());
|
|
579
|
+
const textContent = Platform.StringUtilities.collapseWhitespace(result.text);
|
|
580
|
+
const highlightAnimation = updateRecord?.isCharDataModified() ? ref(el => {
|
|
581
|
+
if (el) {
|
|
582
|
+
UI.UIUtils.runCSSAnimationOnce(el, 'dom-update-highlight');
|
|
583
|
+
}
|
|
584
|
+
}) :
|
|
585
|
+
nothing;
|
|
586
|
+
const renderTextNode = ref(el => {
|
|
587
|
+
if (el) {
|
|
588
|
+
el.textContent = textContent;
|
|
589
|
+
Highlighting.highlightRangesWithStyleClass(el, result.entityRanges, 'webkit-html-entity-value');
|
|
590
|
+
}
|
|
591
|
+
});
|
|
592
|
+
return html`"<span class="webkit-html-text-node" jslog=${VisualLogging.value('text-node').track({
|
|
593
|
+
change: true,
|
|
594
|
+
dblclick: true
|
|
595
|
+
})} ${highlightAnimation} ${renderTextNode}></span>"`;
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
case Node.COMMENT_NODE: {
|
|
599
|
+
return html`<span class="webkit-html-comment"><!--${node.nodeValue()}--></span>`;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
case Node.DOCUMENT_TYPE_NODE: {
|
|
603
|
+
let doctype = '<!DOCTYPE ' + node.nodeName();
|
|
604
|
+
if (node.publicId) {
|
|
605
|
+
doctype += ' PUBLIC "' + node.publicId + '"';
|
|
606
|
+
if (node.systemId) {
|
|
607
|
+
doctype += ' "' + node.systemId + '"';
|
|
608
|
+
}
|
|
609
|
+
} else if (node.systemId) {
|
|
610
|
+
doctype += ' SYSTEM "' + node.systemId + '"';
|
|
611
|
+
}
|
|
612
|
+
if (node.internalSubset) {
|
|
613
|
+
doctype += ' [' + node.internalSubset + ']';
|
|
614
|
+
}
|
|
615
|
+
doctype += '>';
|
|
616
|
+
return html`<span class="webkit-html-doctype">${doctype}</span>`;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
case Node.CDATA_SECTION_NODE: {
|
|
620
|
+
return html`<span class="webkit-html-text-node"><![CDATA[${node.nodeValue()}]]></span>`;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
case Node.DOCUMENT_NODE: {
|
|
624
|
+
const text = (node as SDK.DOMModel.DOMDocument).documentURL;
|
|
625
|
+
const linkify = ref(el => {
|
|
626
|
+
if (el) {
|
|
627
|
+
el.removeChildren();
|
|
628
|
+
el.appendChild(Components.Linkifier.Linkifier.linkifyURL(text, {
|
|
629
|
+
text,
|
|
630
|
+
preventClick: true,
|
|
631
|
+
showColumnNumber: false,
|
|
632
|
+
inlineFrameIndex: 0,
|
|
633
|
+
}));
|
|
634
|
+
}
|
|
635
|
+
});
|
|
636
|
+
return html`<span>#document (<span ${linkify}></span>)</span>`;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
case Node.DOCUMENT_FRAGMENT_NODE: {
|
|
640
|
+
return html`<span class="webkit-html-fragment">${
|
|
641
|
+
Platform.StringUtilities.collapseWhitespace(node.nodeNameInCorrectCase())}</span>`;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
default: {
|
|
645
|
+
return html`${Platform.StringUtilities.collapseWhitespace(node.nodeNameInCorrectCase())}`;
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
function renderAttribute(
|
|
651
|
+
attr: {name: string, value?: string}, updateRecord: Elements.ElementUpdateRecord.ElementUpdateRecord|null,
|
|
652
|
+
isDiff: boolean, node: SDK.DOMModel.DOMNode): Lit.LitTemplate {
|
|
653
|
+
const name = attr.name;
|
|
654
|
+
const value = attr.value || '';
|
|
655
|
+
const forceValue = isDiff;
|
|
656
|
+
const closingPunctuationRegex = /[\/;:\)\]\}]/g;
|
|
657
|
+
let highlightIndex = 0;
|
|
658
|
+
let highlightCount = 0;
|
|
659
|
+
let additionalHighlightOffset = 0;
|
|
660
|
+
|
|
661
|
+
function setValueWithEntities(element: Element, value: string): void {
|
|
662
|
+
const result = convertUnicodeCharsToHTMLEntities(value);
|
|
663
|
+
highlightCount = result.entityRanges.length;
|
|
664
|
+
const newValue = result.text.replace(closingPunctuationRegex, (match, replaceOffset) => {
|
|
665
|
+
while (highlightIndex < highlightCount && result.entityRanges[highlightIndex].offset < replaceOffset) {
|
|
666
|
+
result.entityRanges[highlightIndex].offset += additionalHighlightOffset;
|
|
667
|
+
++highlightIndex;
|
|
668
|
+
}
|
|
669
|
+
additionalHighlightOffset += 1;
|
|
670
|
+
return match + '\u200B';
|
|
671
|
+
});
|
|
672
|
+
|
|
673
|
+
while (highlightIndex < highlightCount) {
|
|
674
|
+
result.entityRanges[highlightIndex].offset += additionalHighlightOffset;
|
|
675
|
+
++highlightIndex;
|
|
676
|
+
}
|
|
677
|
+
element.setTextContentTruncatedIfNeeded(newValue);
|
|
678
|
+
Highlighting.highlightRangesWithStyleClass(element, result.entityRanges, 'webkit-html-entity-value');
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
const hasText = (forceValue || value.length > 0);
|
|
682
|
+
const jslog = VisualLogging.value(name === 'style' ? 'style-attribute' : 'attribute').track({
|
|
683
|
+
change: true,
|
|
684
|
+
dblclick: true,
|
|
685
|
+
});
|
|
686
|
+
|
|
687
|
+
const highlightNameAnimation = updateRecord?.isAttributeModified(name) && !hasText ? ref(el => {
|
|
688
|
+
if (el) {
|
|
689
|
+
UI.UIUtils.runCSSAnimationOnce(el, 'dom-update-highlight');
|
|
690
|
+
}
|
|
691
|
+
}) :
|
|
692
|
+
nothing;
|
|
693
|
+
|
|
694
|
+
const highlightValueAnimation = updateRecord?.isAttributeModified(name) && hasText ? ref(el => {
|
|
695
|
+
if (el) {
|
|
696
|
+
UI.UIUtils.runCSSAnimationOnce(el, 'dom-update-highlight');
|
|
697
|
+
}
|
|
698
|
+
}) :
|
|
699
|
+
nothing;
|
|
700
|
+
|
|
701
|
+
function linkifyValue(value: string): Element {
|
|
702
|
+
const rewrittenHref = node ? node.resolveURL(value) : null;
|
|
703
|
+
if (rewrittenHref === null) {
|
|
704
|
+
const span = document.createElement('span');
|
|
705
|
+
setValueWithEntities(span, value);
|
|
706
|
+
return span;
|
|
707
|
+
}
|
|
708
|
+
value = value.replace(closingPunctuationRegex, '$&\u200B');
|
|
709
|
+
if (value.startsWith('data:')) {
|
|
710
|
+
value = Platform.StringUtilities.trimMiddle(value, 60);
|
|
711
|
+
}
|
|
712
|
+
const link = node && node.nodeName().toLowerCase() === 'a' ?
|
|
713
|
+
Link.create(rewrittenHref, value, undefined, 'image-url') :
|
|
714
|
+
Components.Linkifier.Linkifier.linkifyURL(rewrittenHref, {
|
|
715
|
+
text: value,
|
|
716
|
+
preventClick: true,
|
|
717
|
+
showColumnNumber: false,
|
|
718
|
+
inlineFrameIndex: 0,
|
|
719
|
+
});
|
|
720
|
+
return ImagePreviewPopover.setImageUrl(link, rewrittenHref);
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
function linkifySrcset(value: string): DocumentFragment {
|
|
724
|
+
// Splitting normally on commas or spaces will break on valid srcsets "foo 1x,bar 2x" and "data:,foo 1x".
|
|
725
|
+
const fragment = document.createDocumentFragment();
|
|
726
|
+
let i = 0;
|
|
727
|
+
while (value.length) {
|
|
728
|
+
if (i++ > 0) {
|
|
729
|
+
UI.UIUtils.createTextChild(fragment, ' ');
|
|
730
|
+
}
|
|
731
|
+
value = value.trim();
|
|
732
|
+
let url = '';
|
|
733
|
+
let descriptor = '';
|
|
734
|
+
const indexOfSpace = value.search(/\s/);
|
|
735
|
+
if (indexOfSpace === -1) {
|
|
736
|
+
url = value;
|
|
737
|
+
} else if (indexOfSpace > 0 && value[indexOfSpace - 1] === ',') {
|
|
738
|
+
url = value.substring(0, indexOfSpace);
|
|
739
|
+
} else {
|
|
740
|
+
url = value.substring(0, indexOfSpace);
|
|
741
|
+
const indexOfComma = value.indexOf(',', indexOfSpace);
|
|
742
|
+
if (indexOfComma !== -1) {
|
|
743
|
+
descriptor = value.substring(indexOfSpace, indexOfComma + 1);
|
|
744
|
+
} else {
|
|
745
|
+
descriptor = value.substring(indexOfSpace);
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
if (url) {
|
|
750
|
+
if (url.endsWith(',')) {
|
|
751
|
+
fragment.appendChild(linkifyValue(url.substring(0, url.length - 1)));
|
|
752
|
+
UI.UIUtils.createTextChild(fragment, ',');
|
|
753
|
+
} else {
|
|
754
|
+
fragment.appendChild(linkifyValue(url));
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
if (descriptor) {
|
|
758
|
+
UI.UIUtils.createTextChild(fragment, descriptor);
|
|
759
|
+
}
|
|
760
|
+
value = value.substring(url.length + descriptor.length);
|
|
761
|
+
}
|
|
762
|
+
return fragment;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
const nodeName = node ? node.nodeName().toLowerCase() : '';
|
|
766
|
+
const setAttrValue = ref(el => {
|
|
767
|
+
if (!el) {
|
|
768
|
+
return;
|
|
769
|
+
}
|
|
770
|
+
const valueElement = el as HTMLElement;
|
|
771
|
+
valueElement.removeChildren();
|
|
772
|
+
if (nodeName && (name === 'src' || name === 'href') && value) {
|
|
773
|
+
valueElement.appendChild(linkifyValue(value));
|
|
774
|
+
} else if ((nodeName === 'img' || nodeName === 'source') && name === 'srcset') {
|
|
775
|
+
valueElement.appendChild(linkifySrcset(value));
|
|
776
|
+
} else if (nodeName === 'image' && (name === 'xlink:href' || name === 'href')) {
|
|
777
|
+
valueElement.appendChild(linkifySrcset(value));
|
|
778
|
+
} else {
|
|
779
|
+
setValueWithEntities(valueElement, value);
|
|
780
|
+
}
|
|
781
|
+
});
|
|
782
|
+
|
|
783
|
+
const relationRef =
|
|
784
|
+
(relation: Protocol.DOM.GetElementByRelationRequestRelation, tooltip: string): ReturnType<typeof ref> =>
|
|
785
|
+
ref((el): void => {
|
|
786
|
+
if (!el) {
|
|
787
|
+
return;
|
|
788
|
+
}
|
|
789
|
+
void (async(): Promise<void> => {
|
|
790
|
+
const relatedElementId = await node.domModel().getElementByRelation(node.id, relation);
|
|
791
|
+
const relatedElement = node.domModel().nodeForId(relatedElementId);
|
|
792
|
+
if (!relatedElement) {
|
|
793
|
+
return;
|
|
794
|
+
}
|
|
795
|
+
const link = PanelsCommon.DOMLinkifier.Linkifier.instance().linkify(relatedElement, {
|
|
796
|
+
preventKeyboardFocus: true,
|
|
797
|
+
tooltip,
|
|
798
|
+
textContent: el.textContent || undefined,
|
|
799
|
+
isDynamicLink: true,
|
|
800
|
+
});
|
|
801
|
+
el.removeChildren();
|
|
802
|
+
el.append(link);
|
|
803
|
+
})();
|
|
804
|
+
});
|
|
805
|
+
|
|
806
|
+
let relationRefDirective: ReturnType<typeof relationRef> = ref(() => {});
|
|
807
|
+
if (!value) {
|
|
808
|
+
if (name === 'popovertarget') {
|
|
809
|
+
relationRefDirective = relationRef(
|
|
810
|
+
Protocol.DOM.GetElementByRelationRequestRelation.PopoverTarget, i18nString(UIStrings.showPopoverTarget));
|
|
811
|
+
} else if (name === 'interesttarget') {
|
|
812
|
+
relationRefDirective = relationRef(
|
|
813
|
+
Protocol.DOM.GetElementByRelationRequestRelation.InterestTarget, i18nString(UIStrings.showInterestTarget));
|
|
814
|
+
} else if (name === 'commandfor') {
|
|
815
|
+
relationRefDirective = relationRef(
|
|
816
|
+
Protocol.DOM.GetElementByRelationRequestRelation.CommandFor, i18nString(UIStrings.showCommandForTarget));
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
let valueRelationRefDirective: ReturnType<typeof relationRef> = ref(() => {});
|
|
821
|
+
if (value) {
|
|
822
|
+
if (name === 'popovertarget') {
|
|
823
|
+
valueRelationRefDirective = relationRef(
|
|
824
|
+
Protocol.DOM.GetElementByRelationRequestRelation.PopoverTarget, i18nString(UIStrings.showPopoverTarget));
|
|
825
|
+
} else if (name === 'interesttarget') {
|
|
826
|
+
valueRelationRefDirective = relationRef(
|
|
827
|
+
Protocol.DOM.GetElementByRelationRequestRelation.InterestTarget, i18nString(UIStrings.showInterestTarget));
|
|
828
|
+
} else if (name === 'commandfor') {
|
|
829
|
+
valueRelationRefDirective = relationRef(
|
|
830
|
+
Protocol.DOM.GetElementByRelationRequestRelation.CommandFor, i18nString(UIStrings.showCommandForTarget));
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
return html`<span class="webkit-html-attribute" jslog=${jslog}><span class="webkit-html-attribute-name" ${
|
|
835
|
+
highlightNameAnimation} ${relationRefDirective}>${name}</span>${
|
|
836
|
+
hasText ? html`=\u200B"<span class="webkit-html-attribute-value" ${highlightValueAnimation} ${setAttrValue} ${
|
|
837
|
+
valueRelationRefDirective}></span>"` :
|
|
838
|
+
nothing}</span>`;
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
function renderTag(
|
|
842
|
+
node: SDK.DOMModel.DOMNode, tagName: string, isClosingTag: boolean, expanded: boolean,
|
|
843
|
+
isDistinctTreeElement: boolean,
|
|
844
|
+
updateRecord: Elements.ElementUpdateRecord.ElementUpdateRecord|null): Lit.LitTemplate {
|
|
845
|
+
const classMap = {
|
|
846
|
+
'webkit-html-tag': true,
|
|
847
|
+
close: isClosingTag && isDistinctTreeElement,
|
|
848
|
+
};
|
|
849
|
+
|
|
850
|
+
let hasUpdates = false;
|
|
851
|
+
const attributes = !isClosingTag && node.hasAttributes() ? node.attributes() : [];
|
|
852
|
+
|
|
853
|
+
if (!isClosingTag && updateRecord) {
|
|
854
|
+
hasUpdates = updateRecord.hasRemovedAttributes() || updateRecord.hasRemovedChildren();
|
|
855
|
+
hasUpdates = hasUpdates || (!expanded && updateRecord.hasChangedChildren());
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
const highlightAnimation = hasUpdates ? ref(el => {
|
|
859
|
+
if (el) {
|
|
860
|
+
UI.UIUtils.runCSSAnimationOnce(el, 'dom-update-highlight');
|
|
861
|
+
}
|
|
862
|
+
}) :
|
|
863
|
+
nothing;
|
|
864
|
+
|
|
865
|
+
// We are taking full text content of the tag, including attributes and children, to set the aria label.
|
|
866
|
+
// FIXME: we should compute the aria label ourselves if it is event needed.
|
|
867
|
+
const setAriaLabel = ref(el => {
|
|
868
|
+
if (el?.textContent) {
|
|
869
|
+
UI.ARIAUtils.setLabel(el, el.textContent);
|
|
870
|
+
}
|
|
871
|
+
});
|
|
872
|
+
|
|
873
|
+
const tagNameClass = isClosingTag ? 'webkit-html-close-tag-name' : 'webkit-html-tag-name';
|
|
874
|
+
const tagString = (isClosingTag ? '/' : '') + tagName;
|
|
875
|
+
const jslog = !isClosingTag ? VisualLogging.value('tag-name').track({change: true, dblclick: true}) : '';
|
|
876
|
+
|
|
877
|
+
return html`<span
|
|
878
|
+
class=${Lit.Directives.classMap(classMap)} ${setAriaLabel}
|
|
879
|
+
><<span class=${tagNameClass} jslog=${jslog || nothing} ${highlightAnimation}>${tagString}</span>${
|
|
880
|
+
attributes.map(attr => html` ${renderAttribute(attr, updateRecord, false, node)}`)}></span>\u200B`;
|
|
881
|
+
}
|
|
882
|
+
|
|
470
883
|
export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLElement): void => {
|
|
471
884
|
const hasAdorners = input.showAdAdorner || input.showContainerAdorner || input.showFlexAdorner ||
|
|
472
885
|
input.showGridAdorner || input.showGridLanesAdorner || input.showMediaAdorner || input.showPopoverAdorner ||
|
|
@@ -479,7 +892,16 @@ export const DEFAULT_VIEW = (input: ViewInput, output: ViewOutput, target: HTMLE
|
|
|
479
892
|
// clang-format off
|
|
480
893
|
render(html`
|
|
481
894
|
<div ${ref(el => { output.contentElement = el as HTMLElement; })}>
|
|
482
|
-
${input.
|
|
895
|
+
${input.node ? html`<span class="highlight">${renderTitle(
|
|
896
|
+
input.node,
|
|
897
|
+
input.isClosingTag,
|
|
898
|
+
input.expanded,
|
|
899
|
+
input.isExpandable,
|
|
900
|
+
input.isXMLMimeType,
|
|
901
|
+
input.updateRecord,
|
|
902
|
+
input.onHighlightSearchResults,
|
|
903
|
+
input.onExpand,
|
|
904
|
+
)}</span>` : nothing}
|
|
483
905
|
${input.isHovered || input.isSelected ? html`
|
|
484
906
|
<div class="selection fill" style=${`margin-left: ${-input.indent}px`}></div>
|
|
485
907
|
` : nothing}
|
|
@@ -681,9 +1103,6 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
681
1103
|
nodeInternal: SDK.DOMModel.DOMNode;
|
|
682
1104
|
override treeOutline: ElementsTreeOutline|null;
|
|
683
1105
|
|
|
684
|
-
// Handled by the view output for now.
|
|
685
|
-
contentElement!: HTMLElement;
|
|
686
|
-
|
|
687
1106
|
private searchQuery: string|null;
|
|
688
1107
|
#expandedChildrenLimit: number;
|
|
689
1108
|
private readonly decorationsThrottler: Common.Throttler.Throttler;
|
|
@@ -699,7 +1118,6 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
699
1118
|
readonly tagTypeContext: TagTypeContext;
|
|
700
1119
|
|
|
701
1120
|
#adornersThrottler = new Common.Throttler.Throttler(100);
|
|
702
|
-
#nodeInfo?: DocumentFragment;
|
|
703
1121
|
#containerAdornerActive = false;
|
|
704
1122
|
#flexAdornerActive = false;
|
|
705
1123
|
#gridAdornerActive = false;
|
|
@@ -713,6 +1131,12 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
713
1131
|
#descendantDecorations: Decoration[] = [];
|
|
714
1132
|
#decorationsTooltip = '';
|
|
715
1133
|
|
|
1134
|
+
#updateRecord: Elements.ElementUpdateRecord.ElementUpdateRecord|null = null;
|
|
1135
|
+
|
|
1136
|
+
// Used to add the content to TreeElement's title element.
|
|
1137
|
+
// Relied on by web tests.
|
|
1138
|
+
#contentElement?: HTMLElement;
|
|
1139
|
+
|
|
716
1140
|
constructor(node: SDK.DOMModel.DOMNode, isClosingTag?: boolean) {
|
|
717
1141
|
// The title will be updated in onattach.
|
|
718
1142
|
super();
|
|
@@ -816,9 +1240,23 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
816
1240
|
}
|
|
817
1241
|
}
|
|
818
1242
|
|
|
819
|
-
|
|
1243
|
+
// ClearNode param is used to clean DOM after in-place editing..
|
|
1244
|
+
performUpdate(clearNode = false): void {
|
|
1245
|
+
if (this.editing) {
|
|
1246
|
+
return;
|
|
1247
|
+
}
|
|
1248
|
+
const output: ViewOutput = {};
|
|
820
1249
|
DEFAULT_VIEW(
|
|
821
1250
|
{
|
|
1251
|
+
node: !clearNode ? this.nodeInternal : null,
|
|
1252
|
+
isClosingTag: this.isClosingTag(),
|
|
1253
|
+
expanded: this.expanded,
|
|
1254
|
+
isExpandable: this.isExpandable(),
|
|
1255
|
+
isXMLMimeType: Boolean(this.treeOutline?.isXMLMimeType),
|
|
1256
|
+
updateRecord: this.#updateRecord,
|
|
1257
|
+
onHighlightSearchResults: () => this.#highlightSearchResults(),
|
|
1258
|
+
onExpand: () => this.expand(),
|
|
1259
|
+
|
|
822
1260
|
containerAdornerActive: this.#containerAdornerActive,
|
|
823
1261
|
showAdAdorner: this.nodeInternal.isAdFrameNode(),
|
|
824
1262
|
showContainerAdorner: Boolean(this.#layout?.containerType) && !this.isClosingTag(),
|
|
@@ -847,7 +1285,6 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
847
1285
|
showSlotAdorner: Boolean(this.nodeInternal.assignedSlot) && !this.isClosingTag(),
|
|
848
1286
|
showStartingStyleAdorner: this.nodeInternal.affectedByStartingStyles() && !this.isClosingTag(),
|
|
849
1287
|
startingStyleAdornerActive: this.#startingStyleAdornerActive,
|
|
850
|
-
nodeInfo: this.#nodeInfo,
|
|
851
1288
|
onStartingStyleAdornerClick: (event: Event) => this.#onStartingStyleAdornerClick(event),
|
|
852
1289
|
onSlotAdornerClick: () => {
|
|
853
1290
|
if (this.nodeInternal.assignedSlot) {
|
|
@@ -888,7 +1325,12 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
888
1325
|
}
|
|
889
1326
|
},
|
|
890
1327
|
},
|
|
891
|
-
|
|
1328
|
+
output, this.listItemElement);
|
|
1329
|
+
|
|
1330
|
+
this.#contentElement = output.contentElement;
|
|
1331
|
+
if (this.#updateRecord) {
|
|
1332
|
+
this.#updateRecord = null;
|
|
1333
|
+
}
|
|
892
1334
|
}
|
|
893
1335
|
|
|
894
1336
|
#onContainerAdornerClick(event: Event): void {
|
|
@@ -1096,11 +1538,16 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
1096
1538
|
this.#expandedChildrenLimit = expandedChildrenLimit;
|
|
1097
1539
|
}
|
|
1098
1540
|
|
|
1541
|
+
onTopLayerIndexChanged(): void {
|
|
1542
|
+
this.performUpdate();
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1099
1545
|
override onbind(): void {
|
|
1100
1546
|
this.performUpdate();
|
|
1101
1547
|
if (this.treeOutline && !this.isClosingTag()) {
|
|
1102
1548
|
this.treeOutline.treeElementByNode.set(this.nodeInternal, this);
|
|
1103
|
-
this.nodeInternal.addEventListener(
|
|
1549
|
+
this.nodeInternal.addEventListener(
|
|
1550
|
+
SDK.DOMModel.DOMNodeEvents.TOP_LAYER_INDEX_CHANGED, this.onTopLayerIndexChanged, this);
|
|
1104
1551
|
this.nodeInternal.addEventListener(
|
|
1105
1552
|
SDK.DOMModel.DOMNodeEvents.SCROLLABLE_FLAG_UPDATED, this.#onScrollableFlagUpdated, this);
|
|
1106
1553
|
this.nodeInternal.addEventListener(
|
|
@@ -1127,6 +1574,14 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
1127
1574
|
// element is bound again.
|
|
1128
1575
|
DEFAULT_VIEW(
|
|
1129
1576
|
{
|
|
1577
|
+
node: null,
|
|
1578
|
+
isClosingTag: false,
|
|
1579
|
+
expanded: false,
|
|
1580
|
+
isExpandable: false,
|
|
1581
|
+
isXMLMimeType: false,
|
|
1582
|
+
updateRecord: null,
|
|
1583
|
+
onHighlightSearchResults: () => {},
|
|
1584
|
+
onExpand: () => {},
|
|
1130
1585
|
containerAdornerActive: false,
|
|
1131
1586
|
showAdAdorner: false,
|
|
1132
1587
|
showContainerAdorner: false,
|
|
@@ -1148,7 +1603,6 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
1148
1603
|
showSlotAdorner: false,
|
|
1149
1604
|
showStartingStyleAdorner: false,
|
|
1150
1605
|
startingStyleAdornerActive: false,
|
|
1151
|
-
nodeInfo: this.#nodeInfo,
|
|
1152
1606
|
onStartingStyleAdornerClick: () => {},
|
|
1153
1607
|
onSlotAdornerClick: () => {},
|
|
1154
1608
|
topLayerIndex: -1,
|
|
@@ -1170,12 +1624,13 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
1170
1624
|
decorationsTooltip: '',
|
|
1171
1625
|
indent: 0,
|
|
1172
1626
|
},
|
|
1173
|
-
|
|
1627
|
+
{}, this.listItemElement);
|
|
1174
1628
|
|
|
1175
1629
|
if (this.treeOutline && this.treeOutline.treeElementByNode.get(this.nodeInternal) === this) {
|
|
1176
1630
|
this.treeOutline.treeElementByNode.delete(this.nodeInternal);
|
|
1177
1631
|
}
|
|
1178
|
-
this.nodeInternal.removeEventListener(
|
|
1632
|
+
this.nodeInternal.removeEventListener(
|
|
1633
|
+
SDK.DOMModel.DOMNodeEvents.TOP_LAYER_INDEX_CHANGED, this.onTopLayerIndexChanged, this);
|
|
1179
1634
|
this.nodeInternal.removeEventListener(
|
|
1180
1635
|
SDK.DOMModel.DOMNodeEvents.SCROLLABLE_FLAG_UPDATED, this.#onScrollableFlagUpdated, this);
|
|
1181
1636
|
this.nodeInternal.removeEventListener(
|
|
@@ -1743,7 +2198,10 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
1743
2198
|
// Cannot just convert the textual html into an element without
|
|
1744
2199
|
// a parent node. Use a temporary span container for the HTML.
|
|
1745
2200
|
const container = document.createElement('span');
|
|
1746
|
-
|
|
2201
|
+
|
|
2202
|
+
// eslint-disable-next-line @devtools/no-lit-render-outside-of-view
|
|
2203
|
+
Lit.render(renderAttribute({name: ' ', value: ''}, null, false, this.nodeInternal), container);
|
|
2204
|
+
const attr = container.firstElementChild as HTMLElement;
|
|
1747
2205
|
attr.style.marginLeft = '2px'; // overrides the .editing margin rule
|
|
1748
2206
|
attr.style.marginRight = '2px'; // overrides the .editing margin rule
|
|
1749
2207
|
attr.setAttribute('jslog', `${VisualLogging.value('new-attribute').track({change: true, resize: true})}`);
|
|
@@ -1789,7 +2247,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
1789
2247
|
|
|
1790
2248
|
// Make sure elementForSelection is not a child of attributeValueElement.
|
|
1791
2249
|
elementForSelection =
|
|
1792
|
-
attributeValueElement
|
|
2250
|
+
attributeValueElement?.isAncestor(elementForSelection) ? attributeValueElement : elementForSelection;
|
|
1793
2251
|
|
|
1794
2252
|
function removeZeroWidthSpaceRecursive(node: Node): void {
|
|
1795
2253
|
if (node.nodeType === Node.TEXT_NODE) {
|
|
@@ -1825,7 +2283,7 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
1825
2283
|
return '';
|
|
1826
2284
|
}
|
|
1827
2285
|
|
|
1828
|
-
if (!Common.ParsedURL.ParsedURL.fromString(attributeValueElement
|
|
2286
|
+
if (!Common.ParsedURL.ParsedURL.fromString(attributeValueElement?.textContent || '')) {
|
|
1829
2287
|
config.setPostKeydownFinishHandler(postKeyDownFinishHandler);
|
|
1830
2288
|
}
|
|
1831
2289
|
|
|
@@ -1962,7 +2420,9 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
1962
2420
|
// Hide header items.
|
|
1963
2421
|
let child: (ChildNode|null) = this.listItemElement.firstChild;
|
|
1964
2422
|
while (child) {
|
|
1965
|
-
(child
|
|
2423
|
+
if (child instanceof HTMLElement) {
|
|
2424
|
+
child.style.display = 'none';
|
|
2425
|
+
}
|
|
1966
2426
|
child = child.nextSibling;
|
|
1967
2427
|
}
|
|
1968
2428
|
// Hide children item.
|
|
@@ -2054,7 +2514,9 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
2054
2514
|
// Unhide header items.
|
|
2055
2515
|
let child: (ChildNode|null) = this.listItemElement.firstChild;
|
|
2056
2516
|
while (child) {
|
|
2057
|
-
(child
|
|
2517
|
+
if (child instanceof HTMLElement) {
|
|
2518
|
+
child.style.removeProperty('display');
|
|
2519
|
+
}
|
|
2058
2520
|
child = child.nextSibling;
|
|
2059
2521
|
}
|
|
2060
2522
|
|
|
@@ -2242,8 +2704,8 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
2242
2704
|
if (this.editing) {
|
|
2243
2705
|
return;
|
|
2244
2706
|
}
|
|
2245
|
-
|
|
2246
|
-
this.#
|
|
2707
|
+
this.performUpdate(/* clearNode= */ true);
|
|
2708
|
+
this.#updateRecord = updateRecord ?? null;
|
|
2247
2709
|
if (this.nodeInternal.nodeType() === Node.DOCUMENT_FRAGMENT_NODE && this.nodeInternal.isInShadowTree() &&
|
|
2248
2710
|
this.nodeInternal.shadowRootType()) {
|
|
2249
2711
|
this.childrenListElement.classList.add('shadow-root');
|
|
@@ -2261,8 +2723,10 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
2261
2723
|
}
|
|
2262
2724
|
}
|
|
2263
2725
|
this.performUpdate();
|
|
2264
|
-
|
|
2265
|
-
|
|
2726
|
+
if (this.#contentElement) {
|
|
2727
|
+
// fixme: we probably do not need a title element in the new tree outline.
|
|
2728
|
+
this.title = this.#contentElement;
|
|
2729
|
+
}
|
|
2266
2730
|
this.updateDecorations();
|
|
2267
2731
|
|
|
2268
2732
|
// If there is an issue with this node, make sure to update it.
|
|
@@ -2367,409 +2831,6 @@ export class ElementsTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
2367
2831
|
}
|
|
2368
2832
|
}
|
|
2369
2833
|
|
|
2370
|
-
private buildAttributeDOM(
|
|
2371
|
-
parentElement: Element|DocumentFragment, name: string, value: string,
|
|
2372
|
-
updateRecord: Elements.ElementUpdateRecord.ElementUpdateRecord|null, forceValue?: boolean,
|
|
2373
|
-
node?: SDK.DOMModel.DOMNode): HTMLElement {
|
|
2374
|
-
const closingPunctuationRegex = /[\/;:\)\]\}]/g;
|
|
2375
|
-
let highlightIndex = 0;
|
|
2376
|
-
let highlightCount = 0;
|
|
2377
|
-
let additionalHighlightOffset = 0;
|
|
2378
|
-
|
|
2379
|
-
function setValueWithEntities(this: ElementsTreeElement, element: Element, value: string): void {
|
|
2380
|
-
const result = convertUnicodeCharsToHTMLEntities(value);
|
|
2381
|
-
highlightCount = result.entityRanges.length;
|
|
2382
|
-
value = result.text.replace(closingPunctuationRegex, (match, replaceOffset) => {
|
|
2383
|
-
while (highlightIndex < highlightCount && result.entityRanges[highlightIndex].offset < replaceOffset) {
|
|
2384
|
-
result.entityRanges[highlightIndex].offset += additionalHighlightOffset;
|
|
2385
|
-
++highlightIndex;
|
|
2386
|
-
}
|
|
2387
|
-
additionalHighlightOffset += 1;
|
|
2388
|
-
return match + '\u200B';
|
|
2389
|
-
});
|
|
2390
|
-
|
|
2391
|
-
while (highlightIndex < highlightCount) {
|
|
2392
|
-
result.entityRanges[highlightIndex].offset += additionalHighlightOffset;
|
|
2393
|
-
++highlightIndex;
|
|
2394
|
-
}
|
|
2395
|
-
element.setTextContentTruncatedIfNeeded(value);
|
|
2396
|
-
Highlighting.highlightRangesWithStyleClass(element, result.entityRanges, 'webkit-html-entity-value');
|
|
2397
|
-
}
|
|
2398
|
-
|
|
2399
|
-
const hasText = (forceValue || value.length > 0);
|
|
2400
|
-
const attrSpanElement = parentElement.createChild('span', 'webkit-html-attribute');
|
|
2401
|
-
attrSpanElement.setAttribute(
|
|
2402
|
-
'jslog', `${VisualLogging.value(name === 'style' ? 'style-attribute' : 'attribute').track({
|
|
2403
|
-
change: true,
|
|
2404
|
-
dblclick: true,
|
|
2405
|
-
})}`);
|
|
2406
|
-
|
|
2407
|
-
const attrNameElement = attrSpanElement.createChild('span', 'webkit-html-attribute-name');
|
|
2408
|
-
attrNameElement.textContent = name;
|
|
2409
|
-
|
|
2410
|
-
if (hasText) {
|
|
2411
|
-
UI.UIUtils.createTextChild(attrSpanElement, '=\u200B"');
|
|
2412
|
-
}
|
|
2413
|
-
|
|
2414
|
-
const attrValueElement = attrSpanElement.createChild('span', 'webkit-html-attribute-value');
|
|
2415
|
-
|
|
2416
|
-
if (updateRecord?.isAttributeModified(name)) {
|
|
2417
|
-
UI.UIUtils.runCSSAnimationOnce(hasText ? attrValueElement : attrNameElement, 'dom-update-highlight');
|
|
2418
|
-
}
|
|
2419
|
-
|
|
2420
|
-
function linkifyValue(this: ElementsTreeElement, value: string): Element {
|
|
2421
|
-
const rewrittenHref = node ? node.resolveURL(value) : null;
|
|
2422
|
-
if (rewrittenHref === null) {
|
|
2423
|
-
const span = document.createElement('span');
|
|
2424
|
-
setValueWithEntities.call(this, span, value);
|
|
2425
|
-
return span;
|
|
2426
|
-
}
|
|
2427
|
-
value = value.replace(closingPunctuationRegex, '$&\u200B');
|
|
2428
|
-
if (value.startsWith('data:')) {
|
|
2429
|
-
value = Platform.StringUtilities.trimMiddle(value, 60);
|
|
2430
|
-
}
|
|
2431
|
-
const link = node && node.nodeName().toLowerCase() === 'a' ?
|
|
2432
|
-
Link.create(rewrittenHref, value, undefined, 'image-url') :
|
|
2433
|
-
Components.Linkifier.Linkifier.linkifyURL(rewrittenHref, {
|
|
2434
|
-
text: value,
|
|
2435
|
-
preventClick: true,
|
|
2436
|
-
showColumnNumber: false,
|
|
2437
|
-
inlineFrameIndex: 0,
|
|
2438
|
-
});
|
|
2439
|
-
return ImagePreviewPopover.setImageUrl(link, rewrittenHref);
|
|
2440
|
-
}
|
|
2441
|
-
|
|
2442
|
-
const nodeName = node ? node.nodeName().toLowerCase() : '';
|
|
2443
|
-
// If the href/src attribute has a value, attempt to link it.
|
|
2444
|
-
// There's no point trying to link it if the value is empty (e.g. <a href=''>).
|
|
2445
|
-
if (nodeName && (name === 'src' || name === 'href') && value) {
|
|
2446
|
-
attrValueElement.appendChild(linkifyValue.call(this, value));
|
|
2447
|
-
} else if ((nodeName === 'img' || nodeName === 'source') && name === 'srcset') {
|
|
2448
|
-
attrValueElement.appendChild(linkifySrcset.call(this, value));
|
|
2449
|
-
} else if (nodeName === 'image' && (name === 'xlink:href' || name === 'href')) {
|
|
2450
|
-
attrValueElement.appendChild(linkifySrcset.call(this, value));
|
|
2451
|
-
} else {
|
|
2452
|
-
setValueWithEntities.call(this, attrValueElement, value);
|
|
2453
|
-
}
|
|
2454
|
-
|
|
2455
|
-
switch (name) {
|
|
2456
|
-
case 'popovertarget': {
|
|
2457
|
-
const linkedPart = value ? attrValueElement : attrNameElement;
|
|
2458
|
-
void this.linkifyElementByRelation(
|
|
2459
|
-
linkedPart, Protocol.DOM.GetElementByRelationRequestRelation.PopoverTarget,
|
|
2460
|
-
i18nString(UIStrings.showPopoverTarget));
|
|
2461
|
-
break;
|
|
2462
|
-
}
|
|
2463
|
-
case 'interesttarget': {
|
|
2464
|
-
const linkedPart = value ? attrValueElement : attrNameElement;
|
|
2465
|
-
void this.linkifyElementByRelation(
|
|
2466
|
-
linkedPart, Protocol.DOM.GetElementByRelationRequestRelation.InterestTarget,
|
|
2467
|
-
i18nString(UIStrings.showInterestTarget));
|
|
2468
|
-
break;
|
|
2469
|
-
}
|
|
2470
|
-
case 'commandfor': {
|
|
2471
|
-
const linkedPart = value ? attrValueElement : attrNameElement;
|
|
2472
|
-
void this.linkifyElementByRelation(
|
|
2473
|
-
linkedPart, Protocol.DOM.GetElementByRelationRequestRelation.CommandFor,
|
|
2474
|
-
i18nString(UIStrings.showCommandForTarget));
|
|
2475
|
-
break;
|
|
2476
|
-
}
|
|
2477
|
-
}
|
|
2478
|
-
|
|
2479
|
-
if (hasText) {
|
|
2480
|
-
UI.UIUtils.createTextChild(attrSpanElement, '"');
|
|
2481
|
-
}
|
|
2482
|
-
|
|
2483
|
-
function linkifySrcset(this: ElementsTreeElement, value: string): DocumentFragment {
|
|
2484
|
-
// Splitting normally on commas or spaces will break on valid srcsets "foo 1x,bar 2x" and "data:,foo 1x".
|
|
2485
|
-
// 1) Let the index of the next space be `indexOfSpace`.
|
|
2486
|
-
// 2a) If the character at `indexOfSpace - 1` is a comma, collect the preceding characters up to
|
|
2487
|
-
// `indexOfSpace - 1` as a URL and repeat step 1).
|
|
2488
|
-
// 2b) Else, collect the preceding characters as a URL.
|
|
2489
|
-
// 3) Collect the characters from `indexOfSpace` up to the next comma as the size descriptor and repeat step 1).
|
|
2490
|
-
// https://html.spec.whatwg.org/C/#parse-a-srcset-attribute
|
|
2491
|
-
const fragment = document.createDocumentFragment();
|
|
2492
|
-
let i = 0;
|
|
2493
|
-
while (value.length) {
|
|
2494
|
-
if (i++ > 0) {
|
|
2495
|
-
UI.UIUtils.createTextChild(fragment, ' ');
|
|
2496
|
-
}
|
|
2497
|
-
value = value.trim();
|
|
2498
|
-
// The url and descriptor may end with a separating comma.
|
|
2499
|
-
let url = '';
|
|
2500
|
-
let descriptor = '';
|
|
2501
|
-
const indexOfSpace = value.search(/\s/);
|
|
2502
|
-
if (indexOfSpace === -1) {
|
|
2503
|
-
url = value;
|
|
2504
|
-
} else if (indexOfSpace > 0 && value[indexOfSpace - 1] === ',') {
|
|
2505
|
-
url = value.substring(0, indexOfSpace);
|
|
2506
|
-
} else {
|
|
2507
|
-
url = value.substring(0, indexOfSpace);
|
|
2508
|
-
const indexOfComma = value.indexOf(',', indexOfSpace);
|
|
2509
|
-
if (indexOfComma !== -1) {
|
|
2510
|
-
descriptor = value.substring(indexOfSpace, indexOfComma + 1);
|
|
2511
|
-
} else {
|
|
2512
|
-
descriptor = value.substring(indexOfSpace);
|
|
2513
|
-
}
|
|
2514
|
-
}
|
|
2515
|
-
|
|
2516
|
-
if (url) {
|
|
2517
|
-
// Up to one trailing comma should be removed from `url`.
|
|
2518
|
-
if (url.endsWith(',')) {
|
|
2519
|
-
fragment.appendChild(linkifyValue.call(this, url.substring(0, url.length - 1)));
|
|
2520
|
-
UI.UIUtils.createTextChild(fragment, ',');
|
|
2521
|
-
} else {
|
|
2522
|
-
fragment.appendChild(linkifyValue.call(this, url));
|
|
2523
|
-
}
|
|
2524
|
-
}
|
|
2525
|
-
if (descriptor) {
|
|
2526
|
-
UI.UIUtils.createTextChild(fragment, descriptor);
|
|
2527
|
-
}
|
|
2528
|
-
value = value.substring(url.length + descriptor.length);
|
|
2529
|
-
}
|
|
2530
|
-
return fragment;
|
|
2531
|
-
}
|
|
2532
|
-
|
|
2533
|
-
return attrSpanElement;
|
|
2534
|
-
}
|
|
2535
|
-
|
|
2536
|
-
private async linkifyElementByRelation(
|
|
2537
|
-
linkContainer: Element, relation: Protocol.DOM.GetElementByRelationRequestRelation,
|
|
2538
|
-
tooltip: string): Promise<void> {
|
|
2539
|
-
const relatedElementId = await this.nodeInternal.domModel().getElementByRelation(this.nodeInternal.id, relation);
|
|
2540
|
-
const relatedElement = this.nodeInternal.domModel().nodeForId(relatedElementId);
|
|
2541
|
-
if (!relatedElement) {
|
|
2542
|
-
return;
|
|
2543
|
-
}
|
|
2544
|
-
const link = PanelsCommon.DOMLinkifier.Linkifier.instance().linkify(relatedElement, {
|
|
2545
|
-
preventKeyboardFocus: true,
|
|
2546
|
-
tooltip,
|
|
2547
|
-
textContent: linkContainer.textContent || undefined,
|
|
2548
|
-
isDynamicLink: true,
|
|
2549
|
-
});
|
|
2550
|
-
linkContainer.removeChildren();
|
|
2551
|
-
linkContainer.append(link);
|
|
2552
|
-
}
|
|
2553
|
-
|
|
2554
|
-
private buildPseudoElementDOM(parentElement: DocumentFragment, pseudoElementName: string): void {
|
|
2555
|
-
const pseudoElement = parentElement.createChild('span', 'webkit-html-pseudo-element');
|
|
2556
|
-
pseudoElement.textContent = pseudoElementName;
|
|
2557
|
-
UI.UIUtils.createTextChild(parentElement, '\u200B');
|
|
2558
|
-
}
|
|
2559
|
-
|
|
2560
|
-
private buildTagDOM(
|
|
2561
|
-
parentElement: DocumentFragment, tagName: string, isClosingTag: boolean, isDistinctTreeElement: boolean,
|
|
2562
|
-
updateRecord: Elements.ElementUpdateRecord.ElementUpdateRecord|null): void {
|
|
2563
|
-
const node = this.nodeInternal;
|
|
2564
|
-
const classes = ['webkit-html-tag'];
|
|
2565
|
-
if (isClosingTag && isDistinctTreeElement) {
|
|
2566
|
-
classes.push('close');
|
|
2567
|
-
}
|
|
2568
|
-
const tagElement = parentElement.createChild('span', classes.join(' '));
|
|
2569
|
-
UI.UIUtils.createTextChild(tagElement, '<');
|
|
2570
|
-
const tagNameElement =
|
|
2571
|
-
tagElement.createChild('span', isClosingTag ? 'webkit-html-close-tag-name' : 'webkit-html-tag-name');
|
|
2572
|
-
if (!isClosingTag) {
|
|
2573
|
-
tagNameElement.setAttribute('jslog', `${VisualLogging.value('tag-name').track({change: true, dblclick: true})}`);
|
|
2574
|
-
}
|
|
2575
|
-
tagNameElement.textContent = (isClosingTag ? '/' : '') + tagName;
|
|
2576
|
-
if (!isClosingTag) {
|
|
2577
|
-
if (node.hasAttributes()) {
|
|
2578
|
-
const attributes = node.attributes();
|
|
2579
|
-
for (let i = 0; i < attributes.length; ++i) {
|
|
2580
|
-
const attr = attributes[i];
|
|
2581
|
-
UI.UIUtils.createTextChild(tagElement, ' ');
|
|
2582
|
-
this.buildAttributeDOM(tagElement, attr.name, attr.value, updateRecord, false, node);
|
|
2583
|
-
}
|
|
2584
|
-
}
|
|
2585
|
-
if (updateRecord) {
|
|
2586
|
-
let hasUpdates: boolean = updateRecord.hasRemovedAttributes() || updateRecord.hasRemovedChildren();
|
|
2587
|
-
hasUpdates = hasUpdates || (!this.expanded && updateRecord.hasChangedChildren());
|
|
2588
|
-
if (hasUpdates) {
|
|
2589
|
-
UI.UIUtils.runCSSAnimationOnce(tagNameElement, 'dom-update-highlight');
|
|
2590
|
-
}
|
|
2591
|
-
}
|
|
2592
|
-
}
|
|
2593
|
-
|
|
2594
|
-
UI.UIUtils.createTextChild(tagElement, '>');
|
|
2595
|
-
UI.UIUtils.createTextChild(parentElement, '\u200B');
|
|
2596
|
-
if (tagElement.textContent) {
|
|
2597
|
-
UI.ARIAUtils.setLabel(tagElement, tagElement.textContent);
|
|
2598
|
-
}
|
|
2599
|
-
}
|
|
2600
|
-
|
|
2601
|
-
private nodeTitleInfo(updateRecord: Elements.ElementUpdateRecord.ElementUpdateRecord|null): DocumentFragment {
|
|
2602
|
-
const node = this.nodeInternal;
|
|
2603
|
-
const titleDOM = document.createDocumentFragment();
|
|
2604
|
-
const updateSearchHighlight = (): void => {
|
|
2605
|
-
this.#highlightSearchResults();
|
|
2606
|
-
};
|
|
2607
|
-
|
|
2608
|
-
switch (node.nodeType()) {
|
|
2609
|
-
case Node.ATTRIBUTE_NODE:
|
|
2610
|
-
this.buildAttributeDOM(titleDOM, (node.name as string), (node.value as string), updateRecord, true);
|
|
2611
|
-
break;
|
|
2612
|
-
|
|
2613
|
-
case Node.ELEMENT_NODE: {
|
|
2614
|
-
if (node.pseudoType()) {
|
|
2615
|
-
let pseudoElementName = node.nodeName();
|
|
2616
|
-
const pseudoIdentifier = node.pseudoIdentifier();
|
|
2617
|
-
if (pseudoIdentifier) {
|
|
2618
|
-
pseudoElementName += `(${pseudoIdentifier})`;
|
|
2619
|
-
}
|
|
2620
|
-
this.buildPseudoElementDOM(titleDOM, pseudoElementName);
|
|
2621
|
-
break;
|
|
2622
|
-
}
|
|
2623
|
-
|
|
2624
|
-
const tagName = node.nodeNameInCorrectCase();
|
|
2625
|
-
if (this.isClosingTag()) {
|
|
2626
|
-
this.buildTagDOM(titleDOM, tagName, true, true, updateRecord);
|
|
2627
|
-
break;
|
|
2628
|
-
}
|
|
2629
|
-
|
|
2630
|
-
this.buildTagDOM(titleDOM, tagName, false, false, updateRecord);
|
|
2631
|
-
|
|
2632
|
-
if (this.isExpandable()) {
|
|
2633
|
-
if (!this.expanded) {
|
|
2634
|
-
const expandButton = new ElementsComponents.ElementsTreeExpandButton.ElementsTreeExpandButton();
|
|
2635
|
-
expandButton.data = {
|
|
2636
|
-
clickHandler: () => this.expand(),
|
|
2637
|
-
};
|
|
2638
|
-
titleDOM.appendChild(expandButton);
|
|
2639
|
-
|
|
2640
|
-
// This hidden span with … is for blink layout tests.
|
|
2641
|
-
// The method dumpElementsTree(front_end/legacy_test_runner/elements_test_runner/ElementsTestRunner.js)
|
|
2642
|
-
// dumps … to identify expandable element.
|
|
2643
|
-
const hidden = document.createElement('span');
|
|
2644
|
-
hidden.textContent = '…';
|
|
2645
|
-
hidden.style.fontSize = '0';
|
|
2646
|
-
titleDOM.appendChild(hidden);
|
|
2647
|
-
|
|
2648
|
-
UI.UIUtils.createTextChild(titleDOM, '\u200B');
|
|
2649
|
-
this.buildTagDOM(titleDOM, tagName, true, false, updateRecord);
|
|
2650
|
-
}
|
|
2651
|
-
break;
|
|
2652
|
-
}
|
|
2653
|
-
|
|
2654
|
-
if (ElementsTreeElement.canShowInlineText(node)) {
|
|
2655
|
-
const textNodeElement = titleDOM.createChild('span', 'webkit-html-text-node');
|
|
2656
|
-
textNodeElement.setAttribute(
|
|
2657
|
-
'jslog', `${VisualLogging.value('text-node').track({change: true, dblclick: true})}`);
|
|
2658
|
-
const firstChild = node.firstChild;
|
|
2659
|
-
if (!firstChild) {
|
|
2660
|
-
throw new Error('ElementsTreeElement._nodeTitleInfo expects node.firstChild to be defined.');
|
|
2661
|
-
}
|
|
2662
|
-
const result = convertUnicodeCharsToHTMLEntities(firstChild.nodeValue());
|
|
2663
|
-
textNodeElement.textContent = Platform.StringUtilities.collapseWhitespace(result.text);
|
|
2664
|
-
Highlighting.highlightRangesWithStyleClass(textNodeElement, result.entityRanges, 'webkit-html-entity-value');
|
|
2665
|
-
UI.UIUtils.createTextChild(titleDOM, '\u200B');
|
|
2666
|
-
this.buildTagDOM(titleDOM, tagName, true, false, updateRecord);
|
|
2667
|
-
if (updateRecord?.hasChangedChildren()) {
|
|
2668
|
-
UI.UIUtils.runCSSAnimationOnce(textNodeElement, 'dom-update-highlight');
|
|
2669
|
-
}
|
|
2670
|
-
if (updateRecord?.isCharDataModified()) {
|
|
2671
|
-
UI.UIUtils.runCSSAnimationOnce(textNodeElement, 'dom-update-highlight');
|
|
2672
|
-
}
|
|
2673
|
-
break;
|
|
2674
|
-
}
|
|
2675
|
-
|
|
2676
|
-
if (this.treeOutline?.isXMLMimeType || !ForbiddenClosingTagElements.has(tagName)) {
|
|
2677
|
-
this.buildTagDOM(titleDOM, tagName, true, false, updateRecord);
|
|
2678
|
-
}
|
|
2679
|
-
break;
|
|
2680
|
-
}
|
|
2681
|
-
|
|
2682
|
-
case Node.TEXT_NODE:
|
|
2683
|
-
if (node.parentNode && node.parentNode.nodeName().toLowerCase() === 'script') {
|
|
2684
|
-
const newNode = titleDOM.createChild('span', 'webkit-html-text-node webkit-html-js-node');
|
|
2685
|
-
newNode.setAttribute(
|
|
2686
|
-
'jslog', `${VisualLogging.value('script-text-node').track({change: true, dblclick: true})}`);
|
|
2687
|
-
const text = node.nodeValue();
|
|
2688
|
-
newNode.textContent = text.replace(/^[\n\r]+|\s+$/g, '');
|
|
2689
|
-
void CodeHighlighter.CodeHighlighter.highlightNode(newNode, 'text/javascript').then(updateSearchHighlight);
|
|
2690
|
-
} else if (node.parentNode && node.parentNode.nodeName().toLowerCase() === 'style') {
|
|
2691
|
-
const newNode = titleDOM.createChild('span', 'webkit-html-text-node webkit-html-css-node');
|
|
2692
|
-
newNode.setAttribute(
|
|
2693
|
-
'jslog', `${VisualLogging.value('css-text-node').track({change: true, dblclick: true})}`);
|
|
2694
|
-
const text = node.nodeValue();
|
|
2695
|
-
newNode.textContent = text.replace(/^[\n\r]+|\s+$/g, '');
|
|
2696
|
-
void CodeHighlighter.CodeHighlighter.highlightNode(newNode, 'text/css').then(updateSearchHighlight);
|
|
2697
|
-
} else {
|
|
2698
|
-
UI.UIUtils.createTextChild(titleDOM, '"');
|
|
2699
|
-
const textNodeElement = titleDOM.createChild('span', 'webkit-html-text-node');
|
|
2700
|
-
textNodeElement.setAttribute(
|
|
2701
|
-
'jslog', `${VisualLogging.value('text-node').track({change: true, dblclick: true})}`);
|
|
2702
|
-
const result = convertUnicodeCharsToHTMLEntities(node.nodeValue());
|
|
2703
|
-
textNodeElement.textContent = Platform.StringUtilities.collapseWhitespace(result.text);
|
|
2704
|
-
Highlighting.highlightRangesWithStyleClass(textNodeElement, result.entityRanges, 'webkit-html-entity-value');
|
|
2705
|
-
UI.UIUtils.createTextChild(titleDOM, '"');
|
|
2706
|
-
if (updateRecord?.isCharDataModified()) {
|
|
2707
|
-
UI.UIUtils.runCSSAnimationOnce(textNodeElement, 'dom-update-highlight');
|
|
2708
|
-
}
|
|
2709
|
-
}
|
|
2710
|
-
break;
|
|
2711
|
-
|
|
2712
|
-
case Node.COMMENT_NODE: {
|
|
2713
|
-
const commentElement = titleDOM.createChild('span', 'webkit-html-comment');
|
|
2714
|
-
UI.UIUtils.createTextChild(commentElement, '<!--' + node.nodeValue() + '-->');
|
|
2715
|
-
break;
|
|
2716
|
-
}
|
|
2717
|
-
|
|
2718
|
-
case Node.DOCUMENT_TYPE_NODE: {
|
|
2719
|
-
const docTypeElement = titleDOM.createChild('span', 'webkit-html-doctype');
|
|
2720
|
-
UI.UIUtils.createTextChild(docTypeElement, '<!DOCTYPE ' + node.nodeName());
|
|
2721
|
-
if (node.publicId) {
|
|
2722
|
-
UI.UIUtils.createTextChild(docTypeElement, ' PUBLIC "' + node.publicId + '"');
|
|
2723
|
-
if (node.systemId) {
|
|
2724
|
-
UI.UIUtils.createTextChild(docTypeElement, ' "' + node.systemId + '"');
|
|
2725
|
-
}
|
|
2726
|
-
} else if (node.systemId) {
|
|
2727
|
-
UI.UIUtils.createTextChild(docTypeElement, ' SYSTEM "' + node.systemId + '"');
|
|
2728
|
-
}
|
|
2729
|
-
|
|
2730
|
-
if (node.internalSubset) {
|
|
2731
|
-
UI.UIUtils.createTextChild(docTypeElement, ' [' + node.internalSubset + ']');
|
|
2732
|
-
}
|
|
2733
|
-
|
|
2734
|
-
UI.UIUtils.createTextChild(docTypeElement, '>');
|
|
2735
|
-
break;
|
|
2736
|
-
}
|
|
2737
|
-
|
|
2738
|
-
case Node.CDATA_SECTION_NODE: {
|
|
2739
|
-
const cdataElement = titleDOM.createChild('span', 'webkit-html-text-node');
|
|
2740
|
-
UI.UIUtils.createTextChild(cdataElement, '<![CDATA[' + node.nodeValue() + ']]>');
|
|
2741
|
-
break;
|
|
2742
|
-
}
|
|
2743
|
-
|
|
2744
|
-
case Node.DOCUMENT_NODE: {
|
|
2745
|
-
const documentElement = titleDOM.createChild('span');
|
|
2746
|
-
UI.UIUtils.createTextChild(documentElement, '#document (');
|
|
2747
|
-
const text = (node as SDK.DOMModel.DOMDocument).documentURL;
|
|
2748
|
-
documentElement.appendChild(Components.Linkifier.Linkifier.linkifyURL(text, {
|
|
2749
|
-
text,
|
|
2750
|
-
preventClick: true,
|
|
2751
|
-
showColumnNumber: false,
|
|
2752
|
-
inlineFrameIndex: 0,
|
|
2753
|
-
}));
|
|
2754
|
-
UI.UIUtils.createTextChild(documentElement, ')');
|
|
2755
|
-
break;
|
|
2756
|
-
}
|
|
2757
|
-
|
|
2758
|
-
case Node.DOCUMENT_FRAGMENT_NODE: {
|
|
2759
|
-
const fragmentElement = titleDOM.createChild('span', 'webkit-html-fragment');
|
|
2760
|
-
fragmentElement.textContent = Platform.StringUtilities.collapseWhitespace(node.nodeNameInCorrectCase());
|
|
2761
|
-
break;
|
|
2762
|
-
}
|
|
2763
|
-
|
|
2764
|
-
default: {
|
|
2765
|
-
const nameWithSpaceCollapsed = Platform.StringUtilities.collapseWhitespace(node.nodeNameInCorrectCase());
|
|
2766
|
-
UI.UIUtils.createTextChild(titleDOM, nameWithSpaceCollapsed);
|
|
2767
|
-
}
|
|
2768
|
-
}
|
|
2769
|
-
|
|
2770
|
-
return titleDOM;
|
|
2771
|
-
}
|
|
2772
|
-
|
|
2773
2834
|
async remove(): Promise<void> {
|
|
2774
2835
|
if (this.treeOutline?.isToggledToHidden(this.nodeInternal)) {
|
|
2775
2836
|
// Unhide the node before removing. This avoids inconsistent state if the node is restored via undo.
|