chrome-devtools-frontend 1.0.1585538 → 1.0.1585664
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/generated/SupportedCSSProperties.js +4 -2
- package/front_end/models/ai_code_completion/AiCodeCompletion.ts +12 -0
- package/front_end/panels/ai_assistance/components/ChatView.ts +13 -0
- package/front_end/panels/application/FrameDetailsView.ts +4 -9
- package/front_end/panels/console/ConsoleViewMessage.ts +2 -2
- package/front_end/panels/elements/ElementsTreeElement.ts +148 -107
- package/front_end/panels/elements/NodeStackTraceWidget.ts +3 -11
- package/front_end/panels/elements/StylesAiCodeCompletionProvider.ts +69 -0
- package/front_end/panels/elements/elements.ts +3 -1
- package/front_end/panels/network/RequestInitiatorView.ts +2 -10
- package/front_end/panels/timeline/TimelineUIUtils.ts +2 -6
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/ui/legacy/components/utils/JSPresentationUtils.ts +18 -151
- package/front_end/ui/legacy/components/utils/Linkifier.ts +7 -3
- package/front_end/ui/legacy/components/utils/jsUtils.css +0 -9
- package/package.json +1 -1
|
@@ -4426,7 +4426,8 @@ export const generatedProperties = [
|
|
|
4426
4426
|
"inherited": true,
|
|
4427
4427
|
"keywords": [
|
|
4428
4428
|
"none",
|
|
4429
|
-
"auto"
|
|
4429
|
+
"auto",
|
|
4430
|
+
"all"
|
|
4430
4431
|
],
|
|
4431
4432
|
"name": "text-decoration-skip-ink"
|
|
4432
4433
|
},
|
|
@@ -6976,7 +6977,8 @@ export const generatedPropertyValues = {
|
|
|
6976
6977
|
"text-decoration-skip-ink": {
|
|
6977
6978
|
"values": [
|
|
6978
6979
|
"none",
|
|
6979
|
-
"auto"
|
|
6980
|
+
"auto",
|
|
6981
|
+
"all"
|
|
6980
6982
|
]
|
|
6981
6983
|
},
|
|
6982
6984
|
"text-decoration-style": {
|
|
@@ -346,6 +346,18 @@ export class AiCodeCompletion {
|
|
|
346
346
|
}
|
|
347
347
|
return Boolean(aidaAvailability.enabled && Root.Runtime.hostConfig.devToolsAiCodeCompletion?.enabled);
|
|
348
348
|
}
|
|
349
|
+
|
|
350
|
+
static isAiCodeCompletionStylesEnabled(locale: string): boolean {
|
|
351
|
+
if (!locale.startsWith('en-')) {
|
|
352
|
+
return false;
|
|
353
|
+
}
|
|
354
|
+
const aidaAvailability = Root.Runtime.hostConfig.aidaAvailability;
|
|
355
|
+
if (!aidaAvailability || aidaAvailability.blockedByGeo || aidaAvailability.blockedByAge ||
|
|
356
|
+
aidaAvailability.blockedByEnterprisePolicy) {
|
|
357
|
+
return false;
|
|
358
|
+
}
|
|
359
|
+
return Boolean(aidaAvailability.enabled && Root.Runtime.hostConfig.devToolsAiCodeCompletionStyles?.enabled);
|
|
360
|
+
}
|
|
349
361
|
}
|
|
350
362
|
|
|
351
363
|
export const enum ContextFlavor {
|
|
@@ -183,6 +183,19 @@ const DEFAULT_VIEW: View = (input, output, target) => {
|
|
|
183
183
|
`, target);
|
|
184
184
|
// clang-format on
|
|
185
185
|
};
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* ChatView is a web component for historical reasons and generally should not
|
|
189
|
+
* exist because it barely has any presenter logic and it is definitely not
|
|
190
|
+
* re-usable as a custom element. Instead, the template from ChatView should be
|
|
191
|
+
* embdedded into the AiAssistancePanel (the sole host of chat interfaces) and
|
|
192
|
+
* the scroll handling logic should be implemented in view functions using refs
|
|
193
|
+
* or re-usable custom elements. Currently, the ChatView just combines the
|
|
194
|
+
* interfaces of ChatMessage and ChatInput presenters and passes most of the
|
|
195
|
+
* properties down to those presenters as-is.
|
|
196
|
+
*
|
|
197
|
+
* @deprecated
|
|
198
|
+
*/
|
|
186
199
|
export class ChatView extends HTMLElement {
|
|
187
200
|
readonly #shadow = this.attachShadow({mode: 'open'});
|
|
188
201
|
#scrollTop?: number;
|
|
@@ -272,7 +272,6 @@ interface FrameDetailsViewInput {
|
|
|
272
272
|
frame: SDK.ResourceTreeModel.ResourceTreeFrame;
|
|
273
273
|
target: SDK.Target.Target|null;
|
|
274
274
|
creationStackTrace: StackTrace.StackTrace.StackTrace|null;
|
|
275
|
-
creationTarget: SDK.Target.Target|null;
|
|
276
275
|
adScriptAncestry: Protocol.Page.AdScriptAncestry|null;
|
|
277
276
|
linkTargetDOMNode: SDK.DOMModel.DOMNode|null;
|
|
278
277
|
permissionsPolicies: Protocol.Page.PermissionsPolicyFeatureState[]|null;
|
|
@@ -354,7 +353,7 @@ function renderDocumentSection(input: FrameDetailsViewInput): LitTemplate {
|
|
|
354
353
|
${maybeRenderUnreachableURL(input.frame?.unreachableUrl())}
|
|
355
354
|
${maybeRenderOrigin(input.frame?.securityOrigin)}
|
|
356
355
|
${renderOwnerElement(input.linkTargetDOMNode)}
|
|
357
|
-
${maybeRenderCreationStacktrace(input.creationStackTrace
|
|
356
|
+
${maybeRenderCreationStacktrace(input.creationStackTrace)}
|
|
358
357
|
${maybeRenderAdStatus(input.frame?.adFrameType(), input.frame?.adFrameStatus())}
|
|
359
358
|
${maybeRenderCreatorAdScriptAncestry(input.frame?.adFrameType(), input.target, input.adScriptAncestry)}
|
|
360
359
|
<devtools-report-divider></devtools-report-divider>`;
|
|
@@ -447,9 +446,8 @@ function renderOwnerElement(linkTargetDOMNode: SDK.DOMModel.DOMNode|null): LitTe
|
|
|
447
446
|
return nothing;
|
|
448
447
|
}
|
|
449
448
|
|
|
450
|
-
function maybeRenderCreationStacktrace(
|
|
451
|
-
|
|
452
|
-
if (stackTrace && target) {
|
|
449
|
+
function maybeRenderCreationStacktrace(stackTrace: StackTrace.StackTrace.StackTrace|null): LitTemplate {
|
|
450
|
+
if (stackTrace) {
|
|
453
451
|
// Disabled until https://crbug.com/1079231 is fixed.
|
|
454
452
|
// clang-format off
|
|
455
453
|
return html`
|
|
@@ -457,7 +455,7 @@ function maybeRenderCreationStacktrace(
|
|
|
457
455
|
i18nString(UIStrings.creationStackTrace)}</devtools-report-key>
|
|
458
456
|
<devtools-report-value jslog=${VisualLogging.section('frame-creation-stack-trace')}>
|
|
459
457
|
<devtools-widget .widgetConfig=${UI.Widget.widgetConfig(
|
|
460
|
-
Components.JSPresentationUtils.StackTracePreviewContent, {
|
|
458
|
+
Components.JSPresentationUtils.StackTracePreviewContent, {stackTrace, options: {expandable: true}})}>
|
|
461
459
|
</devtools-widget>
|
|
462
460
|
</devtools-report-value>
|
|
463
461
|
`;
|
|
@@ -844,7 +842,6 @@ export class FrameDetailsReportView extends UI.Widget.Widget {
|
|
|
844
842
|
#frame?: SDK.ResourceTreeModel.ResourceTreeFrame;
|
|
845
843
|
#target: SDK.Target.Target|null = null;
|
|
846
844
|
#creationStackTrace: StackTrace.StackTrace.StackTrace|null = null;
|
|
847
|
-
#creationTarget: SDK.Target.Target|null = null;
|
|
848
845
|
#securityIsolationInfo: Protocol.Network.SecurityIsolationStatus|null = null;
|
|
849
846
|
#linkTargetDOMNode: SDK.DOMModel.DOMNode|null = null;
|
|
850
847
|
#trials: Protocol.Page.OriginTrial[]|null = null;
|
|
@@ -869,7 +866,6 @@ export class FrameDetailsReportView extends UI.Widget.Widget {
|
|
|
869
866
|
});
|
|
870
867
|
const {creationStackTrace: rawCreationStackTrace, creationStackTraceTarget: creationTarget} =
|
|
871
868
|
frame.getCreationStackTraceData();
|
|
872
|
-
this.#creationTarget = creationTarget;
|
|
873
869
|
if (rawCreationStackTrace) {
|
|
874
870
|
void Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance()
|
|
875
871
|
.createStackTraceFromProtocolRuntime(rawCreationStackTrace, creationTarget)
|
|
@@ -924,7 +920,6 @@ export class FrameDetailsReportView extends UI.Widget.Widget {
|
|
|
924
920
|
frame,
|
|
925
921
|
target: this.#target,
|
|
926
922
|
creationStackTrace: this.#creationStackTrace,
|
|
927
|
-
creationTarget: this.#creationTarget,
|
|
928
923
|
protocolMonitorExperimentEnabled: this.#protocolMonitorExperimentEnabled,
|
|
929
924
|
permissionsPolicies: this.#permissionsPolicies,
|
|
930
925
|
adScriptAncestry: this.#adScriptAncestry,
|
|
@@ -705,8 +705,8 @@ export class ConsoleViewMessage implements ConsoleViewportElement {
|
|
|
705
705
|
const stackTraceElement = contentElement.createChild('div', 'hidden-stack-trace');
|
|
706
706
|
const targetManager = SDK.TargetManager.TargetManager.instance();
|
|
707
707
|
const stackTraceTarget = target ?? targetManager.primaryPageTarget() ?? targetManager.rootTarget();
|
|
708
|
-
const stackTracePreview = new Components.JSPresentationUtils.StackTracePreviewContent(
|
|
709
|
-
|
|
708
|
+
const stackTracePreview = new Components.JSPresentationUtils.StackTracePreviewContent();
|
|
709
|
+
stackTracePreview.options = {widthConstrained: true};
|
|
710
710
|
if (stackTraceTarget && stackTrace) {
|
|
711
711
|
const selectableChildIndex = this.selectableChildren.length;
|
|
712
712
|
void Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance()
|
|
@@ -54,7 +54,7 @@ import type * as Adorners from '../../ui/components/adorners/adorners.js';
|
|
|
54
54
|
import * as CodeHighlighter from '../../ui/components/code_highlighter/code_highlighter.js';
|
|
55
55
|
import * as Highlighting from '../../ui/components/highlighting/highlighting.js';
|
|
56
56
|
import * as TextEditor from '../../ui/components/text_editor/text_editor.js';
|
|
57
|
-
import {Icon
|
|
57
|
+
import {Icon} from '../../ui/kit/kit.js';
|
|
58
58
|
import * as Components from '../../ui/legacy/components/utils/utils.js';
|
|
59
59
|
import * as UI from '../../ui/legacy/legacy.js';
|
|
60
60
|
import * as Lit from '../../ui/lit/lit.js';
|
|
@@ -72,7 +72,7 @@ import {type ElementsTreeOutline, MappedCharToEntity} from './ElementsTreeOutlin
|
|
|
72
72
|
import {ImagePreviewPopover} from './ImagePreviewPopover.js';
|
|
73
73
|
import {getRegisteredDecorators, type MarkerDecorator, type MarkerDecoratorRegistration} from './MarkerDecorator.js';
|
|
74
74
|
|
|
75
|
-
const {html, nothing, render, Directives: {ref}} = Lit;
|
|
75
|
+
const {html, nothing, render, Directives: {ref, repeat}} = Lit;
|
|
76
76
|
const {animateOn} = UI.UIUtils;
|
|
77
77
|
|
|
78
78
|
const UIStrings = {
|
|
@@ -634,124 +634,138 @@ function renderTitle(
|
|
|
634
634
|
}
|
|
635
635
|
}
|
|
636
636
|
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
const value = attr.value || '';
|
|
642
|
-
const forceValue = isDiff;
|
|
643
|
-
const closingPunctuationRegex = /[\/;:\)\]\}]/g;
|
|
644
|
-
let highlightIndex = 0;
|
|
645
|
-
let highlightCount = 0;
|
|
646
|
-
let additionalHighlightOffset = 0;
|
|
637
|
+
const enum SrcsetTokenType {
|
|
638
|
+
LITERAL = 0,
|
|
639
|
+
LINK = 1
|
|
640
|
+
}
|
|
647
641
|
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
642
|
+
interface SrcsetToken {
|
|
643
|
+
type: SrcsetTokenType;
|
|
644
|
+
value: string;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
// FIXME: find a home for this in SDK.
|
|
648
|
+
function parseSrcset(value: string): SrcsetToken[] {
|
|
649
|
+
const result: SrcsetToken[] = [];
|
|
650
|
+
let i = 0;
|
|
651
|
+
while (value.length) {
|
|
652
|
+
if (i++ > 0) {
|
|
653
|
+
result.push({value: ' ', type: SrcsetTokenType.LITERAL});
|
|
654
|
+
}
|
|
655
|
+
value = value.trim();
|
|
656
|
+
let url = '';
|
|
657
|
+
let descriptor = '';
|
|
658
|
+
const indexOfSpace = value.search(/\s/);
|
|
659
|
+
if (indexOfSpace === -1) {
|
|
660
|
+
url = value;
|
|
661
|
+
} else if (indexOfSpace > 0 && value[indexOfSpace - 1] === ',') {
|
|
662
|
+
url = value.substring(0, indexOfSpace);
|
|
663
|
+
} else {
|
|
664
|
+
url = value.substring(0, indexOfSpace);
|
|
665
|
+
const indexOfComma = value.indexOf(',', indexOfSpace);
|
|
666
|
+
if (indexOfComma !== -1) {
|
|
667
|
+
descriptor = value.substring(indexOfSpace, indexOfComma + 1);
|
|
668
|
+
} else {
|
|
669
|
+
descriptor = value.substring(indexOfSpace);
|
|
655
670
|
}
|
|
656
|
-
|
|
657
|
-
return match + '\u200B';
|
|
658
|
-
});
|
|
671
|
+
}
|
|
659
672
|
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
673
|
+
if (url) {
|
|
674
|
+
if (url.endsWith(',')) {
|
|
675
|
+
result.push({value: url.substring(0, url.length - 1), type: SrcsetTokenType.LINK});
|
|
676
|
+
result.push({type: SrcsetTokenType.LITERAL, value: ','});
|
|
677
|
+
} else {
|
|
678
|
+
result.push({value: url, type: SrcsetTokenType.LINK});
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
if (descriptor) {
|
|
682
|
+
result.push({type: SrcsetTokenType.LITERAL, value: descriptor});
|
|
663
683
|
}
|
|
664
|
-
|
|
665
|
-
Highlighting.highlightRangesWithStyleClass(element, result.entityRanges, 'webkit-html-entity-value');
|
|
684
|
+
value = value.substring(url.length + descriptor.length);
|
|
666
685
|
}
|
|
686
|
+
return result;
|
|
687
|
+
}
|
|
667
688
|
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
689
|
+
function renderLinkifiedSrcset(tokens: SrcsetToken[], node: SDK.DOMModel.DOMNode): Lit.TemplateResult {
|
|
690
|
+
return html`${repeat(tokens, token => {
|
|
691
|
+
switch (token.type) {
|
|
692
|
+
case SrcsetTokenType.LINK:
|
|
693
|
+
return renderLinkifiedValue(token.value, node);
|
|
694
|
+
case SrcsetTokenType.LITERAL:
|
|
695
|
+
return token.value;
|
|
696
|
+
}
|
|
697
|
+
})}`;
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
const closingPunctuationRegex = /[\/;:\)\]\}]/g;
|
|
701
|
+
|
|
702
|
+
// FIXME: this should be made declarative next.
|
|
703
|
+
function setValueWithEntities(element: Element, value: string): void {
|
|
704
|
+
let highlightIndex = 0;
|
|
705
|
+
let highlightCount = 0;
|
|
706
|
+
let additionalHighlightOffset = 0;
|
|
707
|
+
const result = convertUnicodeCharsToHTMLEntities(value);
|
|
708
|
+
highlightCount = result.entityRanges.length;
|
|
709
|
+
const newValue = result.text.replace(closingPunctuationRegex, (match, replaceOffset) => {
|
|
710
|
+
while (highlightIndex < highlightCount && result.entityRanges[highlightIndex].offset < replaceOffset) {
|
|
711
|
+
result.entityRanges[highlightIndex].offset += additionalHighlightOffset;
|
|
712
|
+
++highlightIndex;
|
|
713
|
+
}
|
|
714
|
+
additionalHighlightOffset += 1;
|
|
715
|
+
return match + '\u200B';
|
|
672
716
|
});
|
|
673
717
|
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
value = value.replace(closingPunctuationRegex, '$&\u200B');
|
|
682
|
-
if (value.startsWith('data:')) {
|
|
683
|
-
value = Platform.StringUtilities.trimMiddle(value, 60);
|
|
684
|
-
}
|
|
685
|
-
const link = node && node.nodeName().toLowerCase() === 'a' ?
|
|
686
|
-
Link.create(rewrittenHref, value, undefined, 'image-url') :
|
|
687
|
-
Components.Linkifier.Linkifier.linkifyURL(rewrittenHref, {
|
|
688
|
-
text: value,
|
|
689
|
-
preventClick: true,
|
|
690
|
-
showColumnNumber: false,
|
|
691
|
-
inlineFrameIndex: 0,
|
|
692
|
-
});
|
|
693
|
-
return ImagePreviewPopover.setImageUrl(link, rewrittenHref);
|
|
694
|
-
}
|
|
695
|
-
|
|
696
|
-
function linkifySrcset(value: string): DocumentFragment {
|
|
697
|
-
// Splitting normally on commas or spaces will break on valid srcsets "foo 1x,bar 2x" and "data:,foo 1x".
|
|
698
|
-
const fragment = document.createDocumentFragment();
|
|
699
|
-
let i = 0;
|
|
700
|
-
while (value.length) {
|
|
701
|
-
if (i++ > 0) {
|
|
702
|
-
UI.UIUtils.createTextChild(fragment, ' ');
|
|
703
|
-
}
|
|
704
|
-
value = value.trim();
|
|
705
|
-
let url = '';
|
|
706
|
-
let descriptor = '';
|
|
707
|
-
const indexOfSpace = value.search(/\s/);
|
|
708
|
-
if (indexOfSpace === -1) {
|
|
709
|
-
url = value;
|
|
710
|
-
} else if (indexOfSpace > 0 && value[indexOfSpace - 1] === ',') {
|
|
711
|
-
url = value.substring(0, indexOfSpace);
|
|
712
|
-
} else {
|
|
713
|
-
url = value.substring(0, indexOfSpace);
|
|
714
|
-
const indexOfComma = value.indexOf(',', indexOfSpace);
|
|
715
|
-
if (indexOfComma !== -1) {
|
|
716
|
-
descriptor = value.substring(indexOfSpace, indexOfComma + 1);
|
|
717
|
-
} else {
|
|
718
|
-
descriptor = value.substring(indexOfSpace);
|
|
719
|
-
}
|
|
720
|
-
}
|
|
718
|
+
while (highlightIndex < highlightCount) {
|
|
719
|
+
result.entityRanges[highlightIndex].offset += additionalHighlightOffset;
|
|
720
|
+
++highlightIndex;
|
|
721
|
+
}
|
|
722
|
+
element.setTextContentTruncatedIfNeeded(newValue);
|
|
723
|
+
Highlighting.highlightRangesWithStyleClass(element, result.entityRanges, 'webkit-html-entity-value');
|
|
724
|
+
}
|
|
721
725
|
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
}
|
|
726
|
+
function renderLinkifiedValue(value: string, node: SDK.DOMModel.DOMNode): Lit.TemplateResult {
|
|
727
|
+
const rewrittenHref = node ? node.resolveURL(value) : null;
|
|
728
|
+
if (rewrittenHref === null) {
|
|
729
|
+
return html`<span ${ref(el => {
|
|
730
|
+
if (el) {
|
|
731
|
+
setValueWithEntities(el, value);
|
|
729
732
|
}
|
|
730
|
-
|
|
731
|
-
|
|
733
|
+
})}}></span>`;
|
|
734
|
+
}
|
|
735
|
+
value = value.replace(closingPunctuationRegex, '$&\u200B');
|
|
736
|
+
if (value.startsWith('data:')) {
|
|
737
|
+
value = Platform.StringUtilities.trimMiddle(value, 60);
|
|
738
|
+
}
|
|
739
|
+
const isAnchor = node && node.nodeName().toLowerCase() === 'a';
|
|
740
|
+
if (isAnchor) {
|
|
741
|
+
return html`<devtools-link class="devtools-link image-url" href=${rewrittenHref} ${ref(el => {
|
|
742
|
+
if (el) {
|
|
743
|
+
ImagePreviewPopover.setImageUrl(el, rewrittenHref);
|
|
732
744
|
}
|
|
733
|
-
|
|
734
|
-
}
|
|
735
|
-
return fragment;
|
|
745
|
+
})}>${Platform.StringUtilities.trimMiddle(value, 150)}</devtools-link>`;
|
|
736
746
|
}
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
valueElement.removeChildren();
|
|
745
|
-
if (nodeName && (name === 'src' || name === 'href') && value) {
|
|
746
|
-
valueElement.appendChild(linkifyValue(value));
|
|
747
|
-
} else if ((nodeName === 'img' || nodeName === 'source') && name === 'srcset') {
|
|
748
|
-
valueElement.appendChild(linkifySrcset(value));
|
|
749
|
-
} else if (nodeName === 'image' && (name === 'xlink:href' || name === 'href')) {
|
|
750
|
-
valueElement.appendChild(linkifySrcset(value));
|
|
751
|
-
} else {
|
|
752
|
-
setValueWithEntities(valueElement, value);
|
|
747
|
+
return Components.Linkifier.Linkifier.renderLinkifiedUrl(rewrittenHref, {
|
|
748
|
+
text: value,
|
|
749
|
+
preventClick: true,
|
|
750
|
+
showColumnNumber: false,
|
|
751
|
+
inlineFrameIndex: 0,
|
|
752
|
+
onRef: link => {
|
|
753
|
+
ImagePreviewPopover.setImageUrl(link, rewrittenHref);
|
|
753
754
|
}
|
|
754
755
|
});
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
function renderAttribute(
|
|
759
|
+
attr: {name: string, value?: string}, updateRecord: Elements.ElementUpdateRecord.ElementUpdateRecord|null,
|
|
760
|
+
isDiff: boolean, node: SDK.DOMModel.DOMNode): Lit.LitTemplate {
|
|
761
|
+
const name = attr.name;
|
|
762
|
+
const value = attr.value || '';
|
|
763
|
+
const forceValue = isDiff;
|
|
764
|
+
const hasText = (forceValue || value.length > 0);
|
|
765
|
+
const jslog = VisualLogging.value(name === 'style' ? 'style-attribute' : 'attribute').track({
|
|
766
|
+
change: true,
|
|
767
|
+
dblclick: true,
|
|
768
|
+
});
|
|
755
769
|
|
|
756
770
|
const relationRef =
|
|
757
771
|
(relation: Protocol.DOM.GetElementByRelationRequestRelation, tooltip: string): ReturnType<typeof ref> =>
|
|
@@ -804,14 +818,41 @@ function renderAttribute(
|
|
|
804
818
|
}
|
|
805
819
|
}
|
|
806
820
|
|
|
821
|
+
const nodeName = node ? node.nodeName().toLowerCase() : '';
|
|
822
|
+
const enum ValueType {
|
|
823
|
+
UNKNOWN = 0,
|
|
824
|
+
SRC = 1,
|
|
825
|
+
SRCSET = 2,
|
|
826
|
+
}
|
|
827
|
+
let valueType = ValueType.UNKNOWN;
|
|
828
|
+
if (nodeName && (name === 'src' || name === 'href') && value) {
|
|
829
|
+
valueType = ValueType.SRC;
|
|
830
|
+
} else if ((nodeName === 'img' || nodeName === 'source') && name === 'srcset') {
|
|
831
|
+
valueType = ValueType.SRCSET;
|
|
832
|
+
} else if (nodeName === 'image' && (name === 'xlink:href' || name === 'href')) {
|
|
833
|
+
valueType = ValueType.SRCSET;
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
const withEntitiesRef = valueType === ValueType.UNKNOWN ? ref(el => {
|
|
837
|
+
if (el) {
|
|
838
|
+
setValueWithEntities(el, value);
|
|
839
|
+
}
|
|
840
|
+
}) :
|
|
841
|
+
nothing;
|
|
842
|
+
|
|
843
|
+
// clang-format off
|
|
807
844
|
return html`<span class="webkit-html-attribute" jslog=${jslog}><span class="webkit-html-attribute-name"
|
|
808
845
|
${animateOn(Boolean(updateRecord?.isAttributeModified(name) && !hasText), DOM_UPDATE_ANIMATION_CLASS_NAME)} ${
|
|
809
846
|
relationRefDirective}>${name}</span>${
|
|
810
847
|
hasText ? html`=\u200B"<span class="webkit-html-attribute-value" ${
|
|
811
848
|
animateOn(
|
|
812
849
|
Boolean(updateRecord?.isAttributeModified(name) && hasText),
|
|
813
|
-
DOM_UPDATE_ANIMATION_CLASS_NAME)} ${
|
|
850
|
+
DOM_UPDATE_ANIMATION_CLASS_NAME)} ${valueRelationRefDirective} ${withEntitiesRef}>
|
|
851
|
+
${valueType === ValueType.SRC ? renderLinkifiedValue(value, node) : nothing}
|
|
852
|
+
${valueType === ValueType.SRCSET ? renderLinkifiedSrcset(parseSrcset(value), node) : nothing}
|
|
853
|
+
</span>"` :
|
|
814
854
|
nothing}</span>`;
|
|
855
|
+
// clang-format on
|
|
815
856
|
}
|
|
816
857
|
|
|
817
858
|
function renderTag(
|
|
@@ -22,22 +22,20 @@ const str_ = i18n.i18n.registerUIStrings('panels/elements/NodeStackTraceWidget.t
|
|
|
22
22
|
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
|
23
23
|
|
|
24
24
|
interface ViewInput {
|
|
25
|
-
target?: SDK.Target.Target;
|
|
26
|
-
linkifier: Components.Linkifier.Linkifier;
|
|
27
25
|
stackTrace?: StackTrace.StackTrace.StackTrace;
|
|
28
26
|
}
|
|
29
27
|
|
|
30
28
|
type View = (input: ViewInput, output: object, target: HTMLElement) => void;
|
|
31
29
|
|
|
32
30
|
export const DEFAULT_VIEW: View = (input, _output, target) => {
|
|
33
|
-
const {
|
|
31
|
+
const {stackTrace} = input;
|
|
34
32
|
// clang-format off
|
|
35
33
|
render(html`
|
|
36
34
|
<style>${nodeStackTraceWidgetStyles}</style>
|
|
37
35
|
${target && stackTrace ?
|
|
38
36
|
html`<devtools-widget
|
|
39
37
|
class="stack-trace"
|
|
40
|
-
.widgetConfig=${UI.Widget.widgetConfig(Components.JSPresentationUtils.StackTracePreviewContent, {
|
|
38
|
+
.widgetConfig=${UI.Widget.widgetConfig(Components.JSPresentationUtils.StackTracePreviewContent, {stackTrace})}>
|
|
41
39
|
</devtools-widget>` :
|
|
42
40
|
html`<div class="gray-info-message">${i18nString(UIStrings.noStackTraceAvailable)}</div>`}`,
|
|
43
41
|
target);
|
|
@@ -45,7 +43,6 @@ export const DEFAULT_VIEW: View = (input, _output, target) => {
|
|
|
45
43
|
};
|
|
46
44
|
|
|
47
45
|
export class NodeStackTraceWidget extends UI.Widget.VBox {
|
|
48
|
-
readonly #linkifier = new Components.Linkifier.Linkifier(UI.UIUtils.MaxLengthForDisplayedURLsInConsole);
|
|
49
46
|
readonly #view: View;
|
|
50
47
|
|
|
51
48
|
constructor(view = DEFAULT_VIEW) {
|
|
@@ -73,11 +70,6 @@ export class NodeStackTraceWidget extends UI.Widget.VBox {
|
|
|
73
70
|
await Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance().createStackTraceFromProtocolRuntime(
|
|
74
71
|
runtimeStackTrace, target) :
|
|
75
72
|
undefined;
|
|
76
|
-
|
|
77
|
-
target,
|
|
78
|
-
linkifier: this.#linkifier,
|
|
79
|
-
stackTrace,
|
|
80
|
-
};
|
|
81
|
-
this.#view(input, {}, this.contentElement);
|
|
73
|
+
this.#view({stackTrace}, {}, this.contentElement);
|
|
82
74
|
}
|
|
83
75
|
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// Copyright 2026 The Chromium Authors
|
|
2
|
+
// Use of this source code is governed by a BSD-style license that can be
|
|
3
|
+
// found in the LICENSE file.
|
|
4
|
+
|
|
5
|
+
import * as Common from '../../core/common/common.js';
|
|
6
|
+
import * as Host from '../../core/host/host.js';
|
|
7
|
+
import * as i18n from '../../core/i18n/i18n.js';
|
|
8
|
+
import * as AiCodeCompletion from '../../models/ai_code_completion/ai_code_completion.js';
|
|
9
|
+
import type * as TextEditor from '../../ui/components/text_editor/text_editor.js';
|
|
10
|
+
|
|
11
|
+
export class StylesAiCodeCompletionProvider {
|
|
12
|
+
#aidaClient: Host.AidaClient.AidaClient = new Host.AidaClient.AidaClient();
|
|
13
|
+
#aiCodeCompletionSetting = Common.Settings.Settings.instance().createSetting('ai-code-completion-enabled', false);
|
|
14
|
+
#aiCodeCompletion?: AiCodeCompletion.AiCodeCompletion.AiCodeCompletion;
|
|
15
|
+
#aiCodeCompletionConfig?: TextEditor.AiCodeCompletionProvider.AiCodeCompletionConfig;
|
|
16
|
+
|
|
17
|
+
#boundOnUpdateAiCodeCompletionState = this.#updateAiCodeCompletionState.bind(this);
|
|
18
|
+
|
|
19
|
+
private constructor(aiCodeCompletionConfig: TextEditor.AiCodeCompletionProvider.AiCodeCompletionConfig) {
|
|
20
|
+
const devtoolsLocale = i18n.DevToolsLocale.DevToolsLocale.instance();
|
|
21
|
+
if (!AiCodeCompletion.AiCodeCompletion.AiCodeCompletion.isAiCodeCompletionStylesEnabled(devtoolsLocale.locale)) {
|
|
22
|
+
throw new Error('AI code completion feature in Styles is not enabled.');
|
|
23
|
+
}
|
|
24
|
+
this.#aiCodeCompletionConfig = aiCodeCompletionConfig;
|
|
25
|
+
Host.AidaClient.HostConfigTracker.instance().addEventListener(
|
|
26
|
+
Host.AidaClient.Events.AIDA_AVAILABILITY_CHANGED, this.#boundOnUpdateAiCodeCompletionState);
|
|
27
|
+
this.#aiCodeCompletionSetting.addChangeListener(this.#boundOnUpdateAiCodeCompletionState);
|
|
28
|
+
void this.#updateAiCodeCompletionState();
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
static createInstance(aiCodeCompletionConfig: TextEditor.AiCodeCompletionProvider.AiCodeCompletionConfig):
|
|
32
|
+
StylesAiCodeCompletionProvider {
|
|
33
|
+
return new StylesAiCodeCompletionProvider(aiCodeCompletionConfig);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
#setupAiCodeCompletion(): void {
|
|
37
|
+
if (!this.#aiCodeCompletionConfig) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (this.#aiCodeCompletion) {
|
|
41
|
+
// early return as this means that code completion was previously setup
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
this.#aiCodeCompletion = new AiCodeCompletion.AiCodeCompletion.AiCodeCompletion(
|
|
45
|
+
{aidaClient: this.#aidaClient}, this.#aiCodeCompletionConfig.panel, undefined,
|
|
46
|
+
this.#aiCodeCompletionConfig.completionContext.stopSequences);
|
|
47
|
+
this.#aiCodeCompletionConfig.onFeatureEnabled();
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
#cleanupAiCodeCompletion(): void {
|
|
51
|
+
if (!this.#aiCodeCompletion) {
|
|
52
|
+
// early return as this means there is no code completion to clean up
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
this.#aiCodeCompletion = undefined;
|
|
56
|
+
this.#aiCodeCompletionConfig?.onFeatureDisabled();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async #updateAiCodeCompletionState(): Promise<void> {
|
|
60
|
+
const aidaAvailability = await Host.AidaClient.AidaClient.checkAccessPreconditions();
|
|
61
|
+
const isAvailable = aidaAvailability === Host.AidaClient.AidaAccessPreconditions.AVAILABLE;
|
|
62
|
+
const isEnabled = this.#aiCodeCompletionSetting.get();
|
|
63
|
+
if (isAvailable && isEnabled) {
|
|
64
|
+
this.#setupAiCodeCompletion();
|
|
65
|
+
} else {
|
|
66
|
+
this.#cleanupAiCodeCompletion();
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
import './InspectElementModeController.js';
|
|
6
6
|
import './ColorSwatchPopoverIcon.js';
|
|
7
|
-
|
|
8
7
|
import './DOMPath.js';
|
|
9
8
|
import './ElementsSidebarPane.js';
|
|
10
9
|
import './ElementsTreeElement.js';
|
|
@@ -20,6 +19,7 @@ import './NodeStackTraceWidget.js';
|
|
|
20
19
|
import './StylePropertiesSection.js';
|
|
21
20
|
import './StylePropertyHighlighter.js';
|
|
22
21
|
import './StylesSidebarPane.js';
|
|
22
|
+
import './StylesAiCodeCompletionProvider.js';
|
|
23
23
|
import './StylePropertyTreeElement.js';
|
|
24
24
|
import './ComputedStyleWidget.js';
|
|
25
25
|
import './CSSRuleValidator.js';
|
|
@@ -59,6 +59,7 @@ import * as StylePropertiesSection from './StylePropertiesSection.js';
|
|
|
59
59
|
import * as StylePropertyHighlighter from './StylePropertyHighlighter.js';
|
|
60
60
|
import * as StylePropertyTreeElement from './StylePropertyTreeElement.js';
|
|
61
61
|
import * as StylePropertyUtils from './StylePropertyUtils.js';
|
|
62
|
+
import * as StylesAiCodeCompletionProvider from './StylesAiCodeCompletionProvider.js';
|
|
62
63
|
import * as StylesSidebarPane from './StylesSidebarPane.js';
|
|
63
64
|
import * as TopLayerContainer from './TopLayerContainer.js';
|
|
64
65
|
import * as WebCustomData from './WebCustomData.js';
|
|
@@ -94,6 +95,7 @@ export {
|
|
|
94
95
|
StylePropertyHighlighter,
|
|
95
96
|
StylePropertyTreeElement,
|
|
96
97
|
StylePropertyUtils,
|
|
98
|
+
StylesAiCodeCompletionProvider,
|
|
97
99
|
StylesSidebarPane,
|
|
98
100
|
TopLayerContainer,
|
|
99
101
|
WebCustomData,
|
|
@@ -39,8 +39,6 @@ export interface ViewInput {
|
|
|
39
39
|
initiatorGraph: Logs.NetworkLog.InitiatorGraph;
|
|
40
40
|
stackTrace: StackTrace.StackTrace.StackTrace|null;
|
|
41
41
|
request: SDK.NetworkRequest.NetworkRequest;
|
|
42
|
-
linkifier: Components.Linkifier.Linkifier;
|
|
43
|
-
target?: SDK.Target.Target;
|
|
44
42
|
}
|
|
45
43
|
|
|
46
44
|
export const DEFAULT_VIEW = (input: ViewInput, _output: undefined, target: HTMLElement): void => {
|
|
@@ -68,8 +66,6 @@ export const DEFAULT_VIEW = (input: ViewInput, _output: undefined, target: HTMLE
|
|
|
68
66
|
<ul role="group">
|
|
69
67
|
<li role="treeitem">
|
|
70
68
|
<devtools-widget .widgetConfig=${widgetConfig(Components.JSPresentationUtils.StackTracePreviewContent, {
|
|
71
|
-
target: input.target,
|
|
72
|
-
linkifier: input.linkifier,
|
|
73
69
|
options: {tabStops: true},
|
|
74
70
|
stackTrace: input.stackTrace,
|
|
75
71
|
})}></devtools-widget>
|
|
@@ -165,7 +161,6 @@ export const DEFAULT_VIEW = (input: ViewInput, _output: undefined, target: HTMLE
|
|
|
165
161
|
type View = typeof DEFAULT_VIEW;
|
|
166
162
|
|
|
167
163
|
export class RequestInitiatorView extends UI.Widget.VBox {
|
|
168
|
-
private readonly linkifier: Components.Linkifier.Linkifier;
|
|
169
164
|
private readonly request: SDK.NetworkRequest.NetworkRequest;
|
|
170
165
|
#view: View;
|
|
171
166
|
|
|
@@ -173,7 +168,6 @@ export class RequestInitiatorView extends UI.Widget.VBox {
|
|
|
173
168
|
super({jslog: `${VisualLogging.pane('initiator').track({resize: true})}`});
|
|
174
169
|
|
|
175
170
|
this.element.classList.add('request-initiator-view');
|
|
176
|
-
this.linkifier = new Components.Linkifier.Linkifier();
|
|
177
171
|
this.request = request;
|
|
178
172
|
this.#view = view;
|
|
179
173
|
}
|
|
@@ -192,8 +186,8 @@ export class RequestInitiatorView extends UI.Widget.VBox {
|
|
|
192
186
|
const networkManager = SDK.NetworkManager.NetworkManager.forRequest(request);
|
|
193
187
|
const target = networkManager?.target() ?? targetManager.primaryPageTarget() ?? targetManager.rootTarget();
|
|
194
188
|
let stackTrace: StackTrace.StackTrace.StackTrace|null = null;
|
|
195
|
-
const preview = new Components.JSPresentationUtils.StackTracePreviewContent(
|
|
196
|
-
|
|
189
|
+
const preview = new Components.JSPresentationUtils.StackTracePreviewContent();
|
|
190
|
+
preview.options = {tabStops: focusableLink};
|
|
197
191
|
if (target) {
|
|
198
192
|
stackTrace = await Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance()
|
|
199
193
|
.createStackTraceFromProtocolRuntime(initiator.stack, target);
|
|
@@ -219,8 +213,6 @@ export class RequestInitiatorView extends UI.Widget.VBox {
|
|
|
219
213
|
initiatorGraph,
|
|
220
214
|
stackTrace,
|
|
221
215
|
request: this.request,
|
|
222
|
-
linkifier: this.linkifier,
|
|
223
|
-
target: target || undefined,
|
|
224
216
|
};
|
|
225
217
|
|
|
226
218
|
this.#view(viewInput, undefined, this.contentElement);
|
|
@@ -2498,10 +2498,6 @@ export class TimelineDetailsContentHelper {
|
|
|
2498
2498
|
* contains any entries, and discards it if it's empty.
|
|
2499
2499
|
*/
|
|
2500
2500
|
async createChildStackTraceElement(runtimeStackTrace: Protocol.Runtime.StackTrace): Promise<HTMLElement|null> {
|
|
2501
|
-
if (!this.#linkifier) {
|
|
2502
|
-
return null;
|
|
2503
|
-
}
|
|
2504
|
-
|
|
2505
2501
|
// Fallback to the main page/root target. Maybe the main page has a source map we need.
|
|
2506
2502
|
// Worst case the stack is identity mapped.
|
|
2507
2503
|
const targetManager = SDK.TargetManager.TargetManager.instance();
|
|
@@ -2513,8 +2509,8 @@ export class TimelineDetailsContentHelper {
|
|
|
2513
2509
|
const stackTrace =
|
|
2514
2510
|
await Bindings.DebuggerWorkspaceBinding.DebuggerWorkspaceBinding.instance().createStackTraceFromProtocolRuntime(
|
|
2515
2511
|
runtimeStackTrace, target);
|
|
2516
|
-
const callFrameContents = new LegacyComponents.JSPresentationUtils.StackTracePreviewContent(
|
|
2517
|
-
|
|
2512
|
+
const callFrameContents = new LegacyComponents.JSPresentationUtils.StackTracePreviewContent();
|
|
2513
|
+
callFrameContents.options = {tabStops: true, showColumnNumber: true};
|
|
2518
2514
|
callFrameContents.stackTrace = stackTrace;
|
|
2519
2515
|
|
|
2520
2516
|
await callFrameContents.updateComplete;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Name: Dependencies sourced from the upstream `chromium` repository
|
|
2
2
|
URL: https://chromium.googlesource.com/chromium/src
|
|
3
3
|
Version: N/A
|
|
4
|
-
Revision:
|
|
4
|
+
Revision: ccc41bdd9ec5ebd001ba6ac080db5aa20d8b96a9
|
|
5
5
|
Update Mechanism: Manual (https://crbug.com/428069060)
|
|
6
6
|
License: BSD-3-Clause
|
|
7
7
|
License File: LICENSE
|
|
@@ -34,17 +34,15 @@
|
|
|
34
34
|
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
35
35
|
*/
|
|
36
36
|
|
|
37
|
-
import * as Common from '../../../../core/common/common.js';
|
|
38
37
|
import * as i18n from '../../../../core/i18n/i18n.js';
|
|
39
38
|
import * as SDK from '../../../../core/sdk/sdk.js';
|
|
40
|
-
import type * as Protocol from '../../../../generated/protocol.js';
|
|
41
39
|
import * as StackTrace from '../../../../models/stack_trace/stack_trace.js';
|
|
42
40
|
import * as Workspace from '../../../../models/workspace/workspace.js';
|
|
43
41
|
import * as VisualLogging from '../../../visual_logging/visual_logging.js';
|
|
44
42
|
import * as UI from '../../legacy.js';
|
|
45
43
|
|
|
46
44
|
import jsUtilsStyles from './jsUtils.css.js';
|
|
47
|
-
import {
|
|
45
|
+
import {Linkifier} from './Linkifier.js';
|
|
48
46
|
|
|
49
47
|
const UIStrings = {
|
|
50
48
|
/**
|
|
@@ -63,10 +61,6 @@ const UIStrings = {
|
|
|
63
61
|
* @description A link to rehide frames that are by default hidden.
|
|
64
62
|
*/
|
|
65
63
|
showLess: 'Show less',
|
|
66
|
-
/**
|
|
67
|
-
* @description Text indicating that source url of a link is currently unknown
|
|
68
|
-
*/
|
|
69
|
-
unknownSource: 'unknown',
|
|
70
64
|
} as const;
|
|
71
65
|
const str_ = i18n.i18n.registerUIStrings('ui/legacy/components/utils/JSPresentationUtils.ts', UIStrings);
|
|
72
66
|
const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
|
@@ -95,74 +89,8 @@ function populateContextMenu(link: Element, event: Event): void {
|
|
|
95
89
|
void contextMenu.show();
|
|
96
90
|
}
|
|
97
91
|
|
|
98
|
-
// TODO(crbug.com/456517732): remove when all usages of runtimeStackTrace are migrated.
|
|
99
|
-
function buildStackTraceRowsForLegacyRuntimeStackTrace(
|
|
100
|
-
stackTrace: Protocol.Runtime.StackTrace,
|
|
101
|
-
target: SDK.Target.Target|null,
|
|
102
|
-
linkifier: Linkifier,
|
|
103
|
-
tabStops: boolean|undefined,
|
|
104
|
-
updateCallback?: (arg0: Array<StackTraceRegularRow|StackTraceAsyncRow>) => void,
|
|
105
|
-
showColumnNumber?: boolean,
|
|
106
|
-
): Array<StackTraceRegularRow|StackTraceAsyncRow> {
|
|
107
|
-
const stackTraceRows: Array<StackTraceRegularRow|StackTraceAsyncRow> = [];
|
|
108
|
-
|
|
109
|
-
if (updateCallback) {
|
|
110
|
-
const throttler = new Common.Throttler.Throttler(100);
|
|
111
|
-
linkifier.addEventListener(LinkifierEvents.LIVE_LOCATION_UPDATED, () => {
|
|
112
|
-
void throttler.schedule(async () => updateCallback(stackTraceRows));
|
|
113
|
-
});
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
function buildStackTraceRowsHelper(
|
|
117
|
-
stackTrace: Protocol.Runtime.StackTrace,
|
|
118
|
-
previousCallFrames: Protocol.Runtime.CallFrame[]|undefined = undefined): void {
|
|
119
|
-
let asyncRow: StackTraceAsyncRow|null = null;
|
|
120
|
-
if (previousCallFrames) {
|
|
121
|
-
asyncRow = {
|
|
122
|
-
asyncDescription: UI.UIUtils.asyncStackTraceLabel(stackTrace.description, previousCallFrames),
|
|
123
|
-
};
|
|
124
|
-
stackTraceRows.push(asyncRow);
|
|
125
|
-
}
|
|
126
|
-
let previousStackFrameWasBreakpointCondition = false;
|
|
127
|
-
for (const stackFrame of stackTrace.callFrames) {
|
|
128
|
-
const functionName = UI.UIUtils.beautifyFunctionName(stackFrame.functionName);
|
|
129
|
-
const link = linkifier.maybeLinkifyConsoleCallFrame(target, stackFrame, {
|
|
130
|
-
showColumnNumber,
|
|
131
|
-
tabStop: Boolean(tabStops),
|
|
132
|
-
inlineFrameIndex: 0,
|
|
133
|
-
revealBreakpoint: previousStackFrameWasBreakpointCondition,
|
|
134
|
-
});
|
|
135
|
-
if (link) {
|
|
136
|
-
link.setAttribute('jslog', `${VisualLogging.link('stack-trace').track({click: true})}`);
|
|
137
|
-
link.addEventListener('contextmenu', populateContextMenu.bind(null, link));
|
|
138
|
-
|
|
139
|
-
if (!link.textContent) {
|
|
140
|
-
link.textContent = i18nString(UIStrings.unknownSource);
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
stackTraceRows.push({functionName, link});
|
|
144
|
-
previousStackFrameWasBreakpointCondition = [
|
|
145
|
-
SDK.DebuggerModel.COND_BREAKPOINT_SOURCE_URL,
|
|
146
|
-
SDK.DebuggerModel.LOGPOINT_SOURCE_URL,
|
|
147
|
-
].includes(stackFrame.url);
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
buildStackTraceRowsHelper(stackTrace);
|
|
152
|
-
let previousCallFrames = stackTrace.callFrames;
|
|
153
|
-
for (let asyncStackTrace = stackTrace.parent; asyncStackTrace; asyncStackTrace = asyncStackTrace.parent) {
|
|
154
|
-
if (asyncStackTrace.callFrames.length) {
|
|
155
|
-
buildStackTraceRowsHelper(asyncStackTrace, previousCallFrames);
|
|
156
|
-
}
|
|
157
|
-
previousCallFrames = asyncStackTrace.callFrames;
|
|
158
|
-
}
|
|
159
|
-
return stackTraceRows;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
92
|
function buildStackTraceRows(
|
|
163
93
|
stackTrace: StackTrace.StackTrace.StackTrace,
|
|
164
|
-
target: SDK.Target.Target|null,
|
|
165
|
-
linkifier: Linkifier,
|
|
166
94
|
tabStops: boolean|undefined,
|
|
167
95
|
showColumnNumber?: boolean,
|
|
168
96
|
): Array<StackTraceRegularRow|StackTraceAsyncRow> {
|
|
@@ -214,9 +142,8 @@ function buildStackTraceRows(
|
|
|
214
142
|
|
|
215
143
|
function renderStackTraceTable(
|
|
216
144
|
container: Element, parent: Element, expandable: boolean,
|
|
217
|
-
stackTraceRows: Array<StackTraceRegularRow|StackTraceAsyncRow>):
|
|
145
|
+
stackTraceRows: Array<StackTraceRegularRow|StackTraceAsyncRow>): void {
|
|
218
146
|
container.removeChildren();
|
|
219
|
-
const links: HTMLElement[] = [];
|
|
220
147
|
|
|
221
148
|
// The tableSection groups one or more synchronous call frames together.
|
|
222
149
|
// Wherever there is an asynchronous call, a new section is created.
|
|
@@ -250,10 +177,7 @@ function renderStackTraceTable(
|
|
|
250
177
|
} else {
|
|
251
178
|
row.createChild('td', 'function-name').textContent = item.functionName;
|
|
252
179
|
row.createChild('td').textContent = ' @ ';
|
|
253
|
-
|
|
254
|
-
row.createChild('td', 'link').appendChild(item.link);
|
|
255
|
-
links.push(item.link);
|
|
256
|
-
}
|
|
180
|
+
row.createChild('td', 'link').appendChild(item.link);
|
|
257
181
|
}
|
|
258
182
|
}
|
|
259
183
|
|
|
@@ -286,13 +210,9 @@ function renderStackTraceTable(
|
|
|
286
210
|
// If we are in a popup, this will trigger a re-layout
|
|
287
211
|
UI.GlassPane.GlassPane.containerMoved(container);
|
|
288
212
|
}, false);
|
|
289
|
-
|
|
290
|
-
return links;
|
|
291
213
|
}
|
|
292
214
|
|
|
293
215
|
export interface Options {
|
|
294
|
-
// TODO(crbug.com/456517732): remove when all usages of runtimeStackTrace are migrated.
|
|
295
|
-
runtimeStackTrace?: Protocol.Runtime.StackTrace;
|
|
296
216
|
tabStops?: boolean;
|
|
297
217
|
// Whether the width of stack trace preview
|
|
298
218
|
// is constrained to its container or whether
|
|
@@ -304,7 +224,7 @@ export interface Options {
|
|
|
304
224
|
|
|
305
225
|
interface StackTraceRegularRow {
|
|
306
226
|
functionName: string;
|
|
307
|
-
link: HTMLElement
|
|
227
|
+
link: HTMLElement;
|
|
308
228
|
}
|
|
309
229
|
|
|
310
230
|
interface StackTraceAsyncRow {
|
|
@@ -313,92 +233,43 @@ interface StackTraceAsyncRow {
|
|
|
313
233
|
|
|
314
234
|
export class StackTracePreviewContent extends UI.Widget.Widget {
|
|
315
235
|
#stackTrace?: StackTrace.StackTrace.StackTrace;
|
|
316
|
-
#
|
|
317
|
-
#linkifier?: Linkifier;
|
|
318
|
-
#ownedLinkifier?: Linkifier;
|
|
319
|
-
#options: Options;
|
|
320
|
-
#links: HTMLElement[] = [];
|
|
236
|
+
#options: Options = {};
|
|
321
237
|
|
|
322
238
|
readonly #table: HTMLElement;
|
|
323
|
-
/**
|
|
324
|
-
* Updated when we update to define if we have any rows for the StackTrace;
|
|
325
|
-
* allowing the caller to know if this element is empty or not.
|
|
326
|
-
*/
|
|
327
|
-
#hasRows = false;
|
|
328
239
|
|
|
329
|
-
constructor(element?: HTMLElement
|
|
330
|
-
super(element, {useShadowDom: true});
|
|
331
|
-
|
|
332
|
-
this.#target = target;
|
|
333
|
-
this.#linkifier = linkifier;
|
|
334
|
-
if (!this.#linkifier) {
|
|
335
|
-
this.#ownedLinkifier = new Linkifier();
|
|
336
|
-
this.#linkifier = this.#ownedLinkifier;
|
|
337
|
-
}
|
|
338
|
-
this.#options = options || {
|
|
339
|
-
widthConstrained: false,
|
|
340
|
-
};
|
|
341
|
-
|
|
342
|
-
this.element.classList.add('monospace');
|
|
343
|
-
this.element.classList.add('stack-preview-container');
|
|
344
|
-
this.element.classList.toggle('width-constrained', this.#options.widthConstrained ?? false);
|
|
345
|
-
this.element.style.display = 'inline-block';
|
|
240
|
+
constructor(element?: HTMLElement) {
|
|
241
|
+
super(element, {useShadowDom: true, classes: ['monospace', 'stack-preview-container']});
|
|
346
242
|
|
|
347
243
|
UI.DOMUtilities.appendStyle(this.element.shadowRoot as ShadowRoot, jsUtilsStyles);
|
|
348
244
|
|
|
349
245
|
this.#table = this.contentElement.createChild('table', 'stack-preview-container');
|
|
350
|
-
this.#table.classList.toggle('width-constrained', this.#options.widthConstrained ?? false);
|
|
351
|
-
|
|
352
|
-
this.performUpdate();
|
|
353
246
|
}
|
|
354
247
|
|
|
355
248
|
hasContent(): boolean {
|
|
356
|
-
|
|
249
|
+
if (!this.#stackTrace) {
|
|
250
|
+
return false;
|
|
251
|
+
}
|
|
252
|
+
const {syncFragment, asyncFragments} = this.#stackTrace;
|
|
253
|
+
return syncFragment.frames.length > 0 || asyncFragments.some(f => f.frames.length > 0);
|
|
357
254
|
}
|
|
358
255
|
|
|
359
256
|
override performUpdate(): void {
|
|
360
|
-
if (!this.#
|
|
257
|
+
if (!this.#stackTrace) {
|
|
361
258
|
return;
|
|
362
259
|
}
|
|
363
260
|
|
|
364
|
-
const
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
const stackTraceRows = buildStackTraceRows(
|
|
368
|
-
this.#stackTrace, this.#target ?? null, this.#linkifier, tabStops, this.#options.showColumnNumber);
|
|
369
|
-
this.#hasRows = stackTraceRows.length > 0;
|
|
370
|
-
this.#links = renderStackTraceTable(this.#table, this.element, this.#options.expandable ?? false, stackTraceRows);
|
|
371
|
-
return;
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
if (runtimeStackTrace) {
|
|
375
|
-
// TODO(crbug.com/456517732): remove when all usages of runtimeStackTrace are migrated.
|
|
376
|
-
const updateCallback =
|
|
377
|
-
renderStackTraceTable.bind(null, this.#table, this.element, this.#options.expandable ?? false);
|
|
378
|
-
const stackTraceRows = buildStackTraceRowsForLegacyRuntimeStackTrace(
|
|
379
|
-
runtimeStackTrace ?? {callFrames: []}, this.#target ?? null, this.#linkifier, tabStops, updateCallback,
|
|
380
|
-
this.#options.showColumnNumber);
|
|
381
|
-
this.#hasRows = stackTraceRows.length > 0;
|
|
382
|
-
this.#links = renderStackTraceTable(this.#table, this.element, this.#options.expandable ?? false, stackTraceRows);
|
|
383
|
-
}
|
|
261
|
+
const stackTraceRows =
|
|
262
|
+
buildStackTraceRows(this.#stackTrace, this.#options.tabStops, this.#options.showColumnNumber);
|
|
263
|
+
renderStackTraceTable(this.#table, this.element, this.#options.expandable ?? false, stackTraceRows);
|
|
384
264
|
}
|
|
385
265
|
|
|
386
266
|
get linkElements(): readonly HTMLElement[] {
|
|
387
|
-
return this
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
set target(target: SDK.Target.Target|undefined) {
|
|
391
|
-
this.#target = target;
|
|
392
|
-
this.requestUpdate();
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
set linkifier(linkifier: Linkifier) {
|
|
396
|
-
this.#linkifier = linkifier;
|
|
397
|
-
this.requestUpdate();
|
|
267
|
+
return [...this.contentElement.querySelectorAll<HTMLElement>('td.link > .devtools-link')];
|
|
398
268
|
}
|
|
399
269
|
|
|
400
270
|
set options(options: Options) {
|
|
401
271
|
this.#options = options;
|
|
272
|
+
this.#table.classList.toggle('width-constrained', this.#options.widthConstrained ?? false);
|
|
402
273
|
this.requestUpdate();
|
|
403
274
|
}
|
|
404
275
|
|
|
@@ -410,8 +281,4 @@ export class StackTracePreviewContent extends UI.Widget.Widget {
|
|
|
410
281
|
this.#stackTrace.addEventListener(StackTrace.StackTrace.Events.UPDATED, this.requestUpdate, this);
|
|
411
282
|
this.requestUpdate();
|
|
412
283
|
}
|
|
413
|
-
|
|
414
|
-
override onDetach(): void {
|
|
415
|
-
this.#ownedLinkifier?.dispose();
|
|
416
|
-
}
|
|
417
284
|
}
|
|
@@ -17,7 +17,7 @@ import * as TextUtils from '../../../../models/text_utils/text_utils.js';
|
|
|
17
17
|
import type * as Trace from '../../../../models/trace/trace.js';
|
|
18
18
|
import * as Workspace from '../../../../models/workspace/workspace.js';
|
|
19
19
|
import * as UIHelpers from '../../../helpers/helpers.js';
|
|
20
|
-
import {Directives, html, type LitTemplate, render} from '../../../lit/lit.js';
|
|
20
|
+
import {Directives, html, type LitTemplate, render, type TemplateResult} from '../../../lit/lit.js';
|
|
21
21
|
import * as VisualLogging from '../../../visual_logging/visual_logging.js';
|
|
22
22
|
import * as UI from '../../legacy.js';
|
|
23
23
|
|
|
@@ -562,7 +562,7 @@ export class Linkifier extends Common.ObjectWrapper.ObjectWrapper<EventTypes> im
|
|
|
562
562
|
info.icon = icon;
|
|
563
563
|
}
|
|
564
564
|
|
|
565
|
-
static renderLinkifiedUrl(url: Platform.DevToolsPath.UrlString, options?: LinkifyURLOptions):
|
|
565
|
+
static renderLinkifiedUrl(url: Platform.DevToolsPath.UrlString, options?: LinkifyURLOptions): TemplateResult {
|
|
566
566
|
options = options || {
|
|
567
567
|
showColumnNumber: false,
|
|
568
568
|
inlineFrameIndex: 0,
|
|
@@ -639,7 +639,8 @@ export class Linkifier extends Common.ObjectWrapper.ObjectWrapper<EventTypes> im
|
|
|
639
639
|
return link;
|
|
640
640
|
}
|
|
641
641
|
|
|
642
|
-
private static renderLink(text: string|HTMLElement, className: string, options: CreateLinkOptions = {}):
|
|
642
|
+
private static renderLink(text: string|HTMLElement, className: string, options: CreateLinkOptions = {}):
|
|
643
|
+
TemplateResult {
|
|
643
644
|
const {maxLength, title, href, preventClick, tabStop, bypassURLTrimming, jslogContext} = options;
|
|
644
645
|
const classes: Record<string, boolean> = {
|
|
645
646
|
'devtools-link': true,
|
|
@@ -666,6 +667,7 @@ export class Linkifier extends Common.ObjectWrapper.ObjectWrapper<EventTypes> im
|
|
|
666
667
|
if (!link) {
|
|
667
668
|
return;
|
|
668
669
|
}
|
|
670
|
+
options.onRef?.(link as HTMLElement);
|
|
669
671
|
if (text instanceof HTMLElement) {
|
|
670
672
|
link.appendChild(text);
|
|
671
673
|
} else if (bypassURLTrimming) {
|
|
@@ -1153,6 +1155,7 @@ export interface LinkifyURLOptions {
|
|
|
1153
1155
|
userMetric?: Host.UserMetrics.Action;
|
|
1154
1156
|
jslogContext?: string;
|
|
1155
1157
|
omitOrigin?: boolean;
|
|
1158
|
+
onRef?: (el: HTMLElement) => void;
|
|
1156
1159
|
}
|
|
1157
1160
|
|
|
1158
1161
|
export interface LinkifyOptions {
|
|
@@ -1183,6 +1186,7 @@ interface CreateLinkOptions {
|
|
|
1183
1186
|
lineNumber?: number;
|
|
1184
1187
|
columnNumber?: number;
|
|
1185
1188
|
userMetric?: Host.UserMetrics.Action;
|
|
1189
|
+
onRef?: (el: HTMLElement) => void;
|
|
1186
1190
|
}
|
|
1187
1191
|
|
|
1188
1192
|
interface LinkDisplayOptions {
|
package/package.json
CHANGED