chrome-devtools-frontend 1.0.1574367 → 1.0.1575635
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/.stylelintrc.json +1 -1
- package/AUTHORS +1 -0
- package/docs/contributing/settings-experiments-features.md +5 -2
- package/front_end/core/common/Settings.ts +1 -1
- package/front_end/core/host/InspectorFrontendHostAPI.ts +7 -1
- package/front_end/core/host/InspectorFrontendHostStub.ts +10 -0
- package/front_end/core/host/UserMetrics.ts +15 -0
- package/front_end/core/root/Runtime.ts +119 -39
- package/front_end/core/sdk/CSSMatchedStyles.ts +27 -0
- package/front_end/entrypoints/main/MainImpl.ts +25 -7
- package/front_end/entrypoints/node_app/app/NodeConnectionsPanel.ts +3 -2
- package/front_end/generated/InspectorBackendCommands.ts +37 -0
- package/front_end/generated/protocol-mapping.d.ts +257 -0
- package/front_end/generated/protocol-proxy-api.d.ts +256 -0
- package/front_end/generated/protocol.ts +359 -0
- package/front_end/models/ai_assistance/AiConversation.ts +31 -10
- package/front_end/models/ai_assistance/AiHistoryStorage.ts +1 -0
- package/front_end/models/ai_assistance/agents/AiAgent.ts +29 -5
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.snapshot.txt +73 -0
- package/front_end/models/ai_assistance/agents/ContextSelectionAgent.ts +141 -0
- package/front_end/models/ai_assistance/agents/StylingAgent.snapshot.txt +3 -3
- package/front_end/models/ai_assistance/agents/StylingAgent.ts +5 -4
- package/front_end/models/ai_assistance/ai_assistance.ts +2 -0
- package/front_end/models/issues_manager/CorsIssue.ts +0 -3
- package/front_end/models/javascript_metadata/NativeFunctions.js +5 -0
- package/front_end/models/live-metrics/LiveMetrics.ts +31 -51
- package/front_end/models/stack_trace/StackTrace.ts +41 -0
- package/front_end/panels/ai_assistance/AiAssistancePanel.ts +72 -6
- package/front_end/panels/ai_assistance/ai_assistance-meta.ts +1 -0
- package/front_end/panels/ai_assistance/components/ChatInput.ts +24 -2
- package/front_end/panels/ai_assistance/components/ChatMessage.ts +6 -4
- package/front_end/panels/ai_assistance/components/ChatView.ts +5 -6
- package/front_end/panels/ai_assistance/components/chatView.css +10 -0
- package/front_end/panels/application/StorageView.ts +3 -3
- package/front_end/panels/application/preloading/components/preloadingDisabledInfobar.css +1 -1
- package/front_end/panels/common/AiCodeGenerationUpgradeDialog.ts +32 -16
- package/front_end/panels/common/aiCodeCompletionSummaryToolbar.css +1 -1
- package/front_end/panels/console/ConsoleContextSelector.ts +4 -3
- package/front_end/panels/console/ConsoleFormat.ts +31 -2
- package/front_end/panels/console/ConsoleInsightTeaser.ts +6 -1
- package/front_end/panels/elements/ElementsTreeElement.ts +46 -2
- package/front_end/panels/elements/ElementsTreeOutline.ts +1 -1
- package/front_end/panels/elements/StylePropertyTreeElement.ts +63 -0
- package/front_end/panels/elements/StylesSidebarPane.ts +17 -2
- package/front_end/panels/elements/stylePropertiesTreeOutline.css +4 -0
- package/front_end/panels/issues/AffectedMetadataAllowedSitesView.ts +3 -3
- package/front_end/panels/layer_viewer/Layers3DView.ts +2 -1
- package/front_end/panels/lighthouse/LighthouseStartView.ts +7 -6
- package/front_end/panels/linear_memory_inspector/LinearMemoryInspectorPane.ts +3 -2
- package/front_end/panels/network/RequestConditionsDrawer.ts +2 -3
- package/front_end/panels/network/SignedExchangeInfoView.ts +3 -4
- package/front_end/panels/network/components/HeaderSectionRow.css +1 -1
- package/front_end/panels/recorder/components/RecordingView.ts +2 -2
- package/front_end/panels/recorder/components/recordingView.css +5 -0
- package/front_end/panels/security/SecurityPanelSidebar.ts +10 -9
- package/front_end/panels/settings/AISettingsTab.ts +2 -1
- package/front_end/panels/settings/KeybindsSettingsTab.ts +3 -5
- package/front_end/panels/settings/SettingsScreen.ts +14 -9
- package/front_end/panels/settings/settings-meta.ts +1 -0
- package/front_end/panels/sources/CallStackSidebarPane.ts +10 -0
- package/front_end/panels/sources/DebuggerPlugin.ts +18 -12
- package/front_end/panels/sources/ScopeChainSidebarPane.ts +4 -3
- package/front_end/panels/sources/SourcesNavigator.ts +2 -2
- package/front_end/panels/sources/SourcesPanel.ts +6 -3
- package/front_end/panels/sources/TabbedEditorContainer.ts +2 -2
- package/front_end/panels/sources/sources-meta.ts +2 -1
- package/front_end/panels/timeline/TimelinePanel.ts +2 -1
- package/front_end/panels/timeline/TimelineUIUtils.ts +2 -2
- package/front_end/panels/timeline/components/DetailsView.ts +7 -7
- package/front_end/panels/timeline/components/insights/BaseInsightComponent.ts +2 -2
- package/front_end/panels/timeline/overlays/components/EntryLabelOverlay.ts +4 -4
- package/front_end/panels/whats_new/ReleaseNoteText.ts +11 -11
- package/front_end/panels/whats_new/releaseNoteView.css +1 -1
- package/front_end/panels/whats_new/resources/WNDT.md +6 -6
- 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/TargetManager.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/TargetManager.js +30 -25
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/TargetManager.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/injected/injected.d.ts +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/util/Mutex.d.ts +2 -2
- 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 +30 -21
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/TargetManager.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/TargetManager.js +31 -26
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/TargetManager.js.map +1 -1
- 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 +3 -3
- package/front_end/third_party/puppeteer/package/src/cdp/TargetManager.ts +45 -44
- package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
- package/front_end/ui/components/buttons/Button.ts +2 -2
- package/front_end/ui/components/panel_feedback/PreviewToggle.ts +1 -1
- package/front_end/ui/components/panel_feedback/panelFeedback.css +1 -1
- package/front_end/ui/kit/link/Link.ts +31 -0
- package/front_end/ui/legacy/LinkContextMenuProvider.ts +3 -5
- package/front_end/ui/legacy/components/object_ui/ObjectPopoverHelper.ts +2 -2
- package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +336 -250
- package/front_end/ui/legacy/inspectorCommon.css +0 -1
- package/front_end/ui/legacy/legacy.ts +0 -4
- package/front_end/ui/visual_logging/KnownContextValues.ts +4 -0
- package/front_end/ui/visual_logging/LoggingDriver.ts +10 -6
- package/mcp/HostBindings.ts +6 -0
- package/package.json +1 -1
- package/front_end/ui/legacy/XElement.ts +0 -41
- package/front_end/ui/legacy/XLink.ts +0 -128
|
@@ -145,26 +145,62 @@ interface NodeChildren {
|
|
|
145
145
|
properties?: ObjectTreeNode[];
|
|
146
146
|
internalProperties?: ObjectTreeNode[];
|
|
147
147
|
arrayRanges?: ArrayGroupTreeNode[];
|
|
148
|
+
accessors?: ObjectTreeNode[];
|
|
148
149
|
}
|
|
149
150
|
|
|
150
|
-
abstract class ObjectTreeNodeBase {
|
|
151
|
+
abstract class ObjectTreeNodeBase extends Common.ObjectWrapper.ObjectWrapper<ObjectTreeNodeBase.EventTypes> {
|
|
151
152
|
#children?: NodeChildren;
|
|
152
153
|
protected extraProperties: ObjectTreeNode[] = [];
|
|
154
|
+
expanded = false;
|
|
153
155
|
constructor(
|
|
154
156
|
readonly parent?: ObjectTreeNodeBase,
|
|
155
157
|
readonly propertiesMode: ObjectPropertiesMode = ObjectPropertiesMode.OWN_AND_INTERNAL_AND_INHERITED) {
|
|
158
|
+
super();
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// Performs a pre-order tree traversal over the populated children. If any children need to be populated, callers must
|
|
162
|
+
// do that while walking (pre-order visitation enables that).
|
|
163
|
+
* #walk(maxDepth = -1): Generator<ObjectTreeNodeBase> {
|
|
164
|
+
function* walkChildren(children: ObjectTreeNodeBase[]|undefined): Generator<ObjectTreeNodeBase> {
|
|
165
|
+
if (children) {
|
|
166
|
+
for (const child of children) {
|
|
167
|
+
yield* child.#walk(Math.max(-1, maxDepth - 1));
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
yield this;
|
|
172
|
+
if (maxDepth !== 0) {
|
|
173
|
+
yield* walkChildren(this.#children?.properties);
|
|
174
|
+
yield* walkChildren(this.#children?.arrayRanges);
|
|
175
|
+
yield* walkChildren(this.#children?.internalProperties);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
async expandRecursively(maxDepth: number): Promise<void> {
|
|
180
|
+
for (const node of this.#walk(maxDepth)) {
|
|
181
|
+
await node.populateChildrenIfNeeded();
|
|
182
|
+
node.expanded = true;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
collapseRecursively(): void {
|
|
187
|
+
for (const node of this.#walk()) {
|
|
188
|
+
node.expanded = false;
|
|
189
|
+
}
|
|
156
190
|
}
|
|
157
191
|
|
|
158
192
|
abstract get object(): SDK.RemoteObject.RemoteObject|undefined;
|
|
159
193
|
|
|
160
194
|
removeChildren(): void {
|
|
161
195
|
this.#children = undefined;
|
|
196
|
+
this.dispatchEventToListeners(ObjectTreeNodeBase.Events.CHILDREN_CHANGED);
|
|
162
197
|
}
|
|
163
198
|
|
|
164
199
|
removeChild(child: ObjectTreeNodeBase): void {
|
|
165
200
|
remove(this.#children?.arrayRanges, child);
|
|
166
201
|
remove(this.#children?.internalProperties, child);
|
|
167
202
|
remove(this.#children?.properties, child);
|
|
203
|
+
this.dispatchEventToListeners(ObjectTreeNodeBase.Events.CHILDREN_CHANGED);
|
|
168
204
|
|
|
169
205
|
function remove<T>(array: T[]|undefined, element: T): void {
|
|
170
206
|
if (!array) {
|
|
@@ -181,14 +217,14 @@ abstract class ObjectTreeNodeBase {
|
|
|
181
217
|
return this;
|
|
182
218
|
}
|
|
183
219
|
|
|
184
|
-
|
|
185
|
-
if (!this.#children) {
|
|
186
|
-
this.#children = await this.populateChildren();
|
|
187
|
-
}
|
|
220
|
+
get children(): NodeChildren|undefined {
|
|
188
221
|
return this.#children;
|
|
189
222
|
}
|
|
190
223
|
|
|
191
|
-
|
|
224
|
+
async populateChildrenIfNeeded(): Promise<NodeChildren> {
|
|
225
|
+
if (this.#children) {
|
|
226
|
+
return this.#children;
|
|
227
|
+
}
|
|
192
228
|
const object = this.object;
|
|
193
229
|
if (!object) {
|
|
194
230
|
return {};
|
|
@@ -230,10 +266,12 @@ abstract class ObjectTreeNodeBase {
|
|
|
230
266
|
|
|
231
267
|
const properties = objectProperties?.map(p => new ObjectTreeNode(p, undefined, effectiveParent, undefined));
|
|
232
268
|
properties?.push(...this.extraProperties);
|
|
269
|
+
properties?.sort(ObjectPropertiesSection.compareProperties);
|
|
270
|
+
const accessors = properties && ObjectTreeNodeBase.getGettersAndSetters(properties);
|
|
233
271
|
|
|
234
272
|
const internalProperties =
|
|
235
273
|
objectInternalProperties?.map(p => new ObjectTreeNode(p, undefined, effectiveParent, undefined));
|
|
236
|
-
return {properties, internalProperties};
|
|
274
|
+
return {properties, internalProperties, accessors};
|
|
237
275
|
}
|
|
238
276
|
|
|
239
277
|
get hasChildren(): boolean {
|
|
@@ -252,6 +290,36 @@ abstract class ObjectTreeNodeBase {
|
|
|
252
290
|
addExtraProperties(...properties: SDK.RemoteObject.RemoteObjectProperty[]): void {
|
|
253
291
|
this.extraProperties.push(...properties.map(p => new ObjectTreeNode(p, undefined, this, undefined)));
|
|
254
292
|
}
|
|
293
|
+
|
|
294
|
+
static getGettersAndSetters(properties: ObjectTreeNode[]): ObjectTreeNode[] {
|
|
295
|
+
const gettersAndSetters = [];
|
|
296
|
+
for (const property of properties) {
|
|
297
|
+
if (property.property.isOwn) {
|
|
298
|
+
if (property.property.getter) {
|
|
299
|
+
const getterProperty = new SDK.RemoteObject.RemoteObjectProperty(
|
|
300
|
+
'get ' + property.property.name, property.property.getter, false);
|
|
301
|
+
gettersAndSetters.push(new ObjectTreeNode(getterProperty, property.propertiesMode, property.parent));
|
|
302
|
+
}
|
|
303
|
+
if (property.property.setter) {
|
|
304
|
+
const setterProperty = new SDK.RemoteObject.RemoteObjectProperty(
|
|
305
|
+
'set ' + property.property.name, property.property.setter, false);
|
|
306
|
+
gettersAndSetters.push(new ObjectTreeNode(setterProperty, property.propertiesMode, property.parent));
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return gettersAndSetters;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
namespace ObjectTreeNodeBase {
|
|
315
|
+
export const enum Events {
|
|
316
|
+
VALUE_CHANGED = 'value-changed',
|
|
317
|
+
CHILDREN_CHANGED = 'children-changed',
|
|
318
|
+
}
|
|
319
|
+
export interface EventTypes {
|
|
320
|
+
[Events.VALUE_CHANGED]: void;
|
|
321
|
+
[Events.CHILDREN_CHANGED]: void;
|
|
322
|
+
}
|
|
255
323
|
}
|
|
256
324
|
|
|
257
325
|
export class ObjectTree extends ObjectTreeNodeBase {
|
|
@@ -280,7 +348,10 @@ class ArrayGroupTreeNode extends ObjectTreeNodeBase {
|
|
|
280
348
|
this.#range = range;
|
|
281
349
|
}
|
|
282
350
|
|
|
283
|
-
|
|
351
|
+
override async populateChildrenIfNeeded(): Promise<NodeChildren> {
|
|
352
|
+
if (this.children) {
|
|
353
|
+
return this.children;
|
|
354
|
+
}
|
|
284
355
|
if (this.#range.count > ArrayGroupingTreeElement.bucketThreshold) {
|
|
285
356
|
const ranges = await arrayRangeGroups(this.object, this.#range.fromIndex, this.#range.toIndex);
|
|
286
357
|
const arrayRanges = ranges?.ranges.map(
|
|
@@ -303,7 +374,8 @@ class ArrayGroupTreeNode extends ObjectTreeNodeBase {
|
|
|
303
374
|
const properties = allProperties.properties?.map(p => new ObjectTreeNode(p, this.propertiesMode, this, undefined));
|
|
304
375
|
properties?.push(...this.extraProperties);
|
|
305
376
|
properties?.sort(ObjectPropertiesSection.compareProperties);
|
|
306
|
-
|
|
377
|
+
const accessors = properties && ObjectTreeNodeBase.getGettersAndSetters(properties);
|
|
378
|
+
return {properties, accessors};
|
|
307
379
|
}
|
|
308
380
|
|
|
309
381
|
get singular(): boolean {
|
|
@@ -365,6 +437,57 @@ export class ObjectTreeNode extends ObjectTreeNodeBase {
|
|
|
365
437
|
override selfOrParentIfInternal(): ObjectTreeNodeBase {
|
|
366
438
|
return this.name === '[[Prototype]]' ? (this.parent ?? this) : this;
|
|
367
439
|
}
|
|
440
|
+
|
|
441
|
+
async setValue(expression: string): Promise<void> {
|
|
442
|
+
const property = SDK.RemoteObject.RemoteObject.toCallArgument(this.property.symbol || this.name);
|
|
443
|
+
expression = JavaScriptREPL.wrapObjectLiteral(expression.trim());
|
|
444
|
+
|
|
445
|
+
if (this.property.synthetic) {
|
|
446
|
+
let invalidate = false;
|
|
447
|
+
if (expression) {
|
|
448
|
+
invalidate = await this.property.setSyntheticValue(expression);
|
|
449
|
+
}
|
|
450
|
+
if (invalidate) {
|
|
451
|
+
this.parent?.removeChildren();
|
|
452
|
+
} else {
|
|
453
|
+
this.dispatchEventToListeners(ObjectTreeNodeBase.Events.VALUE_CHANGED);
|
|
454
|
+
}
|
|
455
|
+
return;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
const parentObject = this.parent?.object as SDK.RemoteObject.RemoteObject;
|
|
459
|
+
const errorPromise =
|
|
460
|
+
expression ? parentObject.setPropertyValue(property, expression) : parentObject.deleteProperty(property);
|
|
461
|
+
const error = await errorPromise;
|
|
462
|
+
if (error) {
|
|
463
|
+
this.dispatchEventToListeners(ObjectTreeNodeBase.Events.VALUE_CHANGED);
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
if (!expression) {
|
|
468
|
+
this.parent?.removeChild(this);
|
|
469
|
+
} else {
|
|
470
|
+
this.parent?.removeChildren();
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
async invokeGetter(getter: SDK.RemoteObject.RemoteObject): Promise<void> {
|
|
475
|
+
const invokeGetter = `
|
|
476
|
+
function invokeGetter(getter) {
|
|
477
|
+
return Reflect.apply(getter, this, []);
|
|
478
|
+
}`;
|
|
479
|
+
// Also passing a string instead of a Function to avoid coverage implementation messing with it.
|
|
480
|
+
const result = await this.parent
|
|
481
|
+
?.object
|
|
482
|
+
// @ts-expect-error No way to teach TypeScript to preserve the Function-ness of `getter`.
|
|
483
|
+
?.callFunction(invokeGetter, [SDK.RemoteObject.RemoteObject.toCallArgument(getter)]);
|
|
484
|
+
if (!result?.object) {
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
this.property.value = result.object;
|
|
488
|
+
this.property.wasThrown = result.wasThrown || false;
|
|
489
|
+
this.dispatchEventToListeners(ObjectTreeNodeBase.Events.VALUE_CHANGED);
|
|
490
|
+
}
|
|
368
491
|
}
|
|
369
492
|
|
|
370
493
|
export const getObjectPropertiesSectionFrom = (element: Element): ObjectPropertiesSection|undefined => {
|
|
@@ -668,8 +791,7 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
|
|
|
668
791
|
}
|
|
669
792
|
if (description.length > maxRenderableStringLength) {
|
|
670
793
|
return html`<span class="value object-value-${subtype || type}" title=${description}><devtools-widget
|
|
671
|
-
|
|
672
|
-
widgetConfig(ExpandableTextPropertyValue, {text: description})}></devtools-widget></span>`;
|
|
794
|
+
.widgetConfig=${widgetConfig(ExpandableTextPropertyValue, {text: description})}></devtools-widget></span>`;
|
|
673
795
|
}
|
|
674
796
|
const hasPreview = value.preview && showPreview;
|
|
675
797
|
return html`<span class="value object-value-${subtype || type}" title=${description}>${
|
|
@@ -810,6 +932,7 @@ export class RootElement extends UI.TreeOutline.TreeElement {
|
|
|
810
932
|
super(contentElement);
|
|
811
933
|
|
|
812
934
|
this.object = object;
|
|
935
|
+
this.object.addEventListener(ObjectTreeNodeBase.Events.CHILDREN_CHANGED, this.onpopulate, this);
|
|
813
936
|
this.linkifier = linkifier;
|
|
814
937
|
this.emptyPlaceholder = emptyPlaceholder;
|
|
815
938
|
|
|
@@ -820,11 +943,6 @@ export class RootElement extends UI.TreeOutline.TreeElement {
|
|
|
820
943
|
this.listItemElement.addEventListener('contextmenu', this.onContextMenu.bind(this), false);
|
|
821
944
|
}
|
|
822
945
|
|
|
823
|
-
override invalidateChildren(): void {
|
|
824
|
-
super.invalidateChildren();
|
|
825
|
-
this.object.removeChildren();
|
|
826
|
-
}
|
|
827
|
-
|
|
828
946
|
override onexpand(): void {
|
|
829
947
|
if (this.treeOutline) {
|
|
830
948
|
this.treeOutline.element.classList.add('expanded');
|
|
@@ -865,6 +983,7 @@ export class RootElement extends UI.TreeOutline.TreeElement {
|
|
|
865
983
|
}
|
|
866
984
|
|
|
867
985
|
override async onpopulate(): Promise<void> {
|
|
986
|
+
this.removeChildren();
|
|
868
987
|
const treeOutline = (this.treeOutline as ObjectPropertiesSection | null);
|
|
869
988
|
const skipProto = treeOutline ? Boolean(treeOutline.skipProtoInternal) : false;
|
|
870
989
|
return await ObjectPropertyTreeElement.populate(
|
|
@@ -878,7 +997,7 @@ export class RootElement extends UI.TreeOutline.TreeElement {
|
|
|
878
997
|
**/
|
|
879
998
|
export const InitialVisibleChildrenLimit = 200;
|
|
880
999
|
|
|
881
|
-
export interface
|
|
1000
|
+
export interface ObjectPropertyViewInput {
|
|
882
1001
|
startEditing(): unknown;
|
|
883
1002
|
invokeGetter(getter: SDK.RemoteObject.RemoteObject): unknown;
|
|
884
1003
|
onAutoComplete(expression: string, filter: string, force: boolean): unknown;
|
|
@@ -890,12 +1009,13 @@ export interface TreeElementViewInput {
|
|
|
890
1009
|
editingCommitted(detail: string): unknown;
|
|
891
1010
|
node: ObjectTreeNode;
|
|
892
1011
|
}
|
|
893
|
-
interface
|
|
1012
|
+
interface ObjectPropertyViewOutput {
|
|
894
1013
|
valueElement: Element|undefined;
|
|
895
1014
|
nameElement: Element|undefined;
|
|
896
1015
|
}
|
|
897
|
-
type
|
|
898
|
-
|
|
1016
|
+
type ObjectPropertyView = (input: ObjectPropertyViewInput, output: ObjectPropertyViewOutput, target: HTMLElement) =>
|
|
1017
|
+
void;
|
|
1018
|
+
export const OBJECT_PROPERTY_DEFAULT_VIEW: ObjectPropertyView = (input, output, target) => {
|
|
899
1019
|
const {property} = input.node;
|
|
900
1020
|
const isInternalEntries = property.synthetic && input.node.name === '[[Entries]]';
|
|
901
1021
|
const completionsId = `completions-${input.node.parent?.object?.objectId?.replaceAll('.', '-')}-${input.node.name}`;
|
|
@@ -950,7 +1070,10 @@ export const TREE_ELEMENT_DEFAULT_VIEW: TreeElementView = (input, output, target
|
|
|
950
1070
|
i18nString(UIStrings.valueUnavailable)}</span>`;
|
|
951
1071
|
};
|
|
952
1072
|
|
|
953
|
-
const
|
|
1073
|
+
const onActivate = (event: MouseEvent|KeyboardEvent): void => {
|
|
1074
|
+
if (event instanceof KeyboardEvent && !Platform.KeyboardUtilities.isEnterOrSpaceKey(event)) {
|
|
1075
|
+
return;
|
|
1076
|
+
}
|
|
954
1077
|
event.consume(true);
|
|
955
1078
|
if (property.value && !property.value.customPreview() && (property.writable || property.setter)) {
|
|
956
1079
|
input.startEditing();
|
|
@@ -970,7 +1093,8 @@ export const TREE_ELEMENT_DEFAULT_VIEW: TreeElementView = (input, output, target
|
|
|
970
1093
|
@commit=${(e: UI.TextPrompt.TextPromptElement.CommitEvent) => input.editingCommitted(e.detail)}
|
|
971
1094
|
@cancel=${() => input.editingEnded()}
|
|
972
1095
|
@beforeautocomplete=${onAutoComplete}
|
|
973
|
-
@dblclick=${
|
|
1096
|
+
@dblclick=${onActivate}
|
|
1097
|
+
@keydown=${onActivate}
|
|
974
1098
|
completions=${completionsId}
|
|
975
1099
|
placeholder=${i18nString(UIStrings.stringIsTooLargeToEdit)}
|
|
976
1100
|
?editing=${input.editing}>
|
|
@@ -990,26 +1114,166 @@ export const TREE_ELEMENT_DEFAULT_VIEW: TreeElementView = (input, output, target
|
|
|
990
1114
|
target);
|
|
991
1115
|
// clang-format on
|
|
992
1116
|
};
|
|
1117
|
+
|
|
1118
|
+
export class ObjectPropertyWidget extends UI.Widget.Widget {
|
|
1119
|
+
#highlightChanges: Highlighting.HighlightChange[] = [];
|
|
1120
|
+
#property?: ObjectTreeNode;
|
|
1121
|
+
#nameElement?: Element;
|
|
1122
|
+
#valueElement?: Element;
|
|
1123
|
+
#completions: string[] = [];
|
|
1124
|
+
#editing = false;
|
|
1125
|
+
readonly #view: ObjectPropertyView;
|
|
1126
|
+
#expanded = false;
|
|
1127
|
+
#linkifier: Components.Linkifier.Linkifier|undefined;
|
|
1128
|
+
|
|
1129
|
+
constructor(target?: HTMLElement, view = OBJECT_PROPERTY_DEFAULT_VIEW) {
|
|
1130
|
+
super(target);
|
|
1131
|
+
this.#view = view;
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
get property(): ObjectTreeNode|undefined {
|
|
1135
|
+
return this.#property;
|
|
1136
|
+
}
|
|
1137
|
+
set property(property: ObjectTreeNode) {
|
|
1138
|
+
if (this.#property) {
|
|
1139
|
+
this.#property.removeEventListener(ObjectTreeNodeBase.Events.VALUE_CHANGED, this.requestUpdate, this);
|
|
1140
|
+
this.#property.removeEventListener(ObjectTreeNodeBase.Events.CHILDREN_CHANGED, this.requestUpdate, this);
|
|
1141
|
+
}
|
|
1142
|
+
this.#property = property;
|
|
1143
|
+
this.#property.addEventListener(ObjectTreeNodeBase.Events.VALUE_CHANGED, this.requestUpdate, this);
|
|
1144
|
+
this.#property.addEventListener(ObjectTreeNodeBase.Events.CHILDREN_CHANGED, this.requestUpdate, this);
|
|
1145
|
+
this.requestUpdate();
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
get expanded(): boolean {
|
|
1149
|
+
return this.#expanded;
|
|
1150
|
+
}
|
|
1151
|
+
set expanded(expanded: boolean) {
|
|
1152
|
+
this.#expanded = expanded;
|
|
1153
|
+
this.requestUpdate();
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
get linkifier(): Components.Linkifier.Linkifier|undefined {
|
|
1157
|
+
return this.#linkifier;
|
|
1158
|
+
}
|
|
1159
|
+
set linkifier(linkifier: Components.Linkifier.Linkifier|undefined) {
|
|
1160
|
+
this.#linkifier = linkifier;
|
|
1161
|
+
this.requestUpdate();
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
override performUpdate(): void {
|
|
1165
|
+
if (!this.#property) {
|
|
1166
|
+
return;
|
|
1167
|
+
}
|
|
1168
|
+
const input: ObjectPropertyViewInput = {
|
|
1169
|
+
expanded: this.#expanded,
|
|
1170
|
+
editing: this.#editing,
|
|
1171
|
+
editingEnded: this.#editingEnded.bind(this),
|
|
1172
|
+
editingCommitted: this.#editingCommitted.bind(this),
|
|
1173
|
+
node: this.#property,
|
|
1174
|
+
linkifier: this.#linkifier,
|
|
1175
|
+
completions: this.#editing ? this.#completions : [],
|
|
1176
|
+
onAutoComplete: this.#updateCompletions.bind(this),
|
|
1177
|
+
invokeGetter: this.#invokeGetter.bind(this),
|
|
1178
|
+
startEditing: this.startEditing.bind(this),
|
|
1179
|
+
};
|
|
1180
|
+
const that = this;
|
|
1181
|
+
const output: ObjectPropertyViewOutput = {
|
|
1182
|
+
set nameElement(e: Element|undefined) {
|
|
1183
|
+
that.#nameElement = e;
|
|
1184
|
+
},
|
|
1185
|
+
set valueElement(e: Element|undefined) {
|
|
1186
|
+
that.#valueElement = e;
|
|
1187
|
+
},
|
|
1188
|
+
};
|
|
1189
|
+
this.#view(input, output, this.element);
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
setSearchRegex(regex: RegExp, additionalCssClassName?: string): boolean {
|
|
1193
|
+
let cssClasses = Highlighting.highlightedSearchResultClassName;
|
|
1194
|
+
if (additionalCssClassName) {
|
|
1195
|
+
cssClasses += ' ' + additionalCssClassName;
|
|
1196
|
+
}
|
|
1197
|
+
this.revertHighlightChanges();
|
|
1198
|
+
|
|
1199
|
+
if (this.#nameElement) {
|
|
1200
|
+
this.#applySearch(regex, this.#nameElement, cssClasses);
|
|
1201
|
+
}
|
|
1202
|
+
if (this.property?.object) {
|
|
1203
|
+
const valueType = this.property?.object.type;
|
|
1204
|
+
if (valueType !== 'object' && this.#valueElement) {
|
|
1205
|
+
this.#applySearch(regex, this.#valueElement, cssClasses);
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
return Boolean(this.#highlightChanges.length);
|
|
1210
|
+
}
|
|
1211
|
+
|
|
1212
|
+
#applySearch(regex: RegExp, element: Element, cssClassName: string): void {
|
|
1213
|
+
const ranges = [];
|
|
1214
|
+
const content = element.textContent || '';
|
|
1215
|
+
regex.lastIndex = 0;
|
|
1216
|
+
let match = regex.exec(content);
|
|
1217
|
+
while (match) {
|
|
1218
|
+
ranges.push(new TextUtils.TextRange.SourceRange(match.index, match[0].length));
|
|
1219
|
+
match = regex.exec(content);
|
|
1220
|
+
}
|
|
1221
|
+
if (ranges.length) {
|
|
1222
|
+
Highlighting.highlightRangesWithStyleClass(element, ranges, cssClassName, this.#highlightChanges);
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
|
|
1226
|
+
revertHighlightChanges(): void {
|
|
1227
|
+
Highlighting.revertDomChanges(this.#highlightChanges);
|
|
1228
|
+
this.#highlightChanges = [];
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
async #updateCompletions(expression: string, filter: string, force: boolean): Promise<void> {
|
|
1232
|
+
const suggestions = await TextEditor.JavaScript.completeInContext(expression, filter, force);
|
|
1233
|
+
this.#completions = suggestions.map(v => v.text);
|
|
1234
|
+
this.requestUpdate();
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
get editing(): boolean {
|
|
1238
|
+
return this.#editing;
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
startEditing(): void {
|
|
1242
|
+
this.#editing = true;
|
|
1243
|
+
this.requestUpdate();
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
#editingEnded(): void {
|
|
1247
|
+
this.#completions = [];
|
|
1248
|
+
this.#editing = false;
|
|
1249
|
+
this.requestUpdate();
|
|
1250
|
+
}
|
|
1251
|
+
|
|
1252
|
+
async #editingCommitted(newContent: string): Promise<void> {
|
|
1253
|
+
this.#editingEnded();
|
|
1254
|
+
await this.#property?.setValue(newContent);
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
#invokeGetter(getter: SDK.RemoteObject.RemoteObject): void {
|
|
1258
|
+
void this.#property?.invokeGetter(getter);
|
|
1259
|
+
}
|
|
1260
|
+
}
|
|
1261
|
+
|
|
993
1262
|
export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
994
1263
|
property: ObjectTreeNode;
|
|
995
1264
|
override toggleOnClick: boolean;
|
|
996
|
-
private highlightChanges: Highlighting.HighlightChange[];
|
|
997
1265
|
private linkifier: Components.Linkifier.Linkifier|undefined;
|
|
998
1266
|
private readonly maxNumPropertiesToShow: number;
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
readonly #view: TreeElementView;
|
|
1002
|
-
#completions: string[] = [];
|
|
1003
|
-
#nameElement: Element|undefined;
|
|
1004
|
-
#valueElement: Element|undefined;
|
|
1005
|
-
constructor(property: ObjectTreeNode, linkifier?: Components.Linkifier.Linkifier, view = TREE_ELEMENT_DEFAULT_VIEW) {
|
|
1267
|
+
readonly #widget: ObjectPropertyWidget;
|
|
1268
|
+
constructor(property: ObjectTreeNode, linkifier?: Components.Linkifier.Linkifier) {
|
|
1006
1269
|
// Pass an empty title, the title gets made later in onattach.
|
|
1007
1270
|
super();
|
|
1008
1271
|
|
|
1009
|
-
this.#
|
|
1272
|
+
this.#widget = new ObjectPropertyWidget();
|
|
1010
1273
|
this.property = property;
|
|
1274
|
+
this.property.addEventListener(ObjectTreeNodeBase.Events.VALUE_CHANGED, this.#updateValue, this);
|
|
1275
|
+
this.property.addEventListener(ObjectTreeNodeBase.Events.CHILDREN_CHANGED, this.#updateChildren, this);
|
|
1011
1276
|
this.toggleOnClick = true;
|
|
1012
|
-
this.highlightChanges = [];
|
|
1013
1277
|
this.linkifier = linkifier;
|
|
1014
1278
|
this.maxNumPropertiesToShow = InitialVisibleChildrenLimit;
|
|
1015
1279
|
this.listItemElement.addEventListener('contextmenu', this.contextMenuFired.bind(this), false);
|
|
@@ -1025,7 +1289,7 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
1025
1289
|
linkifier?: Components.Linkifier.Linkifier,
|
|
1026
1290
|
emptyPlaceholder?: string|null,
|
|
1027
1291
|
): Promise<void> {
|
|
1028
|
-
const properties = await value.
|
|
1292
|
+
const properties = await value.populateChildrenIfNeeded();
|
|
1029
1293
|
if (properties.arrayRanges) {
|
|
1030
1294
|
await ArrayGroupingTreeElement.populate(treeElement, properties, linkifier);
|
|
1031
1295
|
} else {
|
|
@@ -1035,8 +1299,8 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
1035
1299
|
}
|
|
1036
1300
|
|
|
1037
1301
|
static populateWithProperties(
|
|
1038
|
-
treeNode: UI.TreeOutline.TreeElement, {properties, internalProperties}: NodeChildren,
|
|
1039
|
-
skipGettersAndSetters: boolean, linkifier?: Components.Linkifier.Linkifier,
|
|
1302
|
+
treeNode: UI.TreeOutline.TreeElement, {properties, internalProperties, accessors}: NodeChildren,
|
|
1303
|
+
skipProto: boolean, skipGettersAndSetters: boolean, linkifier?: Components.Linkifier.Linkifier,
|
|
1040
1304
|
emptyPlaceholder?: string|null): void {
|
|
1041
1305
|
properties?.sort(ObjectPropertiesSection.compareProperties);
|
|
1042
1306
|
|
|
@@ -1048,27 +1312,12 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
1048
1312
|
treeNode.appendChild(treeElement);
|
|
1049
1313
|
}
|
|
1050
1314
|
|
|
1051
|
-
const tailProperties = [];
|
|
1052
1315
|
for (const property of properties ?? []) {
|
|
1053
1316
|
if (treeNode instanceof ObjectPropertyTreeElement &&
|
|
1054
1317
|
!ObjectPropertiesSection.isDisplayableProperty(property.property, treeNode.property?.property)) {
|
|
1055
1318
|
continue;
|
|
1056
1319
|
}
|
|
1057
1320
|
|
|
1058
|
-
// FIXME move into node
|
|
1059
|
-
if (property.property.isOwn && !skipGettersAndSetters) {
|
|
1060
|
-
if (property.property.getter) {
|
|
1061
|
-
const getterProperty = new SDK.RemoteObject.RemoteObjectProperty(
|
|
1062
|
-
'get ' + property.property.name, property.property.getter, false);
|
|
1063
|
-
tailProperties.push(new ObjectTreeNode(getterProperty, property.propertiesMode, property.parent));
|
|
1064
|
-
}
|
|
1065
|
-
if (property.property.setter) {
|
|
1066
|
-
const setterProperty = new SDK.RemoteObject.RemoteObjectProperty(
|
|
1067
|
-
'set ' + property.property.name, property.property.setter, false);
|
|
1068
|
-
tailProperties.push(new ObjectTreeNode(setterProperty, property.propertiesMode, property.parent));
|
|
1069
|
-
}
|
|
1070
|
-
}
|
|
1071
|
-
|
|
1072
1321
|
const canShowProperty = property.property.getter || !property.property.isAccessorProperty();
|
|
1073
1322
|
if (canShowProperty) {
|
|
1074
1323
|
const element = new ObjectPropertyTreeElement(property, linkifier);
|
|
@@ -1081,8 +1330,9 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
1081
1330
|
treeNode.appendChild(element);
|
|
1082
1331
|
}
|
|
1083
1332
|
}
|
|
1084
|
-
|
|
1085
|
-
|
|
1333
|
+
|
|
1334
|
+
for (const accessor of accessors ?? []) {
|
|
1335
|
+
treeNode.appendChild(new ObjectPropertyTreeElement(accessor, linkifier));
|
|
1086
1336
|
}
|
|
1087
1337
|
|
|
1088
1338
|
for (const property of internalProperties ?? []) {
|
|
@@ -1099,6 +1349,28 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
1099
1349
|
ObjectPropertyTreeElement.appendEmptyPlaceholderIfNeeded(treeNode, emptyPlaceholder);
|
|
1100
1350
|
}
|
|
1101
1351
|
|
|
1352
|
+
revertHighlightChanges(): void {
|
|
1353
|
+
this.#widget.revertHighlightChanges();
|
|
1354
|
+
}
|
|
1355
|
+
setSearchRegex(regex: RegExp, additionalCssClassName?: string): boolean {
|
|
1356
|
+
return this.#widget.setSearchRegex(regex, additionalCssClassName);
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1359
|
+
// This is called by layout tests
|
|
1360
|
+
startEditing(): void {
|
|
1361
|
+
this.#widget.startEditing();
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
// This is called by layout tests
|
|
1365
|
+
get editing(): boolean {
|
|
1366
|
+
return this.#widget.editing;
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
// This is called by layout tests
|
|
1370
|
+
async applyExpression(expression: string): Promise<void> {
|
|
1371
|
+
await this.property.setValue(expression);
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1102
1374
|
private static appendEmptyPlaceholderIfNeeded(treeNode: UI.TreeOutline.TreeElement, emptyPlaceholder?: string|null):
|
|
1103
1375
|
void {
|
|
1104
1376
|
if (treeNode.childCount()) {
|
|
@@ -1111,44 +1383,6 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
1111
1383
|
treeNode.appendChild(infoElement);
|
|
1112
1384
|
}
|
|
1113
1385
|
|
|
1114
|
-
get nameElement(): Element|undefined {
|
|
1115
|
-
return this.#nameElement;
|
|
1116
|
-
}
|
|
1117
|
-
|
|
1118
|
-
setSearchRegex(regex: RegExp, additionalCssClassName?: string): boolean {
|
|
1119
|
-
let cssClasses = Highlighting.highlightedSearchResultClassName;
|
|
1120
|
-
if (additionalCssClassName) {
|
|
1121
|
-
cssClasses += ' ' + additionalCssClassName;
|
|
1122
|
-
}
|
|
1123
|
-
this.revertHighlightChanges();
|
|
1124
|
-
|
|
1125
|
-
if (this.#nameElement) {
|
|
1126
|
-
this.applySearch(regex, this.#nameElement, cssClasses);
|
|
1127
|
-
}
|
|
1128
|
-
if (this.property.object) {
|
|
1129
|
-
const valueType = this.property.object.type;
|
|
1130
|
-
if (valueType !== 'object' && this.#valueElement) {
|
|
1131
|
-
this.applySearch(regex, this.#valueElement, cssClasses);
|
|
1132
|
-
}
|
|
1133
|
-
}
|
|
1134
|
-
|
|
1135
|
-
return Boolean(this.highlightChanges.length);
|
|
1136
|
-
}
|
|
1137
|
-
|
|
1138
|
-
private applySearch(regex: RegExp, element: Element, cssClassName: string): void {
|
|
1139
|
-
const ranges = [];
|
|
1140
|
-
const content = element.textContent || '';
|
|
1141
|
-
regex.lastIndex = 0;
|
|
1142
|
-
let match = regex.exec(content);
|
|
1143
|
-
while (match) {
|
|
1144
|
-
ranges.push(new TextUtils.TextRange.SourceRange(match.index, match[0].length));
|
|
1145
|
-
match = regex.exec(content);
|
|
1146
|
-
}
|
|
1147
|
-
if (ranges.length) {
|
|
1148
|
-
Highlighting.highlightRangesWithStyleClass(element, ranges, cssClassName, this.highlightChanges);
|
|
1149
|
-
}
|
|
1150
|
-
}
|
|
1151
|
-
|
|
1152
1386
|
private showAllPropertiesElementSelected(element: UI.TreeOutline.TreeElement): boolean {
|
|
1153
1387
|
this.removeChild(element);
|
|
1154
1388
|
this.children().forEach(x => {
|
|
@@ -1171,16 +1405,10 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
1171
1405
|
this.appendChild(showAllPropertiesButton);
|
|
1172
1406
|
}
|
|
1173
1407
|
|
|
1174
|
-
revertHighlightChanges(): void {
|
|
1175
|
-
Highlighting.revertDomChanges(this.highlightChanges);
|
|
1176
|
-
this.highlightChanges = [];
|
|
1177
|
-
}
|
|
1178
|
-
|
|
1179
1408
|
override async onpopulate(): Promise<void> {
|
|
1180
1409
|
const treeOutline = (this.treeOutline as ObjectPropertiesSection | null);
|
|
1181
1410
|
const skipProto = treeOutline ? Boolean(treeOutline.skipProtoInternal) : false;
|
|
1182
1411
|
this.removeChildren();
|
|
1183
|
-
this.property.removeChildren();
|
|
1184
1412
|
|
|
1185
1413
|
if (this.property.object) {
|
|
1186
1414
|
await ObjectPropertyTreeElement.populate(this, this.property, skipProto, false, this.linkifier);
|
|
@@ -1190,57 +1418,29 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
1190
1418
|
}
|
|
1191
1419
|
}
|
|
1192
1420
|
|
|
1193
|
-
override onenter(): boolean {
|
|
1194
|
-
if (this.property.object && !this.property.object.customPreview() &&
|
|
1195
|
-
(this.property.property.writable || this.property.property.setter)) {
|
|
1196
|
-
this.startEditing();
|
|
1197
|
-
return true;
|
|
1198
|
-
}
|
|
1199
|
-
return false;
|
|
1200
|
-
}
|
|
1201
|
-
|
|
1202
1421
|
override onattach(): void {
|
|
1203
|
-
this.performUpdate();
|
|
1204
1422
|
this.updateExpandable();
|
|
1423
|
+
this.#widget.markAsRoot();
|
|
1424
|
+
this.#widget.show(this.listItemElement);
|
|
1425
|
+
this.#widget.property = this.property;
|
|
1426
|
+
this.#widget.linkifier = this.linkifier;
|
|
1205
1427
|
}
|
|
1206
1428
|
|
|
1207
1429
|
override onexpand(): void {
|
|
1208
|
-
this.
|
|
1430
|
+
this.#widget.expanded = true;
|
|
1209
1431
|
}
|
|
1210
1432
|
|
|
1211
1433
|
override oncollapse(): void {
|
|
1212
|
-
this.
|
|
1434
|
+
this.#widget.expanded = false;
|
|
1213
1435
|
}
|
|
1214
1436
|
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
this.#completions = suggestions.map(v => v.text);
|
|
1218
|
-
this.performUpdate();
|
|
1437
|
+
#updateValue(): void {
|
|
1438
|
+
this.updateExpandable();
|
|
1219
1439
|
}
|
|
1220
1440
|
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
editing: this.#editing,
|
|
1225
|
-
editingEnded: this.editingEnded.bind(this),
|
|
1226
|
-
editingCommitted: this.editingCommitted.bind(this),
|
|
1227
|
-
node: this.property,
|
|
1228
|
-
linkifier: this.linkifier,
|
|
1229
|
-
completions: this.#editing ? this.#completions : [],
|
|
1230
|
-
onAutoComplete: this.#updateCompletions.bind(this),
|
|
1231
|
-
invokeGetter: this.onInvokeGetterClick.bind(this),
|
|
1232
|
-
startEditing: this.startEditing.bind(this),
|
|
1233
|
-
};
|
|
1234
|
-
const that = this;
|
|
1235
|
-
const output: TreeElementViewOutput = {
|
|
1236
|
-
set nameElement(e: Element|undefined) {
|
|
1237
|
-
that.#nameElement = e;
|
|
1238
|
-
},
|
|
1239
|
-
set valueElement(e: Element|undefined) {
|
|
1240
|
-
that.#valueElement = e;
|
|
1241
|
-
},
|
|
1242
|
-
};
|
|
1243
|
-
this.#view(input, output, this.listItemElement);
|
|
1441
|
+
#updateChildren(): void {
|
|
1442
|
+
this.removeChildren();
|
|
1443
|
+
void this.onpopulate();
|
|
1244
1444
|
}
|
|
1245
1445
|
|
|
1246
1446
|
getContextMenu(event: Event): UI.ContextMenu.ContextMenu {
|
|
@@ -1284,115 +1484,6 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
1284
1484
|
void contextMenu.show();
|
|
1285
1485
|
}
|
|
1286
1486
|
|
|
1287
|
-
get editing(): boolean {
|
|
1288
|
-
return this.#editing;
|
|
1289
|
-
}
|
|
1290
|
-
|
|
1291
|
-
private startEditing(): void {
|
|
1292
|
-
if (!this.readOnly) {
|
|
1293
|
-
this.#editing = true;
|
|
1294
|
-
this.performUpdate();
|
|
1295
|
-
}
|
|
1296
|
-
}
|
|
1297
|
-
|
|
1298
|
-
private editingEnded(): void {
|
|
1299
|
-
this.#completions = [];
|
|
1300
|
-
this.#editing = false;
|
|
1301
|
-
this.performUpdate();
|
|
1302
|
-
this.updateExpandable();
|
|
1303
|
-
this.select();
|
|
1304
|
-
}
|
|
1305
|
-
|
|
1306
|
-
private async editingCommitted(newContent: string): Promise<void> {
|
|
1307
|
-
this.editingEnded();
|
|
1308
|
-
await this.applyExpression(newContent);
|
|
1309
|
-
}
|
|
1310
|
-
|
|
1311
|
-
private promptKeyDown(originalContent: string, event: Event): void {
|
|
1312
|
-
const keyboardEvent = (event as KeyboardEvent);
|
|
1313
|
-
if (keyboardEvent.key === 'Enter') {
|
|
1314
|
-
keyboardEvent.consume();
|
|
1315
|
-
void this.editingCommitted(originalContent);
|
|
1316
|
-
return;
|
|
1317
|
-
}
|
|
1318
|
-
if (keyboardEvent.key === Platform.KeyboardUtilities.ESCAPE_KEY) {
|
|
1319
|
-
keyboardEvent.consume();
|
|
1320
|
-
this.editingEnded();
|
|
1321
|
-
return;
|
|
1322
|
-
}
|
|
1323
|
-
}
|
|
1324
|
-
|
|
1325
|
-
private async applyExpression(expression: string): Promise<void> {
|
|
1326
|
-
const property = SDK.RemoteObject.RemoteObject.toCallArgument(this.property.property.symbol || this.property.name);
|
|
1327
|
-
expression = JavaScriptREPL.wrapObjectLiteral(expression.trim());
|
|
1328
|
-
|
|
1329
|
-
if (this.property.property.synthetic) {
|
|
1330
|
-
let invalidate = false;
|
|
1331
|
-
if (expression) {
|
|
1332
|
-
invalidate = await this.property.property.setSyntheticValue(expression);
|
|
1333
|
-
}
|
|
1334
|
-
if (invalidate) {
|
|
1335
|
-
const parent = this.parent;
|
|
1336
|
-
if (parent) {
|
|
1337
|
-
parent.invalidateChildren();
|
|
1338
|
-
void parent.onpopulate();
|
|
1339
|
-
}
|
|
1340
|
-
} else {
|
|
1341
|
-
this.performUpdate();
|
|
1342
|
-
}
|
|
1343
|
-
return;
|
|
1344
|
-
}
|
|
1345
|
-
|
|
1346
|
-
const parentObject = this.property.parent?.object as SDK.RemoteObject.RemoteObject;
|
|
1347
|
-
const errorPromise =
|
|
1348
|
-
expression ? parentObject.setPropertyValue(property, expression) : parentObject.deleteProperty(property);
|
|
1349
|
-
const error = await errorPromise;
|
|
1350
|
-
if (error) {
|
|
1351
|
-
this.performUpdate();
|
|
1352
|
-
return;
|
|
1353
|
-
}
|
|
1354
|
-
|
|
1355
|
-
if (!expression) {
|
|
1356
|
-
// The property was deleted, so remove this tree element.
|
|
1357
|
-
this.parent?.removeChild(this);
|
|
1358
|
-
this.property.parent?.removeChild(this.property);
|
|
1359
|
-
} else {
|
|
1360
|
-
// Call updateSiblings since their value might be based on the value that just changed.
|
|
1361
|
-
const parent = this.parent;
|
|
1362
|
-
if (parent) {
|
|
1363
|
-
parent.invalidateChildren();
|
|
1364
|
-
this.property.parent?.removeChildren();
|
|
1365
|
-
void parent.onpopulate();
|
|
1366
|
-
}
|
|
1367
|
-
}
|
|
1368
|
-
}
|
|
1369
|
-
|
|
1370
|
-
override invalidateChildren(): void {
|
|
1371
|
-
super.invalidateChildren();
|
|
1372
|
-
this.property.removeChildren();
|
|
1373
|
-
}
|
|
1374
|
-
|
|
1375
|
-
async onInvokeGetterClick(getter: SDK.RemoteObject.RemoteObject): Promise<void> {
|
|
1376
|
-
const invokeGetter = `
|
|
1377
|
-
function invokeGetter(getter) {
|
|
1378
|
-
return Reflect.apply(getter, this, []);
|
|
1379
|
-
}`;
|
|
1380
|
-
// Also passing a string instead of a Function to avoid coverage implementation messing with it.
|
|
1381
|
-
const result = await this.property.parent
|
|
1382
|
-
?.object
|
|
1383
|
-
// @ts-expect-error No way to teach TypeScript to preserve the Function-ness of `getter`.
|
|
1384
|
-
?.callFunction(invokeGetter, [SDK.RemoteObject.RemoteObject.toCallArgument(getter)]);
|
|
1385
|
-
if (!result?.object) {
|
|
1386
|
-
return;
|
|
1387
|
-
}
|
|
1388
|
-
this.property.property.value = result.object;
|
|
1389
|
-
this.property.property.wasThrown = result.wasThrown || false;
|
|
1390
|
-
|
|
1391
|
-
this.performUpdate();
|
|
1392
|
-
this.invalidateChildren();
|
|
1393
|
-
this.updateExpandable();
|
|
1394
|
-
}
|
|
1395
|
-
|
|
1396
1487
|
private updateExpandable(): void {
|
|
1397
1488
|
if (this.property.object) {
|
|
1398
1489
|
this.setExpandable(
|
|
@@ -1549,6 +1640,7 @@ export class ArrayGroupingTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
1549
1640
|
constructor(child: ArrayGroupTreeNode, linkifier?: Components.Linkifier.Linkifier) {
|
|
1550
1641
|
super(Platform.StringUtilities.sprintf('[%d … %d]', child.range.fromIndex, child.range.toIndex), true);
|
|
1551
1642
|
this.#child = child;
|
|
1643
|
+
this.#child.addEventListener(ObjectTreeNodeBase.Events.CHILDREN_CHANGED, this.onpopulate, this);
|
|
1552
1644
|
this.toggleOnClick = true;
|
|
1553
1645
|
this.linkifier = linkifier;
|
|
1554
1646
|
}
|
|
@@ -1574,14 +1666,8 @@ export class ArrayGroupingTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
1574
1666
|
ObjectPropertyTreeElement.populateWithProperties(treeNode, children, false, false, linkifier);
|
|
1575
1667
|
}
|
|
1576
1668
|
|
|
1577
|
-
override invalidateChildren(): void {
|
|
1578
|
-
super.invalidateChildren();
|
|
1579
|
-
this.#child.removeChildren();
|
|
1580
|
-
}
|
|
1581
|
-
|
|
1582
1669
|
override async onpopulate(): Promise<void> {
|
|
1583
1670
|
this.removeChildren();
|
|
1584
|
-
this.#child.removeChildren();
|
|
1585
1671
|
await ObjectPropertyTreeElement.populate(this, this.#child, false, false, this.linkifier);
|
|
1586
1672
|
}
|
|
1587
1673
|
|