chrome-devtools-frontend 1.0.1585538 → 1.0.1586699
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/common/Srcset.ts +61 -0
- package/front_end/core/common/common.ts +2 -0
- package/front_end/generated/SupportedCSSProperties.js +4 -2
- package/front_end/models/ai_assistance/AiConversation.ts +6 -2
- package/front_end/models/ai_code_completion/AiCodeCompletion.ts +12 -0
- package/front_end/models/javascript_metadata/NativeFunctions.js +2 -2
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +1 -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/console/PromptBuilder.ts +15 -3
- package/front_end/panels/elements/ElementsTreeElement.ts +95 -106
- 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/network/components/RequestHeadersView.ts +85 -153
- package/front_end/panels/sources/CallStackSidebarPane.ts +3 -7
- package/front_end/panels/timeline/TimelineUIUtils.ts +2 -6
- package/front_end/panels/utils/utils.ts +13 -5
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/third_party/puppeteer/README.chromium +2 -2
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/FrameManager.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/FrameManager.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/util.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/util.js +7 -7
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/common/util.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.d.ts +3 -3
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/revisions.js +3 -3
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/version.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +7 -7
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/FrameManager.js +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/FrameManager.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/util.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/util.js +7 -7
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/common/util.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.d.ts +3 -3
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/revisions.js +3 -3
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/util/version.js +1 -1
- package/front_end/third_party/puppeteer/package/package.json +2 -2
- package/front_end/third_party/puppeteer/package/src/cdp/FrameManager.ts +1 -1
- package/front_end/third_party/puppeteer/package/src/common/util.ts +9 -8
- package/front_end/third_party/puppeteer/package/src/revisions.ts +3 -3
- package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
- package/front_end/ui/legacy/UIUtils.ts +31 -14
- package/front_end/ui/legacy/components/utils/JSPresentationUtils.ts +96 -216
- 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
|
@@ -0,0 +1,61 @@
|
|
|
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
|
+
export const enum TokenType {
|
|
6
|
+
LITERAL = 0,
|
|
7
|
+
URL = 1
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface Token {
|
|
11
|
+
type: TokenType;
|
|
12
|
+
value: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Parsing of
|
|
17
|
+
* https://html.spec.whatwg.org/multipage/images.html#srcset-attribute and href
|
|
18
|
+
* attributes to identify URLs vs other text in the srcset.
|
|
19
|
+
*
|
|
20
|
+
* Note: this is probably not spec compliant.
|
|
21
|
+
*/
|
|
22
|
+
export function parseSrcset(value: string): Token[] {
|
|
23
|
+
const result: Token[] = [];
|
|
24
|
+
let i = 0;
|
|
25
|
+
while (value.length) {
|
|
26
|
+
if (i++ > 0) {
|
|
27
|
+
result.push({value: ' ', type: TokenType.LITERAL});
|
|
28
|
+
}
|
|
29
|
+
value = value.trim();
|
|
30
|
+
let url = '';
|
|
31
|
+
let descriptor = '';
|
|
32
|
+
const indexOfSpace = value.search(/\s/);
|
|
33
|
+
if (indexOfSpace === -1) {
|
|
34
|
+
url = value;
|
|
35
|
+
} else if (indexOfSpace > 0 && value[indexOfSpace - 1] === ',') {
|
|
36
|
+
url = value.substring(0, indexOfSpace);
|
|
37
|
+
} else {
|
|
38
|
+
url = value.substring(0, indexOfSpace);
|
|
39
|
+
const indexOfComma = value.indexOf(',', indexOfSpace);
|
|
40
|
+
if (indexOfComma !== -1) {
|
|
41
|
+
descriptor = value.substring(indexOfSpace, indexOfComma + 1);
|
|
42
|
+
} else {
|
|
43
|
+
descriptor = value.substring(indexOfSpace);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (url) {
|
|
48
|
+
if (url.endsWith(',')) {
|
|
49
|
+
result.push({value: url.substring(0, url.length - 1), type: TokenType.URL});
|
|
50
|
+
result.push({type: TokenType.LITERAL, value: ','});
|
|
51
|
+
} else {
|
|
52
|
+
result.push({value: url, type: TokenType.URL});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if (descriptor) {
|
|
56
|
+
result.push({type: TokenType.LITERAL, value: descriptor});
|
|
57
|
+
}
|
|
58
|
+
value = value.substring(url.length + descriptor.length);
|
|
59
|
+
}
|
|
60
|
+
return result;
|
|
61
|
+
}
|
|
@@ -29,6 +29,7 @@ import * as SegmentedRange from './SegmentedRange.js';
|
|
|
29
29
|
import * as SettingRegistration from './SettingRegistration.js';
|
|
30
30
|
import * as Settings from './Settings.js';
|
|
31
31
|
import * as SimpleHistoryManager from './SimpleHistoryManager.js';
|
|
32
|
+
import * as Srcset from './Srcset.js';
|
|
32
33
|
import * as StringOutputStream from './StringOutputStream.js';
|
|
33
34
|
import * as TextDictionary from './TextDictionary.js';
|
|
34
35
|
import * as Throttler from './Throttler.js';
|
|
@@ -68,6 +69,7 @@ export {
|
|
|
68
69
|
SettingRegistration,
|
|
69
70
|
Settings,
|
|
70
71
|
SimpleHistoryManager,
|
|
72
|
+
Srcset,
|
|
71
73
|
StringOutputStream,
|
|
72
74
|
TextDictionary,
|
|
73
75
|
Throttler,
|
|
@@ -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": {
|
|
@@ -456,16 +456,20 @@ Time: ${micros(time)}`;
|
|
|
456
456
|
},
|
|
457
457
|
options.multimodalInput,
|
|
458
458
|
)) {
|
|
459
|
+
// Add to history if relevant
|
|
459
460
|
if (shouldAddToHistory(data)) {
|
|
460
461
|
void this.addHistoryItem(data);
|
|
461
462
|
}
|
|
463
|
+
// Always yield the data
|
|
464
|
+
yield data;
|
|
465
|
+
|
|
466
|
+
// If we change the context
|
|
467
|
+
// requery with the specialized agent.
|
|
462
468
|
if (data.type === ResponseType.CONTEXT_CHANGE) {
|
|
463
469
|
this.setContext(data.context);
|
|
464
470
|
yield* this.#runAgent(initialQuery, options);
|
|
465
471
|
return;
|
|
466
472
|
}
|
|
467
|
-
|
|
468
|
-
yield data;
|
|
469
473
|
}
|
|
470
474
|
}
|
|
471
475
|
|
|
@@ -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 {
|
|
@@ -6624,8 +6624,8 @@ export const NativeFunctions = [
|
|
|
6624
6624
|
signatures: [["type","?eventInitDict"]]
|
|
6625
6625
|
},
|
|
6626
6626
|
{
|
|
6627
|
-
name: "
|
|
6628
|
-
signatures: [["
|
|
6627
|
+
name: "getValueRange",
|
|
6628
|
+
signatures: [["start","end"]]
|
|
6629
6629
|
},
|
|
6630
6630
|
{
|
|
6631
6631
|
name: "getBoxQuads",
|
|
@@ -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()
|
|
@@ -9,6 +9,7 @@ import * as Formatter from '../../models/formatter/formatter.js';
|
|
|
9
9
|
import * as Logs from '../../models/logs/logs.js';
|
|
10
10
|
import * as TextUtils from '../../models/text_utils/text_utils.js';
|
|
11
11
|
import * as Components from '../../ui/legacy/components/utils/utils.js';
|
|
12
|
+
import * as UI from '../../ui/legacy/legacy.js';
|
|
12
13
|
|
|
13
14
|
import type {ConsoleViewMessage} from './ConsoleViewMessage.js';
|
|
14
15
|
|
|
@@ -85,7 +86,7 @@ export class PromptBuilder {
|
|
|
85
86
|
|
|
86
87
|
const relatedCode = sourceCode?.text ? formatRelatedCode(sourceCode) : '';
|
|
87
88
|
const relatedRequest = request ? formatNetworkRequest(request) : '';
|
|
88
|
-
const stacktrace = sourcesTypes.includes(SourceType.STACKTRACE) ? formatStackTrace(this.#consoleMessage) : '';
|
|
89
|
+
const stacktrace = sourcesTypes.includes(SourceType.STACKTRACE) ? await formatStackTrace(this.#consoleMessage) : '';
|
|
89
90
|
|
|
90
91
|
const message = formatConsoleMessage(this.#consoleMessage);
|
|
91
92
|
|
|
@@ -290,14 +291,25 @@ export function formatConsoleMessage(message: ConsoleViewMessage): string {
|
|
|
290
291
|
* This formats the stacktrace from the console message which might or might not
|
|
291
292
|
* match the content of stacktrace(s) in the console message arguments.
|
|
292
293
|
*/
|
|
293
|
-
|
|
294
|
+
async function formatStackTrace(message: ConsoleViewMessage): Promise<string> {
|
|
294
295
|
const previewContainer = message.contentElement().querySelector('.stack-preview-container');
|
|
295
296
|
|
|
296
297
|
if (!previewContainer) {
|
|
297
298
|
return '';
|
|
298
299
|
}
|
|
299
300
|
|
|
300
|
-
const
|
|
301
|
+
const widget =
|
|
302
|
+
UI.Widget.Widget.get(previewContainer) as Components.JSPresentationUtils.StackTracePreviewContent | undefined;
|
|
303
|
+
if (!widget) {
|
|
304
|
+
return '';
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
await widget.updateComplete;
|
|
308
|
+
|
|
309
|
+
// TODO(crbug.com/433162438): Get the `StackTrace` from the widget and render that instead
|
|
310
|
+
// of crawling the DOM. `StackTrace` is source mapped and has ignore listing.
|
|
311
|
+
|
|
312
|
+
const preview = widget.contentElement.querySelector('.stack-preview-container') as HTMLElement;
|
|
301
313
|
|
|
302
314
|
const nodes = preview.childTextNodes();
|
|
303
315
|
// Gets application-level source mapped stack trace taking the ignore list
|
|
@@ -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,86 @@ function renderTitle(
|
|
|
634
634
|
}
|
|
635
635
|
}
|
|
636
636
|
|
|
637
|
-
function
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
637
|
+
function renderLinkifiedSrcset(tokens: Common.Srcset.Token[], node: SDK.DOMModel.DOMNode): Lit.TemplateResult {
|
|
638
|
+
return html`${repeat(tokens, token => {
|
|
639
|
+
switch (token.type) {
|
|
640
|
+
case Common.Srcset.TokenType.URL:
|
|
641
|
+
return renderLinkifiedValue(token.value, node);
|
|
642
|
+
case Common.Srcset.TokenType.LITERAL:
|
|
643
|
+
return token.value;
|
|
644
|
+
}
|
|
645
|
+
})}`;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
const closingPunctuationRegex = /[\/;:\)\]\}]/g;
|
|
649
|
+
|
|
650
|
+
// FIXME: this should be made declarative next.
|
|
651
|
+
function setValueWithEntities(element: Element, value: string): void {
|
|
644
652
|
let highlightIndex = 0;
|
|
645
653
|
let highlightCount = 0;
|
|
646
654
|
let additionalHighlightOffset = 0;
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
highlightCount
|
|
651
|
-
const newValue = result.text.replace(closingPunctuationRegex, (match, replaceOffset) => {
|
|
652
|
-
while (highlightIndex < highlightCount && result.entityRanges[highlightIndex].offset < replaceOffset) {
|
|
653
|
-
result.entityRanges[highlightIndex].offset += additionalHighlightOffset;
|
|
654
|
-
++highlightIndex;
|
|
655
|
-
}
|
|
656
|
-
additionalHighlightOffset += 1;
|
|
657
|
-
return match + '\u200B';
|
|
658
|
-
});
|
|
659
|
-
|
|
660
|
-
while (highlightIndex < highlightCount) {
|
|
655
|
+
const result = convertUnicodeCharsToHTMLEntities(value);
|
|
656
|
+
highlightCount = result.entityRanges.length;
|
|
657
|
+
const newValue = result.text.replace(closingPunctuationRegex, (match, replaceOffset) => {
|
|
658
|
+
while (highlightIndex < highlightCount && result.entityRanges[highlightIndex].offset < replaceOffset) {
|
|
661
659
|
result.entityRanges[highlightIndex].offset += additionalHighlightOffset;
|
|
662
660
|
++highlightIndex;
|
|
663
661
|
}
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
const hasText = (forceValue || value.length > 0);
|
|
669
|
-
const jslog = VisualLogging.value(name === 'style' ? 'style-attribute' : 'attribute').track({
|
|
670
|
-
change: true,
|
|
671
|
-
dblclick: true,
|
|
662
|
+
additionalHighlightOffset += 1;
|
|
663
|
+
return match + '\u200B';
|
|
672
664
|
});
|
|
673
665
|
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
const span = document.createElement('span');
|
|
678
|
-
setValueWithEntities(span, value);
|
|
679
|
-
return span;
|
|
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);
|
|
666
|
+
while (highlightIndex < highlightCount) {
|
|
667
|
+
result.entityRanges[highlightIndex].offset += additionalHighlightOffset;
|
|
668
|
+
++highlightIndex;
|
|
694
669
|
}
|
|
670
|
+
element.setTextContentTruncatedIfNeeded(newValue);
|
|
671
|
+
Highlighting.highlightRangesWithStyleClass(element, result.entityRanges, 'webkit-html-entity-value');
|
|
672
|
+
}
|
|
695
673
|
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
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
|
-
}
|
|
721
|
-
|
|
722
|
-
if (url) {
|
|
723
|
-
if (url.endsWith(',')) {
|
|
724
|
-
fragment.appendChild(linkifyValue(url.substring(0, url.length - 1)));
|
|
725
|
-
UI.UIUtils.createTextChild(fragment, ',');
|
|
726
|
-
} else {
|
|
727
|
-
fragment.appendChild(linkifyValue(url));
|
|
728
|
-
}
|
|
674
|
+
function renderLinkifiedValue(value: string, node: SDK.DOMModel.DOMNode): Lit.TemplateResult {
|
|
675
|
+
const rewrittenHref = node ? node.resolveURL(value) : null;
|
|
676
|
+
if (rewrittenHref === null) {
|
|
677
|
+
return html`<span ${ref(el => {
|
|
678
|
+
if (el) {
|
|
679
|
+
setValueWithEntities(el, value);
|
|
729
680
|
}
|
|
730
|
-
|
|
731
|
-
|
|
681
|
+
})}}></span>`;
|
|
682
|
+
}
|
|
683
|
+
value = value.replace(closingPunctuationRegex, '$&\u200B');
|
|
684
|
+
if (value.startsWith('data:')) {
|
|
685
|
+
value = Platform.StringUtilities.trimMiddle(value, 60);
|
|
686
|
+
}
|
|
687
|
+
const isAnchor = node && node.nodeName().toLowerCase() === 'a';
|
|
688
|
+
if (isAnchor) {
|
|
689
|
+
return html`<devtools-link class="devtools-link image-url" href=${rewrittenHref} ${ref(el => {
|
|
690
|
+
if (el) {
|
|
691
|
+
ImagePreviewPopover.setImageUrl(el, rewrittenHref);
|
|
732
692
|
}
|
|
733
|
-
|
|
734
|
-
}
|
|
735
|
-
return fragment;
|
|
693
|
+
})}>${Platform.StringUtilities.trimMiddle(value, 150)}</devtools-link>`;
|
|
736
694
|
}
|
|
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);
|
|
695
|
+
return Components.Linkifier.Linkifier.renderLinkifiedUrl(rewrittenHref, {
|
|
696
|
+
text: value,
|
|
697
|
+
preventClick: true,
|
|
698
|
+
showColumnNumber: false,
|
|
699
|
+
inlineFrameIndex: 0,
|
|
700
|
+
onRef: link => {
|
|
701
|
+
ImagePreviewPopover.setImageUrl(link, rewrittenHref);
|
|
753
702
|
}
|
|
754
703
|
});
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
function renderAttribute(
|
|
707
|
+
attr: {name: string, value?: string}, updateRecord: Elements.ElementUpdateRecord.ElementUpdateRecord|null,
|
|
708
|
+
isDiff: boolean, node: SDK.DOMModel.DOMNode): Lit.LitTemplate {
|
|
709
|
+
const name = attr.name;
|
|
710
|
+
const value = attr.value || '';
|
|
711
|
+
const forceValue = isDiff;
|
|
712
|
+
const hasText = (forceValue || value.length > 0);
|
|
713
|
+
const jslog = VisualLogging.value(name === 'style' ? 'style-attribute' : 'attribute').track({
|
|
714
|
+
change: true,
|
|
715
|
+
dblclick: true,
|
|
716
|
+
});
|
|
755
717
|
|
|
756
718
|
const relationRef =
|
|
757
719
|
(relation: Protocol.DOM.GetElementByRelationRequestRelation, tooltip: string): ReturnType<typeof ref> =>
|
|
@@ -804,14 +766,41 @@ function renderAttribute(
|
|
|
804
766
|
}
|
|
805
767
|
}
|
|
806
768
|
|
|
769
|
+
const nodeName = node ? node.nodeName().toLowerCase() : '';
|
|
770
|
+
const enum ValueType {
|
|
771
|
+
UNKNOWN = 0,
|
|
772
|
+
SRC = 1,
|
|
773
|
+
SRCSET = 2,
|
|
774
|
+
}
|
|
775
|
+
let valueType = ValueType.UNKNOWN;
|
|
776
|
+
if (nodeName && (name === 'src' || name === 'href') && value) {
|
|
777
|
+
valueType = ValueType.SRC;
|
|
778
|
+
} else if ((nodeName === 'img' || nodeName === 'source') && name === 'srcset') {
|
|
779
|
+
valueType = ValueType.SRCSET;
|
|
780
|
+
} else if (nodeName === 'image' && (name === 'xlink:href' || name === 'href')) {
|
|
781
|
+
valueType = ValueType.SRCSET;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
const withEntitiesRef = valueType === ValueType.UNKNOWN ? ref(el => {
|
|
785
|
+
if (el) {
|
|
786
|
+
setValueWithEntities(el, value);
|
|
787
|
+
}
|
|
788
|
+
}) :
|
|
789
|
+
nothing;
|
|
790
|
+
|
|
791
|
+
// clang-format off
|
|
807
792
|
return html`<span class="webkit-html-attribute" jslog=${jslog}><span class="webkit-html-attribute-name"
|
|
808
793
|
${animateOn(Boolean(updateRecord?.isAttributeModified(name) && !hasText), DOM_UPDATE_ANIMATION_CLASS_NAME)} ${
|
|
809
794
|
relationRefDirective}>${name}</span>${
|
|
810
795
|
hasText ? html`=\u200B"<span class="webkit-html-attribute-value" ${
|
|
811
796
|
animateOn(
|
|
812
797
|
Boolean(updateRecord?.isAttributeModified(name) && hasText),
|
|
813
|
-
DOM_UPDATE_ANIMATION_CLASS_NAME)} ${
|
|
798
|
+
DOM_UPDATE_ANIMATION_CLASS_NAME)} ${valueRelationRefDirective} ${withEntitiesRef}>
|
|
799
|
+
${valueType === ValueType.SRC ? renderLinkifiedValue(value, node) : nothing}
|
|
800
|
+
${valueType === ValueType.SRCSET ? renderLinkifiedSrcset(Common.Srcset.parseSrcset(value), node) : nothing}
|
|
801
|
+
</span>"` :
|
|
814
802
|
nothing}</span>`;
|
|
803
|
+
// clang-format on
|
|
815
804
|
}
|
|
816
805
|
|
|
817
806
|
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
|
}
|