chrome-devtools-frontend 1.0.1662289 → 1.0.1662965
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/devtools-unicode-escaping/SKILL.md +64 -0
- package/.agents/skills/migrate-chromium-test/SKILL.md +29 -4
- package/front_end/core/common/SettingRegistration.ts +0 -5
- package/front_end/core/common/Settings.ts +69 -3
- package/front_end/core/platform/StringUtilities.ts +38 -6
- package/front_end/core/sdk/ServiceWorkerCacheModel.ts +0 -10
- package/front_end/core/sdk/StorageBucketsModel.ts +0 -10
- package/front_end/core/sdk/sdk-meta.ts +0 -1
- package/front_end/entrypoints/inspector_main/OutermostTargetSelector.ts +0 -13
- package/front_end/entrypoints/inspector_main/RenderingOptions.ts +8 -3
- package/front_end/entrypoints/inspector_main/inspector_main-meta.ts +3 -3
- package/front_end/entrypoints/main/MainImpl.ts +7 -2
- package/front_end/foundation/Universe.ts +16 -0
- package/front_end/generated/InspectorBackendCommands.ts +2 -14
- package/front_end/generated/protocol-mapping.d.ts +0 -53
- package/front_end/generated/protocol-proxy-api.d.ts +0 -46
- package/front_end/generated/protocol.ts +0 -148
- package/front_end/models/ai_assistance/AiAgent2.ts +3 -3
- package/front_end/models/ai_assistance/AiConversation.ts +21 -10
- package/front_end/models/ai_assistance/AiHistoryStorage.ts +21 -10
- package/front_end/models/ai_assistance/ChangeManager.ts +2 -2
- package/front_end/models/ai_assistance/ExtensionScope.ts +6 -2
- package/front_end/models/ai_assistance/agents/AccessibilityAgent.ts +1 -1
- package/front_end/models/ai_assistance/agents/AiAgent.ts +8 -1
- package/front_end/models/ai_assistance/agents/StylingAgent.ts +1 -1
- package/front_end/models/badges/UserBadges.ts +31 -17
- package/front_end/models/bindings/NetworkProject.ts +16 -4
- package/front_end/models/emulation/DeviceModeModel.ts +67 -5
- package/front_end/models/extensions/RecorderPluginManager.ts +10 -6
- package/front_end/models/har/Log.snapshot.txt +193 -0
- package/front_end/models/har/Log.ts +3 -2
- package/front_end/models/source_map_scopes/FunctionCodeResolver.ts +7 -5
- package/front_end/models/source_map_scopes/NamesResolver.ts +36 -30
- package/front_end/models/stack_trace/StackTrace.ts +17 -0
- package/front_end/panels/application/IndexedDBModel.ts +0 -10
- package/front_end/panels/application/IndexedDBViews.ts +240 -164
- package/front_end/panels/application/SharedStorageModel.ts +0 -10
- package/front_end/panels/application/components/AdsView.ts +23 -0
- package/front_end/panels/application/components/SharedStorageAccessGrid.ts +1 -1
- package/front_end/panels/application/components/adsView.css +21 -1
- package/front_end/panels/application/indexedDBViews.css +1 -1
- package/front_end/panels/network/NetworkDataGridNode.ts +43 -1
- package/front_end/panels/network/RequestInitiatorView.ts +24 -2
- package/front_end/panels/network/networkLogView.css +5 -0
- package/front_end/panels/network/requestInitiatorViewTree.css +5 -0
- package/front_end/panels/profiler/HeapProfileView.ts +198 -79
- package/front_end/panels/recorder/README.md +1 -2
- package/front_end/panels/recorder/RecorderPanel.ts +1749 -17
- package/front_end/panels/recorder/recorder.ts +0 -2
- package/front_end/panels/settings/AISettingsTab.ts +13 -0
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/ui/components/spinners/Spinner.ts +29 -32
- package/front_end/ui/components/spinners/spinner.css +32 -84
- package/front_end/ui/legacy/Treeoutline.ts +14 -6
- package/front_end/ui/legacy/UIUtils.ts +25 -10
- package/front_end/ui/legacy/Widget.ts +17 -10
- package/front_end/ui/legacy/components/data_grid/DataGridElement.ts +36 -7
- package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +63 -68
- package/front_end/ui/legacy/components/object_ui/RemoteObjectPreviewFormatter.ts +1 -1
- package/front_end/ui/legacy/components/object_ui/objectValue.css +2 -1
- package/front_end/ui/legacy/inspectorCommon.css +4 -4
- package/front_end/ui/lit/lit.ts +1 -0
- package/front_end/ui/lit/render.ts +44 -10
- package/front_end/ui/lit/strip-whitespace.ts +23 -2
- package/package.json +1 -1
- package/front_end/panels/recorder/RecorderController.ts +0 -1759
- /package/front_end/panels/recorder/{recorderController.css → recorderPanel.css} +0 -0
|
@@ -48,9 +48,10 @@ import {CustomPreviewComponent} from './CustomPreviewComponent.js';
|
|
|
48
48
|
import {JavaScriptREPL} from './JavaScriptREPL.js';
|
|
49
49
|
import objectPropertiesSectionStyles from './objectPropertiesSection.css.js';
|
|
50
50
|
import objectValueStyles from './objectValue.css.js';
|
|
51
|
-
import {RemoteObjectPreviewFormatter, renderNodeTitle} from './RemoteObjectPreviewFormatter.js';
|
|
51
|
+
import {RemoteObjectPreviewFormatter, renderNodeTitle, renderTrustedType} from './RemoteObjectPreviewFormatter.js';
|
|
52
52
|
|
|
53
53
|
export {objectPropertiesSectionStyles, objectValueStyles};
|
|
54
|
+
|
|
54
55
|
const {widget} = UI.Widget;
|
|
55
56
|
const {ref, repeat, ifDefined, classMap, until} = Directives;
|
|
56
57
|
const UIStrings = {
|
|
@@ -259,8 +260,8 @@ export class ObjectTreeExpansionTracker {
|
|
|
259
260
|
if (!(node instanceof ObjectTreeNode)) {
|
|
260
261
|
return undefined;
|
|
261
262
|
}
|
|
262
|
-
return node.parent?.children?.internalProperties?.find(
|
|
263
|
-
|
|
263
|
+
return node.parent?.children?.internalProperties?.find(p => p.name === '[[Prototype]]' &&
|
|
264
|
+
p.children?.properties?.includes(node));
|
|
264
265
|
}
|
|
265
266
|
|
|
266
267
|
static #keyType(node: ObjectTreeNodeBase): keyof NodeChildren|null {
|
|
@@ -572,8 +573,8 @@ export abstract class ObjectTreeNodeBase extends Common.ObjectWrapper.ObjectWrap
|
|
|
572
573
|
}
|
|
573
574
|
|
|
574
575
|
const {properties: objectProperties, internalProperties: objectInternalProperties} =
|
|
575
|
-
await SDK.RemoteObject.RemoteObject.loadFromObjectPerProto(
|
|
576
|
-
|
|
576
|
+
await SDK.RemoteObject.RemoteObject.loadFromObjectPerProto(this.object, true /* generatePreview */,
|
|
577
|
+
true /* nonIndexedPropertiesOnly */);
|
|
577
578
|
|
|
578
579
|
const properties = objectProperties?.map(p => new ObjectTreeNode(p, effectiveParent, {
|
|
579
580
|
readOnly: this.readOnly,
|
|
@@ -647,8 +648,8 @@ export abstract class ObjectTreeNodeBase extends Common.ObjectWrapper.ObjectWrap
|
|
|
647
648
|
for (const property of properties) {
|
|
648
649
|
if (property.property.isOwn) {
|
|
649
650
|
if (property.property.getter) {
|
|
650
|
-
const getterProperty = new SDK.RemoteObject.RemoteObjectProperty(
|
|
651
|
-
|
|
651
|
+
const getterProperty = new SDK.RemoteObject.RemoteObjectProperty('get ' + property.property.name,
|
|
652
|
+
property.property.getter, false);
|
|
652
653
|
gettersAndSetters.push(new ObjectTreeNode(getterProperty, property.parent, {
|
|
653
654
|
propertiesMode: property.propertiesMode,
|
|
654
655
|
readOnly: property.readOnly,
|
|
@@ -656,8 +657,8 @@ export abstract class ObjectTreeNodeBase extends Common.ObjectWrapper.ObjectWrap
|
|
|
656
657
|
}));
|
|
657
658
|
}
|
|
658
659
|
if (property.property.setter) {
|
|
659
|
-
const setterProperty = new SDK.RemoteObject.RemoteObjectProperty(
|
|
660
|
-
|
|
660
|
+
const setterProperty = new SDK.RemoteObject.RemoteObjectProperty('set ' + property.property.name,
|
|
661
|
+
property.property.setter, false);
|
|
661
662
|
gettersAndSetters.push(new ObjectTreeNode(setterProperty, property.parent, {
|
|
662
663
|
propertiesMode: property.propertiesMode,
|
|
663
664
|
readOnly: property.readOnly,
|
|
@@ -706,9 +707,8 @@ interface ArrayGroupRange {
|
|
|
706
707
|
export class ArrayGroupTreeNode extends ObjectTreeNodeBase {
|
|
707
708
|
readonly #object: SDK.RemoteObject.RemoteObject;
|
|
708
709
|
readonly #range: ArrayGroupRange;
|
|
709
|
-
constructor(
|
|
710
|
-
|
|
711
|
-
options: ObjectTreeOptions) {
|
|
710
|
+
constructor(object: SDK.RemoteObject.RemoteObject, range: ArrayGroupRange, parent: ObjectTreeNodeBase,
|
|
711
|
+
options: ObjectTreeOptions) {
|
|
712
712
|
super(parent, options);
|
|
713
713
|
this.#object = object;
|
|
714
714
|
this.#range = range;
|
|
@@ -879,9 +879,8 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
|
|
|
879
879
|
titleElement: Element;
|
|
880
880
|
skipProtoInternal?: boolean;
|
|
881
881
|
|
|
882
|
-
constructor(
|
|
883
|
-
|
|
884
|
-
showOverflow?: boolean, editable = true) {
|
|
882
|
+
constructor(object: SDK.RemoteObject.RemoteObject, title?: string|Element|null,
|
|
883
|
+
linkifier?: Components.Linkifier.Linkifier, showOverflow?: boolean, editable = true) {
|
|
885
884
|
super();
|
|
886
885
|
this.root = new ObjectTree(object, {
|
|
887
886
|
readOnly: !editable,
|
|
@@ -896,7 +895,7 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
|
|
|
896
895
|
this.appendChild(this.#objectTreeElement);
|
|
897
896
|
if (typeof title === 'string' || !title) {
|
|
898
897
|
this.titleElement = this.element.createChild('span');
|
|
899
|
-
this.titleElement.textContent = title
|
|
898
|
+
this.titleElement.textContent = title ? Platform.StringUtilities.escapeUnicodeAsText(title) : '';
|
|
900
899
|
} else {
|
|
901
900
|
this.titleElement = title;
|
|
902
901
|
this.element.appendChild(title);
|
|
@@ -910,9 +909,8 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
|
|
|
910
909
|
this.rootElement().childrenListElement.classList.add('source-code', 'object-properties-section');
|
|
911
910
|
}
|
|
912
911
|
|
|
913
|
-
static defaultObjectPresentation(
|
|
914
|
-
|
|
915
|
-
readOnly?: boolean): Element {
|
|
912
|
+
static defaultObjectPresentation(object: SDK.RemoteObject.RemoteObject, linkifier?: Components.Linkifier.Linkifier,
|
|
913
|
+
skipProto?: boolean, readOnly?: boolean): Element {
|
|
916
914
|
const objectPropertiesSection =
|
|
917
915
|
ObjectPropertiesSection.defaultObjectPropertiesSection(object, linkifier, skipProto, readOnly);
|
|
918
916
|
if (!object.hasChildren) {
|
|
@@ -921,9 +919,9 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
|
|
|
921
919
|
return objectPropertiesSection.element;
|
|
922
920
|
}
|
|
923
921
|
|
|
924
|
-
static defaultObjectPropertiesSection(
|
|
925
|
-
|
|
926
|
-
|
|
922
|
+
static defaultObjectPropertiesSection(object: SDK.RemoteObject.RemoteObject,
|
|
923
|
+
linkifier?: Components.Linkifier.Linkifier, skipProto?: boolean,
|
|
924
|
+
readOnly?: boolean): ObjectPropertiesSection {
|
|
927
925
|
const titleElement = document.createElement('span');
|
|
928
926
|
titleElement.classList.add('source-code');
|
|
929
927
|
const shadowRoot = UI.UIUtils.createShadowRootWithCoreStyles(titleElement, {cssFile: objectValueStyles});
|
|
@@ -1001,24 +999,25 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
|
|
|
1001
999
|
if (name === null) {
|
|
1002
1000
|
return element;
|
|
1003
1001
|
}
|
|
1004
|
-
|
|
1005
|
-
|
|
1002
|
+
const escapedName = Platform.StringUtilities.escapeUnicodeAsText(name);
|
|
1003
|
+
if (/^\s|\s$|^$|\n/.test(escapedName)) {
|
|
1004
|
+
element.textContent = `"${escapedName.replace(/\n/g, '\u21B5')}"`;
|
|
1006
1005
|
return element;
|
|
1007
1006
|
}
|
|
1008
1007
|
if (isPrivate) {
|
|
1009
1008
|
const privatePropertyHash = document.createElement('span');
|
|
1010
1009
|
privatePropertyHash.classList.add('private-property-hash');
|
|
1011
|
-
privatePropertyHash.textContent =
|
|
1010
|
+
privatePropertyHash.textContent = escapedName[0];
|
|
1012
1011
|
element.appendChild(privatePropertyHash);
|
|
1013
|
-
element.appendChild(document.createTextNode(
|
|
1012
|
+
element.appendChild(document.createTextNode(escapedName.substring(1)));
|
|
1014
1013
|
return element;
|
|
1015
1014
|
}
|
|
1016
|
-
element.textContent =
|
|
1015
|
+
element.textContent = escapedName;
|
|
1017
1016
|
return element;
|
|
1018
1017
|
}
|
|
1019
1018
|
|
|
1020
|
-
static valueElementForFunctionDescription(
|
|
1021
|
-
|
|
1019
|
+
static valueElementForFunctionDescription(description?: string, includePreview?: boolean, defaultName?: string,
|
|
1020
|
+
className?: string): LitTemplate {
|
|
1022
1021
|
const contents =
|
|
1023
1022
|
(description: string, defaultName: string): {prefix: string, abbreviation: string, body: string} => {
|
|
1024
1023
|
const text = description.replace(/^function [gs]et /, 'function ')
|
|
@@ -1095,17 +1094,17 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
|
|
|
1095
1094
|
}
|
|
1096
1095
|
}
|
|
1097
1096
|
|
|
1098
|
-
static createPropertyValueWithCustomSupport(
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1097
|
+
static createPropertyValueWithCustomSupport(value: SDK.RemoteObject.RemoteObject, wasThrown: boolean,
|
|
1098
|
+
showPreview: boolean, linkifier?: Components.Linkifier.Linkifier,
|
|
1099
|
+
isSyntheticProperty?: boolean, variableName?: string,
|
|
1100
|
+
includeNullOrUndefined?: boolean): HTMLElement {
|
|
1102
1101
|
if (value.customPreview()) {
|
|
1103
1102
|
const result = (new CustomPreviewComponent(value)).element;
|
|
1104
1103
|
result.classList.add('object-properties-section-custom-section');
|
|
1105
1104
|
return result;
|
|
1106
1105
|
}
|
|
1107
|
-
return ObjectPropertiesSection.createPropertyValue(
|
|
1108
|
-
|
|
1106
|
+
return ObjectPropertiesSection.createPropertyValue(value, wasThrown, showPreview, linkifier, isSyntheticProperty,
|
|
1107
|
+
variableName, includeNullOrUndefined);
|
|
1109
1108
|
}
|
|
1110
1109
|
|
|
1111
1110
|
static getMemoryIcon(object: SDK.RemoteObject.RemoteObject, expression?: string): LitTemplate {
|
|
@@ -1132,10 +1131,9 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
|
|
|
1132
1131
|
element.appendChild(fragment);
|
|
1133
1132
|
}
|
|
1134
1133
|
|
|
1135
|
-
static createPropertyValue(
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
includeNullOrUndefined?: boolean): HTMLElement {
|
|
1134
|
+
static createPropertyValue(value: SDK.RemoteObject.RemoteObject, wasThrown: boolean, showPreview: boolean,
|
|
1135
|
+
linkifier?: Components.Linkifier.Linkifier, isSyntheticProperty = false,
|
|
1136
|
+
variableName?: string, includeNullOrUndefined?: boolean): HTMLElement {
|
|
1139
1137
|
const propertyValue = document.createDocumentFragment();
|
|
1140
1138
|
const type = value.type;
|
|
1141
1139
|
const subtype = value.subtype;
|
|
@@ -1149,21 +1147,20 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
|
|
|
1149
1147
|
if (rawLocation && linkifier) {
|
|
1150
1148
|
return html`${linkifier.linkifyRawLocation(rawLocation, Platform.DevToolsPath.EmptyUrlString, 'value')}`;
|
|
1151
1149
|
}
|
|
1152
|
-
|
|
1150
|
+
const title = description || undefined;
|
|
1151
|
+
return html`<span class=value title=${ifDefined(title)}>${'<' + i18nString(UIStrings.unknown) + '>'}</span>`;
|
|
1153
1152
|
}
|
|
1154
1153
|
if (type === 'string' && typeof description === 'string') {
|
|
1155
|
-
const text = Platform.StringUtilities.
|
|
1154
|
+
const text = Platform.StringUtilities.escapeUnicodeAsText(JSON.stringify(description));
|
|
1156
1155
|
const tooLong = description.length > maxRenderableStringLength;
|
|
1157
1156
|
return html`<span class="value object-value-string" title=${ifDefined(tooLong ? undefined : description)}>${
|
|
1158
1157
|
tooLong ? widget(ExpandableTextPropertyValue, {text}) : text}</span>`;
|
|
1159
1158
|
}
|
|
1160
1159
|
if (type === 'object' && subtype === 'trustedtype') {
|
|
1161
|
-
const text = `${className}
|
|
1160
|
+
const text = `${className} "${description}"`;
|
|
1162
1161
|
const tooLong = text.length > maxRenderableStringLength;
|
|
1163
1162
|
return html`<span class="value object-value-trustedtype" title=${ifDefined(tooLong ? undefined : text)}>${
|
|
1164
|
-
tooLong ? widget(ExpandableTextPropertyValue, {text}) :
|
|
1165
|
-
html`${className} <span class=object-value-string title=${description}>${
|
|
1166
|
-
Platform.StringUtilities.escapeUnicode(JSON.stringify(description))}</span>`}</span>`;
|
|
1163
|
+
tooLong ? widget(ExpandableTextPropertyValue, {text}) : renderTrustedType(description, className)}</span>`;
|
|
1167
1164
|
}
|
|
1168
1165
|
if (type === 'function') {
|
|
1169
1166
|
return ObjectPropertiesSection.valueElementForFunctionDescription(description, undefined, undefined, 'value');
|
|
@@ -1194,10 +1191,9 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
|
|
|
1194
1191
|
|
|
1195
1192
|
if (wasThrown) {
|
|
1196
1193
|
// eslint-disable-next-line @devtools/no-lit-render-outside-of-view
|
|
1197
|
-
render(
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
propertyValue);
|
|
1194
|
+
render(html`<span class="error value">${
|
|
1195
|
+
uiI18n.getFormatLocalizedStringTemplate(str_, UIStrings.exceptionS, {PH1: contents()})}</span>`,
|
|
1196
|
+
propertyValue);
|
|
1201
1197
|
} else {
|
|
1202
1198
|
// eslint-disable-next-line @devtools/no-lit-render-outside-of-view
|
|
1203
1199
|
render(contents(), propertyValue);
|
|
@@ -1209,9 +1205,8 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
|
|
|
1209
1205
|
return child;
|
|
1210
1206
|
}
|
|
1211
1207
|
|
|
1212
|
-
static formatObjectAsFunction(
|
|
1213
|
-
|
|
1214
|
-
includePreview?: boolean): Promise<void> {
|
|
1208
|
+
static formatObjectAsFunction(func: SDK.RemoteObject.RemoteObject, element: Element, linkify: boolean,
|
|
1209
|
+
includePreview?: boolean): Promise<void> {
|
|
1215
1210
|
return func.debuggerModel().functionDetailsPromise(func).then(didGetDetails);
|
|
1216
1211
|
|
|
1217
1212
|
function didGetDetails(response: SDK.DebuggerModel.FunctionDetails|null): void {
|
|
@@ -1230,16 +1225,14 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
|
|
|
1230
1225
|
}
|
|
1231
1226
|
const valueElement = document.createDocumentFragment();
|
|
1232
1227
|
// eslint-disable-next-line @devtools/no-lit-render-outside-of-view
|
|
1233
|
-
render(
|
|
1234
|
-
|
|
1235
|
-
valueElement);
|
|
1228
|
+
render(ObjectPropertiesSection.valueElementForFunctionDescription(func.description, includePreview, defaultName),
|
|
1229
|
+
valueElement);
|
|
1236
1230
|
element.appendChild(valueElement);
|
|
1237
1231
|
}
|
|
1238
1232
|
}
|
|
1239
1233
|
|
|
1240
|
-
static isDisplayableProperty(
|
|
1241
|
-
|
|
1242
|
-
parentProperty?: SDK.RemoteObject.RemoteObjectProperty): boolean {
|
|
1234
|
+
static isDisplayableProperty(property: SDK.RemoteObject.RemoteObjectProperty,
|
|
1235
|
+
parentProperty?: SDK.RemoteObject.RemoteObjectProperty): boolean {
|
|
1243
1236
|
if (!parentProperty?.synthetic) {
|
|
1244
1237
|
return true;
|
|
1245
1238
|
}
|
|
@@ -1272,9 +1265,9 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
|
|
|
1272
1265
|
i18nString(UIStrings.expandRecursively),
|
|
1273
1266
|
this.#objectTreeElement.expandRecursively.bind(this.#objectTreeElement, EXPANDABLE_MAX_DEPTH),
|
|
1274
1267
|
{jslogContext: 'expand-recursively'});
|
|
1275
|
-
contextMenu.viewSection().appendItem(
|
|
1276
|
-
|
|
1277
|
-
|
|
1268
|
+
contextMenu.viewSection().appendItem(i18nString(UIStrings.collapseChildren),
|
|
1269
|
+
this.#objectTreeElement.collapseChildren.bind(this.#objectTreeElement),
|
|
1270
|
+
{jslogContext: 'collapse-children'});
|
|
1278
1271
|
}
|
|
1279
1272
|
void contextMenu.show();
|
|
1280
1273
|
}
|
|
@@ -1321,8 +1314,9 @@ export function populateObjectTreeContextMenu(
|
|
|
1321
1314
|
|
|
1322
1315
|
if (object.object instanceof SDK.RemoteObject.LocalJSONObject) {
|
|
1323
1316
|
const {value} = object.object;
|
|
1324
|
-
const propertyValue =
|
|
1325
|
-
|
|
1317
|
+
const propertyValue = typeof value === 'object' ?
|
|
1318
|
+
Platform.StringUtilities.escapeUnicodeAsText(JSON.stringify(value, null, 2)) :
|
|
1319
|
+
value;
|
|
1326
1320
|
const copyValueHandler = (): void => {
|
|
1327
1321
|
Host.userMetrics.actionTaken(Host.UserMetrics.Action.NetworkPanelCopyValue);
|
|
1328
1322
|
Host.InspectorFrontendHost.InspectorFrontendHostInstance.copyText((propertyValue as string | undefined));
|
|
@@ -1444,8 +1438,8 @@ class RootElement extends UI.TreeOutline.TreeElement {
|
|
|
1444
1438
|
this.removeChildren();
|
|
1445
1439
|
const treeOutline = (this.treeOutline as ObjectPropertiesSection | null);
|
|
1446
1440
|
const skipProto = treeOutline ? Boolean(treeOutline.skipProtoInternal) : false;
|
|
1447
|
-
return await ObjectPropertyTreeElement.populate(
|
|
1448
|
-
|
|
1441
|
+
return await ObjectPropertyTreeElement.populate(this, this.object, skipProto, false, this.linkifier,
|
|
1442
|
+
this.emptyPlaceholder);
|
|
1449
1443
|
}
|
|
1450
1444
|
}
|
|
1451
1445
|
|
|
@@ -2010,8 +2004,9 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
2010
2004
|
contextMenu.appendApplicableItems(this.property.object);
|
|
2011
2005
|
if (this.property.parent?.object instanceof SDK.RemoteObject.LocalJSONObject) {
|
|
2012
2006
|
const {object: {value}} = this.property;
|
|
2013
|
-
const propertyValue =
|
|
2014
|
-
|
|
2007
|
+
const propertyValue = typeof value === 'object' ?
|
|
2008
|
+
Platform.StringUtilities.escapeUnicodeAsText(JSON.stringify(value, null, 2)) :
|
|
2009
|
+
value;
|
|
2015
2010
|
const copyValueHandler = (): void => {
|
|
2016
2011
|
Host.userMetrics.actionTaken(Host.UserMetrics.Action.NetworkPanelCopyValue);
|
|
2017
2012
|
Host.InspectorFrontendHost.InspectorFrontendHostInstance.copyText((propertyValue as string | undefined));
|
|
@@ -2381,7 +2376,7 @@ export const EXPANDABLE_TEXT_DEFAULT_VIEW: ExpandableTextView = (input, output,
|
|
|
2381
2376
|
data-text=${i18nString(UIStrings.copy)}
|
|
2382
2377
|
jslog=${VisualLogging.action('copy').track({click: true})}
|
|
2383
2378
|
></button>
|
|
2384
|
-
|
|
2379
|
+
</span>`,
|
|
2385
2380
|
// clang-format on
|
|
2386
2381
|
target);
|
|
2387
2382
|
};
|
|
@@ -313,7 +313,7 @@ export function renderNodeTitle(nodeTitle: string): LitTemplate|null {
|
|
|
313
313
|
match[3] && html`<span class=webkit-html-attribute-name>${match[3]}</span>`}`;
|
|
314
314
|
}
|
|
315
315
|
|
|
316
|
-
export function renderTrustedType(description: string, className: string): LitTemplate {
|
|
316
|
+
export function renderTrustedType(description: string, className: string|null): LitTemplate {
|
|
317
317
|
return html`${className} <span class=object-value-string title=${description}>"${
|
|
318
318
|
description.replace(/\n/g, '\u21B5')}"</span>`;
|
|
319
319
|
}
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
.object-value-regexp,
|
|
42
42
|
.object-value-symbol {
|
|
43
43
|
white-space: pre;
|
|
44
|
-
unicode-bidi:
|
|
44
|
+
unicode-bidi: isolate;
|
|
45
45
|
color: var(--sys-color-token-property-special);
|
|
46
46
|
}
|
|
47
47
|
|
|
@@ -90,6 +90,7 @@
|
|
|
90
90
|
.name {
|
|
91
91
|
color: var(--sys-color-token-tag);
|
|
92
92
|
flex-shrink: 0;
|
|
93
|
+
unicode-bidi: isolate;
|
|
93
94
|
}
|
|
94
95
|
|
|
95
96
|
.object-properties-preview .name {
|
|
@@ -1221,7 +1221,7 @@ devtools-toolbar {
|
|
|
1221
1221
|
|
|
1222
1222
|
.webkit-html-text-node {
|
|
1223
1223
|
color: var(--text-primary);
|
|
1224
|
-
unicode-bidi:
|
|
1224
|
+
unicode-bidi: isolate;
|
|
1225
1225
|
}
|
|
1226
1226
|
|
|
1227
1227
|
.webkit-html-entity-value {
|
|
@@ -1229,7 +1229,7 @@ devtools-toolbar {
|
|
|
1229
1229
|
/* See: crbug.com/1152736 for color variable migration. */
|
|
1230
1230
|
/* stylelint-disable-next-line plugin/use_theme_colors */
|
|
1231
1231
|
background-color: rgb(0 0 0 / 15%);
|
|
1232
|
-
unicode-bidi:
|
|
1232
|
+
unicode-bidi: isolate;
|
|
1233
1233
|
}
|
|
1234
1234
|
|
|
1235
1235
|
.webkit-html-doctype {
|
|
@@ -1242,13 +1242,13 @@ devtools-toolbar {
|
|
|
1242
1242
|
.webkit-html-attribute-name {
|
|
1243
1243
|
/* Keep this in sync with view-source.css (.webkit-html-attribute-name) */
|
|
1244
1244
|
color: var(--sys-color-token-attribute);
|
|
1245
|
-
unicode-bidi:
|
|
1245
|
+
unicode-bidi: isolate;
|
|
1246
1246
|
}
|
|
1247
1247
|
|
|
1248
1248
|
.webkit-html-attribute-value {
|
|
1249
1249
|
/* Keep this in sync with view-source.css (.webkit-html-attribute-value) */
|
|
1250
1250
|
color: var(--sys-color-token-attribute-value);
|
|
1251
|
-
unicode-bidi:
|
|
1251
|
+
unicode-bidi: isolate;
|
|
1252
1252
|
word-break: break-all;
|
|
1253
1253
|
}
|
|
1254
1254
|
|
package/front_end/ui/lit/lit.ts
CHANGED
|
@@ -15,6 +15,13 @@ export interface RenderOptions extends Lit.RenderOptions {
|
|
|
15
15
|
|
|
16
16
|
const renderOptions = new WeakMap<HTMLElement|DocumentFragment, RenderOptions|undefined>();
|
|
17
17
|
|
|
18
|
+
interface ListenerEntry {
|
|
19
|
+
listener: EventListenerOrEventListenerObject;
|
|
20
|
+
wrapper: EventListener;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const containerListeners = new WeakMap<HTMLElement|DocumentFragment, Map<string, ListenerEntry>>();
|
|
24
|
+
|
|
18
25
|
export function render(template: unknown, container: HTMLElement|DocumentFragment, options?: RenderOptions):
|
|
19
26
|
ReturnType<typeof Lit.render> {
|
|
20
27
|
const host = container instanceof ShadowRoot ? container.host : container;
|
|
@@ -62,22 +69,49 @@ export function render(template: unknown, container: HTMLElement|DocumentFragmen
|
|
|
62
69
|
}
|
|
63
70
|
}
|
|
64
71
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
if (newListeners?.[name] !== listener) {
|
|
70
|
-
host.removeEventListener(name, listener);
|
|
71
|
-
}
|
|
72
|
-
}
|
|
72
|
+
let listenersMap = containerListeners.get(container);
|
|
73
|
+
if (!listenersMap) {
|
|
74
|
+
listenersMap = new Map();
|
|
75
|
+
containerListeners.set(container, listenersMap);
|
|
73
76
|
}
|
|
77
|
+
|
|
78
|
+
const newListeners = options?.container?.listeners;
|
|
74
79
|
if (newListeners) {
|
|
75
80
|
for (const [name, listener] of Object.entries(newListeners)) {
|
|
76
|
-
|
|
77
|
-
|
|
81
|
+
const entry = listenersMap.get(name);
|
|
82
|
+
if (entry) {
|
|
83
|
+
entry.listener = listener;
|
|
84
|
+
} else {
|
|
85
|
+
let currentListener = listener;
|
|
86
|
+
const newEntry: ListenerEntry = {
|
|
87
|
+
get listener() {
|
|
88
|
+
return currentListener;
|
|
89
|
+
},
|
|
90
|
+
set listener(val: EventListenerOrEventListenerObject) {
|
|
91
|
+
currentListener = val;
|
|
92
|
+
},
|
|
93
|
+
wrapper: (event: Event) => {
|
|
94
|
+
if (typeof currentListener === 'function') {
|
|
95
|
+
return currentListener.call(host, event);
|
|
96
|
+
}
|
|
97
|
+
if (currentListener && 'handleEvent' in currentListener) {
|
|
98
|
+
return currentListener.handleEvent(event);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
listenersMap.set(name, newEntry);
|
|
103
|
+
host.addEventListener(name, newEntry.wrapper);
|
|
78
104
|
}
|
|
79
105
|
}
|
|
80
106
|
}
|
|
107
|
+
|
|
108
|
+
// Remove old listeners that are no longer present
|
|
109
|
+
for (const [name, entry] of listenersMap.entries()) {
|
|
110
|
+
if (!newListeners || !(name in newListeners)) {
|
|
111
|
+
host.removeEventListener(name, entry.wrapper);
|
|
112
|
+
listenersMap.delete(name);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
81
115
|
renderOptions.set(container, options);
|
|
82
116
|
return Lit.render(template, container, options);
|
|
83
117
|
}
|
|
@@ -1,11 +1,16 @@
|
|
|
1
|
-
// Copyright
|
|
1
|
+
// Copyright 2026 The Chromium Authors
|
|
2
2
|
// Use of this source code is governed by a BSD-style license that can be
|
|
3
3
|
// found in the LICENSE file.
|
|
4
4
|
|
|
5
|
+
import * as Platform from '../../core/platform/platform.js';
|
|
5
6
|
import * as Lit from '../../third_party/lit/lit.js';
|
|
6
7
|
|
|
7
8
|
const templates = new WeakMap<TemplateStringsArray, TemplateStringsArray>();
|
|
8
9
|
|
|
10
|
+
export function isLitDirective(value: unknown): value is {values: unknown[]} {
|
|
11
|
+
return Boolean(typeof value === 'object' && value && '_$litDirective$' in value && 'values' in value);
|
|
12
|
+
}
|
|
13
|
+
|
|
9
14
|
export function html(strings: TemplateStringsArray, ...values: unknown[]): Lit.TemplateResult {
|
|
10
15
|
let stripped = templates.get(strings);
|
|
11
16
|
if (!stripped) {
|
|
@@ -16,7 +21,23 @@ export function html(strings: TemplateStringsArray, ...values: unknown[]): Lit.T
|
|
|
16
21
|
}
|
|
17
22
|
}
|
|
18
23
|
templates.set(strings, stripped);
|
|
19
|
-
|
|
24
|
+
|
|
25
|
+
const escapeValue = (val: unknown): unknown => {
|
|
26
|
+
if (typeof val === 'string') {
|
|
27
|
+
return Platform.StringUtilities.safeEscapeUnicode(val);
|
|
28
|
+
}
|
|
29
|
+
if (Array.isArray(val)) {
|
|
30
|
+
return val.map(escapeValue);
|
|
31
|
+
}
|
|
32
|
+
if (isLitDirective(val)) {
|
|
33
|
+
val.values = val.values.map(escapeValue);
|
|
34
|
+
return val;
|
|
35
|
+
}
|
|
36
|
+
return val;
|
|
37
|
+
};
|
|
38
|
+
const escapedValues = values.map(escapeValue);
|
|
39
|
+
|
|
40
|
+
return Lit.html(stripped, ...escapedValues);
|
|
20
41
|
}
|
|
21
42
|
|
|
22
43
|
function strip(strings: TemplateStringsArray): TemplateStringsArray {
|
package/package.json
CHANGED