chrome-devtools-frontend 1.0.1539728 → 1.0.1541169
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/eslint.config.mjs +167 -151
- package/front_end/core/common/Debouncer.ts +2 -2
- package/front_end/core/common/Gzip.ts +1 -1
- package/front_end/core/common/Revealer.ts +5 -0
- package/front_end/core/common/Throttler.ts +3 -3
- package/front_end/core/host/GdpClient.ts +4 -0
- package/front_end/core/host/InspectorFrontendHost.ts +10 -10
- package/front_end/core/protocol_client/DevToolsCDPConnection.ts +181 -0
- package/front_end/core/protocol_client/InspectorBackend.ts +36 -203
- package/front_end/core/protocol_client/protocol_client.ts +2 -2
- package/front_end/core/sdk/DebuggerModel.ts +3 -16
- package/front_end/core/sdk/NetworkManager.ts +16 -11
- package/front_end/core/sdk/RemoteObject.ts +4 -0
- package/front_end/core/sdk/Target.ts +3 -6
- package/front_end/core/sdk/TargetManager.ts +1 -2
- package/front_end/core/sdk/sdk-meta.ts +0 -35
- package/front_end/entrypoints/lighthouse_worker/LighthouseWorkerService.ts +1 -3
- package/front_end/entrypoints/node_app/app/NodeMain.ts +3 -2
- package/front_end/entrypoints/shell/shell.ts +1 -0
- package/front_end/entrypoints/trace_app/trace_app.ts +1 -0
- package/front_end/generated/Deprecation.ts +8 -0
- package/front_end/generated/InspectorBackendCommands.ts +8 -5
- package/front_end/generated/SupportedCSSProperties.js +58 -4
- package/front_end/generated/protocol.ts +60 -4
- package/front_end/models/ai_assistance/EvaluateAction.ts +88 -5
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.snapshot.txt +121 -56
- package/front_end/models/ai_assistance/data_formatters/PerformanceTraceFormatter.ts +104 -62
- package/front_end/models/ai_assistance/injected.ts +15 -2
- package/front_end/models/ai_assistance/performance/AIQueries.ts +56 -2
- package/front_end/{panels/issues → models/issues_manager}/IssueAggregator.ts +83 -65
- package/front_end/models/issues_manager/issues_manager.ts +2 -0
- package/front_end/models/live-metrics/web-vitals-injected/README.md +1 -1
- package/front_end/models/trace/Processor.ts +5 -4
- package/front_end/models/trace/Styles.ts +1 -1
- package/front_end/models/trace/insights/types.ts +1 -1
- package/front_end/models/trace/types/TraceEvents.ts +1 -1
- package/front_end/models/workspace/IgnoreListManager.ts +41 -47
- package/front_end/models/workspace/workspace-meta.ts +40 -0
- package/front_end/panels/ai_assistance/PatchWidget.ts +22 -12
- package/front_end/panels/ai_assistance/components/ChatView.ts +1 -1
- package/front_end/panels/animation/AnimationTimeline.ts +4 -4
- package/front_end/panels/animation/AnimationUI.ts +28 -34
- package/front_end/panels/common/AiCodeCompletionDisclaimer.ts +4 -4
- package/front_end/panels/common/AiCodeCompletionSummaryToolbar.ts +2 -2
- package/front_end/panels/elements/ElementsTreeElement.ts +37 -9
- package/front_end/panels/elements/LayoutPane.ts +2 -2
- package/front_end/panels/elements/PropertiesWidget.ts +3 -2
- package/front_end/panels/elements/components/AdornerManager.ts +9 -9
- package/front_end/panels/elements/layoutPane.css +5 -9
- package/front_end/panels/event_listeners/EventListenersView.ts +10 -6
- package/front_end/panels/explain/components/ConsoleInsight.ts +498 -449
- package/front_end/panels/issues/AffectedResourcesView.ts +3 -4
- package/front_end/panels/issues/CorsIssueDetailsView.ts +1 -2
- package/front_end/panels/issues/IssueView.ts +1 -1
- package/front_end/panels/issues/IssuesPane.ts +12 -15
- package/front_end/panels/issues/issues.ts +0 -2
- package/front_end/panels/lighthouse/LighthouseProtocolService.ts +3 -3
- package/front_end/panels/linear_memory_inspector/LinearMemoryInspectorController.ts +2 -2
- package/front_end/panels/network/NetworkDataGridNode.ts +2 -1
- package/front_end/panels/network/RequestConditionsDrawer.ts +149 -46
- package/front_end/panels/network/RequestPayloadView.ts +2 -1
- package/front_end/panels/network/RequestTimingView.ts +17 -10
- package/front_end/panels/network/components/RequestHeadersView.ts +24 -17
- package/front_end/panels/network/network-meta.ts +11 -0
- package/front_end/panels/protocol_monitor/JSONEditor.ts +2 -2
- package/front_end/panels/recorder/RecorderController.ts +6 -7
- package/front_end/panels/recorder/models/RecordingPlayer.ts +3 -3
- package/front_end/panels/settings/components/SyncSection.ts +1 -1
- package/front_end/panels/settings/emulation/components/userAgentClientHintsForm.css +1 -1
- package/front_end/panels/sources/BreakpointsView.ts +3 -3
- package/front_end/panels/sources/DebuggerPlugin.ts +1 -1
- package/front_end/panels/sources/ScopeChainSidebarPane.ts +4 -3
- package/front_end/panels/sources/WatchExpressionsSidebarPane.ts +4 -3
- package/front_end/panels/sources/breakpointsView.css +1 -1
- package/front_end/panels/sources/sourcesPanel.css +2 -2
- package/front_end/panels/timeline/TimelineFlameChartView.ts +3 -3
- package/front_end/panels/timeline/TimelinePanel.ts +3 -3
- package/front_end/panels/timeline/components/FieldSettingsDialog.ts +9 -5
- package/front_end/panels/timeline/components/LayoutShiftDetails.ts +16 -10
- package/front_end/panels/timeline/components/LiveMetricsView.ts +20 -9
- package/front_end/panels/timeline/components/MetricCard.ts +4 -2
- package/front_end/panels/timeline/components/SidebarSingleInsightSet.ts +2 -0
- package/front_end/services/puppeteer/PuppeteerConnection.ts +2 -1
- 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/api/Page.d.ts +5 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/api/Page.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Page.d.ts +1 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Page.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Page.js +3 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/bidi/Page.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.d.ts +1 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.js +21 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Browser.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/ExtensionTransport.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/ExtensionTransport.js +5 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/ExtensionTransport.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.d.ts +1 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.js +6 -0
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/Page.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/cjs/puppeteer/cdp/TargetManager.d.ts +1 -1
- 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 +29 -27
- 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.d.ts +5 -0
- package/front_end/third_party/puppeteer/package/lib/es5-iife/puppeteer-core-browser.js +61 -26
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.d.ts +5 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/api/Page.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Page.d.ts +1 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Page.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Page.js +3 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/bidi/Page.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.d.ts +1 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.js +21 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Browser.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/ExtensionTransport.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/ExtensionTransport.js +5 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/ExtensionTransport.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.d.ts +1 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.d.ts.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.js +6 -0
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/Page.js.map +1 -1
- package/front_end/third_party/puppeteer/package/lib/esm/puppeteer/cdp/TargetManager.d.ts +1 -1
- 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 +30 -28
- 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/lib/types.d.ts +5 -0
- package/front_end/third_party/puppeteer/package/package.json +1 -1
- package/front_end/third_party/puppeteer/package/src/api/Page.ts +6 -0
- package/front_end/third_party/puppeteer/package/src/bidi/Page.ts +4 -0
- package/front_end/third_party/puppeteer/package/src/cdp/Browser.ts +32 -0
- package/front_end/third_party/puppeteer/package/src/cdp/ExtensionTransport.ts +5 -1
- package/front_end/third_party/puppeteer/package/src/cdp/Page.ts +8 -0
- package/front_end/third_party/puppeteer/package/src/cdp/TargetManager.ts +36 -43
- package/front_end/third_party/puppeteer/package/src/util/version.ts +1 -1
- package/front_end/ui/components/dialogs/ButtonDialog.ts +15 -5
- package/front_end/ui/components/expandable_list/ExpandableList.ts +1 -1
- package/front_end/ui/components/helpers/helpers.ts +0 -2
- package/front_end/ui/components/markdown_view/MarkdownView.ts +1 -0
- package/front_end/ui/components/menus/Menu.ts +5 -3
- package/front_end/ui/components/snackbars/Snackbars.docs.ts +46 -0
- package/front_end/ui/components/survey_link/SurveyLink.docs.ts +22 -0
- package/front_end/ui/components/tree_outline/TreeOutline.ts +1 -2
- package/front_end/ui/{components/docs/context_menu/basic.ts → legacy/ContextMenu.docs.ts} +58 -25
- package/front_end/ui/legacy/SelectMenu.docs.ts +14 -0
- package/front_end/ui/legacy/UIUtils.ts +2 -1
- package/front_end/ui/legacy/components/inline_editor/BezierEditor.ts +1 -1
- package/front_end/ui/legacy/components/object_ui/CustomPreviewComponent.ts +3 -1
- package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +558 -439
- package/front_end/ui/legacy/components/perf_ui/TimelineOverviewPane.ts +3 -3
- package/front_end/ui/legacy/components/perf_ui/pieChart.css +1 -1
- package/front_end/ui/legacy/components/utils/Linkifier.ts +1 -1
- package/front_end/ui/legacy/inspectorCommon.css +3 -2
- package/mcp/mcp.ts +15 -1
- package/package.json +2 -1
- package/front_end/core/protocol_client/NodeURL.ts +0 -40
- package/front_end/ui/components/docs/combo_box/basic.html +0 -20
- package/front_end/ui/components/docs/combo_box/basic.ts +0 -49
- package/front_end/ui/components/docs/context_menu/basic.html +0 -45
- package/front_end/ui/components/docs/legacy_color_invert/basic.html +0 -77
- package/front_end/ui/components/docs/legacy_color_invert/basic.ts +0 -98
- package/front_end/ui/components/docs/linkifier/simple-url.html +0 -25
- package/front_end/ui/components/docs/linkifier/simple-url.ts +0 -25
- package/front_end/ui/components/docs/panel_feedback/basic.html +0 -25
- package/front_end/ui/components/docs/panel_feedback/basic.ts +0 -21
- package/front_end/ui/components/docs/panel_feedback/button.html +0 -25
- package/front_end/ui/components/docs/panel_feedback/button.ts +0 -19
- package/front_end/ui/components/docs/panel_introduction_steps/basic.html +0 -25
- package/front_end/ui/components/docs/panel_introduction_steps/basic.ts +0 -28
- package/front_end/ui/components/docs/perf_piechart/basic-with-legend.html +0 -20
- package/front_end/ui/components/docs/perf_piechart/basic-with-legend.ts +0 -20
- package/front_end/ui/components/docs/perf_piechart/basic-without-legend.html +0 -20
- package/front_end/ui/components/docs/perf_piechart/basic-without-legend.ts +0 -18
- package/front_end/ui/components/docs/snackbars/basic.html +0 -17
- package/front_end/ui/components/docs/snackbars/basic.ts +0 -50
- package/front_end/ui/components/docs/survey_link/basic.html +0 -20
- package/front_end/ui/components/docs/survey_link/basic.ts +0 -28
- package/front_end/ui/components/docs/tree_outline/basic.html +0 -33
- package/front_end/ui/components/docs/tree_outline/basic.ts +0 -38
- package/front_end/ui/components/docs/tree_outline/custom-renderers.html +0 -32
- package/front_end/ui/components/docs/tree_outline/custom-renderers.ts +0 -61
- package/front_end/ui/components/docs/tree_outline/lazy-children.html +0 -32
- package/front_end/ui/components/docs/tree_outline/lazy-children.ts +0 -91
- package/front_end/ui/components/docs/tree_outline/sample-data.ts +0 -67
- package/front_end/ui/components/helpers/directives.ts +0 -38
|
@@ -34,10 +34,12 @@ import * as Host from '../../../../core/host/host.js';
|
|
|
34
34
|
import * as i18n from '../../../../core/i18n/i18n.js';
|
|
35
35
|
import * as Platform from '../../../../core/platform/platform.js';
|
|
36
36
|
import * as SDK from '../../../../core/sdk/sdk.js';
|
|
37
|
+
import type * as Protocol from '../../../../generated/protocol.js';
|
|
37
38
|
import * as TextUtils from '../../../../models/text_utils/text_utils.js';
|
|
38
39
|
import * as uiI18n from '../../../../ui/i18n/i18n.js';
|
|
39
40
|
import * as IconButton from '../../../components/icon_button/icon_button.js';
|
|
40
41
|
import * as TextEditor from '../../../components/text_editor/text_editor.js';
|
|
42
|
+
import {Directives, html, render} from '../../../lit/lit.js';
|
|
41
43
|
import * as VisualLogging from '../../../visual_logging/visual_logging.js';
|
|
42
44
|
import * as UI from '../../legacy.js';
|
|
43
45
|
import type * as Components from '../utils/utils.js';
|
|
@@ -48,6 +50,7 @@ import objectPropertiesSectionStyles from './objectPropertiesSection.css.js';
|
|
|
48
50
|
import objectValueStyles from './objectValue.css.js';
|
|
49
51
|
import {createSpansForNodeTitle, RemoteObjectPreviewFormatter} from './RemoteObjectPreviewFormatter.js';
|
|
50
52
|
|
|
53
|
+
const {ifDefined} = Directives;
|
|
51
54
|
const UIStrings = {
|
|
52
55
|
/**
|
|
53
56
|
* @description Text in Object Properties Section
|
|
@@ -136,15 +139,214 @@ const i18nString = i18n.i18n.getLocalizedString.bind(undefined, str_);
|
|
|
136
139
|
const EXPANDABLE_MAX_LENGTH = 50;
|
|
137
140
|
const EXPANDABLE_MAX_DEPTH = 100;
|
|
138
141
|
|
|
139
|
-
const parentMap = new WeakMap<SDK.RemoteObject.RemoteObjectProperty, SDK.RemoteObject.RemoteObject|null>();
|
|
140
142
|
const objectPropertiesSectionMap = new WeakMap<Element, ObjectPropertiesSection>();
|
|
141
143
|
|
|
144
|
+
interface NodeChildren {
|
|
145
|
+
properties?: ObjectTreeNode[];
|
|
146
|
+
internalProperties?: ObjectTreeNode[];
|
|
147
|
+
arrayRanges?: ArrayGroupTreeNode[];
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
abstract class ObjectTreeNodeBase {
|
|
151
|
+
#children?: NodeChildren;
|
|
152
|
+
protected extraProperties: ObjectTreeNode[] = [];
|
|
153
|
+
constructor(
|
|
154
|
+
readonly parent?: ObjectTreeNodeBase,
|
|
155
|
+
readonly propertiesMode: ObjectPropertiesMode = ObjectPropertiesMode.OWN_AND_INTERNAL_AND_INHERITED) {
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
abstract get object(): SDK.RemoteObject.RemoteObject|undefined;
|
|
159
|
+
|
|
160
|
+
removeChildren(): void {
|
|
161
|
+
this.#children = undefined;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
removeChild(child: ObjectTreeNodeBase): void {
|
|
165
|
+
remove(this.#children?.arrayRanges, child);
|
|
166
|
+
remove(this.#children?.internalProperties, child);
|
|
167
|
+
remove(this.#children?.properties, child);
|
|
168
|
+
|
|
169
|
+
function remove<T>(array: T[]|undefined, element: T): void {
|
|
170
|
+
if (!array) {
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
const index = array.indexOf(element);
|
|
174
|
+
if (index >= 0) {
|
|
175
|
+
array.splice(index, 1);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
protected selfOrParentIfInternal(): ObjectTreeNodeBase {
|
|
181
|
+
return this;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
async children(): Promise<NodeChildren> {
|
|
185
|
+
if (!this.#children) {
|
|
186
|
+
this.#children = await this.populateChildren();
|
|
187
|
+
}
|
|
188
|
+
return this.#children;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
protected async populateChildren(): Promise<NodeChildren> {
|
|
192
|
+
const object = this.object;
|
|
193
|
+
if (!object) {
|
|
194
|
+
return {};
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const effectiveParent = this.selfOrParentIfInternal();
|
|
198
|
+
|
|
199
|
+
if (this.arrayLength > ARRAY_LOAD_THRESHOLD) {
|
|
200
|
+
const ranges = await arrayRangeGroups(object, 0, this.arrayLength - 1);
|
|
201
|
+
const arrayRanges = ranges?.ranges.map(
|
|
202
|
+
([fromIndex, toIndex, count]) => new ArrayGroupTreeNode(object, {fromIndex, toIndex, count}));
|
|
203
|
+
if (!arrayRanges) {
|
|
204
|
+
return {};
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const {properties: objectProperties, internalProperties: objectInternalProperties} =
|
|
208
|
+
await SDK.RemoteObject.RemoteObject.loadFromObjectPerProto(
|
|
209
|
+
this.object, true /* generatePreview */, true /* nonIndexedPropertiesOnly */);
|
|
210
|
+
|
|
211
|
+
const properties = objectProperties?.map(p => new ObjectTreeNode(p, undefined, effectiveParent, undefined));
|
|
212
|
+
|
|
213
|
+
const internalProperties =
|
|
214
|
+
objectInternalProperties?.map(p => new ObjectTreeNode(p, undefined, effectiveParent, undefined));
|
|
215
|
+
return {arrayRanges, properties, internalProperties};
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
let objectProperties: SDK.RemoteObject.RemoteObjectProperty[]|null = null;
|
|
219
|
+
let objectInternalProperties: SDK.RemoteObject.RemoteObjectProperty[]|null = null;
|
|
220
|
+
switch (this.propertiesMode) {
|
|
221
|
+
case ObjectPropertiesMode.ALL:
|
|
222
|
+
({properties: objectProperties} =
|
|
223
|
+
await object.getAllProperties(false /* accessorPropertiesOnly */, true /* generatePreview */));
|
|
224
|
+
break;
|
|
225
|
+
case ObjectPropertiesMode.OWN_AND_INTERNAL_AND_INHERITED:
|
|
226
|
+
({properties: objectProperties, internalProperties: objectInternalProperties} =
|
|
227
|
+
await SDK.RemoteObject.RemoteObject.loadFromObjectPerProto(object, true /* generatePreview */));
|
|
228
|
+
break;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const properties = objectProperties?.map(p => new ObjectTreeNode(p, undefined, effectiveParent, undefined));
|
|
232
|
+
properties?.push(...this.extraProperties);
|
|
233
|
+
|
|
234
|
+
const internalProperties =
|
|
235
|
+
objectInternalProperties?.map(p => new ObjectTreeNode(p, undefined, effectiveParent, undefined));
|
|
236
|
+
return {properties, internalProperties};
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
get hasChildren(): boolean {
|
|
240
|
+
return this.object?.hasChildren ?? false;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
get arrayLength(): number {
|
|
244
|
+
return this.object?.arrayLength() ?? 0;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// This is used in web tests
|
|
248
|
+
async setPropertyValue(name: string|Protocol.Runtime.CallArgument, value: string): Promise<string|undefined> {
|
|
249
|
+
return await this.object?.setPropertyValue(name, value);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
addExtraProperties(...properties: SDK.RemoteObject.RemoteObjectProperty[]): void {
|
|
253
|
+
this.extraProperties.push(...properties.map(p => new ObjectTreeNode(p, undefined, this, undefined)));
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
export class ObjectTree extends ObjectTreeNodeBase {
|
|
258
|
+
readonly #object: SDK.RemoteObject.RemoteObject;
|
|
259
|
+
|
|
260
|
+
constructor(
|
|
261
|
+
object: SDK.RemoteObject.RemoteObject,
|
|
262
|
+
propertiesMode: ObjectPropertiesMode = ObjectPropertiesMode.OWN_AND_INTERNAL_AND_INHERITED) {
|
|
263
|
+
super(undefined, propertiesMode);
|
|
264
|
+
this.#object = object;
|
|
265
|
+
}
|
|
266
|
+
override get object(): SDK.RemoteObject.RemoteObject {
|
|
267
|
+
return this.#object;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
class ArrayGroupTreeNode extends ObjectTreeNodeBase {
|
|
272
|
+
readonly #object: SDK.RemoteObject.RemoteObject;
|
|
273
|
+
readonly #range: {fromIndex: number, toIndex: number, count: number};
|
|
274
|
+
constructor(
|
|
275
|
+
object: SDK.RemoteObject.RemoteObject, range: {fromIndex: number, toIndex: number, count: number},
|
|
276
|
+
parent?: ObjectTreeNodeBase,
|
|
277
|
+
propertiesMode: ObjectPropertiesMode = ObjectPropertiesMode.OWN_AND_INTERNAL_AND_INHERITED) {
|
|
278
|
+
super(parent, propertiesMode);
|
|
279
|
+
this.#object = object;
|
|
280
|
+
this.#range = range;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
protected override async populateChildren(): Promise<NodeChildren> {
|
|
284
|
+
if (this.#range.count > ArrayGroupingTreeElement.bucketThreshold) {
|
|
285
|
+
const ranges = await arrayRangeGroups(this.object, this.#range.fromIndex, this.#range.toIndex);
|
|
286
|
+
const arrayRanges = ranges?.ranges.map(
|
|
287
|
+
([fromIndex, toIndex, count]) => new ArrayGroupTreeNode(this.object, {fromIndex, toIndex, count}));
|
|
288
|
+
return {arrayRanges};
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const result = await this.#object.callFunction(buildArrayFragment, [
|
|
292
|
+
{value: this.#range.fromIndex},
|
|
293
|
+
{value: this.#range.toIndex},
|
|
294
|
+
{value: ArrayGroupingTreeElement.sparseIterationThreshold},
|
|
295
|
+
]);
|
|
296
|
+
if (!result.object || result.wasThrown) {
|
|
297
|
+
return {};
|
|
298
|
+
}
|
|
299
|
+
const arrayFragment = result.object;
|
|
300
|
+
const allProperties =
|
|
301
|
+
await arrayFragment.getAllProperties(false /* accessorPropertiesOnly */, true /* generatePreview */);
|
|
302
|
+
arrayFragment.release();
|
|
303
|
+
const properties = allProperties.properties?.map(p => new ObjectTreeNode(p, this.propertiesMode, this, undefined));
|
|
304
|
+
properties?.push(...this.extraProperties);
|
|
305
|
+
properties?.sort(ObjectPropertiesSection.compareProperties);
|
|
306
|
+
return {properties};
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
get singular(): boolean {
|
|
310
|
+
return this.#range.fromIndex === this.#range.toIndex;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
get range(): {fromIndex: number, toIndex: number, count: number} {
|
|
314
|
+
return this.#range;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
override get object(): SDK.RemoteObject.RemoteObject {
|
|
318
|
+
return this.#object;
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
export class ObjectTreeNode extends ObjectTreeNodeBase {
|
|
323
|
+
constructor(
|
|
324
|
+
readonly property: SDK.RemoteObject.RemoteObjectProperty,
|
|
325
|
+
propertiesMode: ObjectPropertiesMode = ObjectPropertiesMode.OWN_AND_INTERNAL_AND_INHERITED,
|
|
326
|
+
parent?: ObjectTreeNodeBase,
|
|
327
|
+
readonly nonSyntheticParent?: SDK.RemoteObject.RemoteObject,
|
|
328
|
+
) {
|
|
329
|
+
super(parent, propertiesMode);
|
|
330
|
+
}
|
|
331
|
+
override get object(): SDK.RemoteObject.RemoteObject|undefined {
|
|
332
|
+
return this.property.value;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
get name(): string {
|
|
336
|
+
return this.property.name;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
override selfOrParentIfInternal(): ObjectTreeNodeBase {
|
|
340
|
+
return this.name === '[[Prototype]]' ? (this.parent ?? this) : this;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
142
344
|
export const getObjectPropertiesSectionFrom = (element: Element): ObjectPropertiesSection|undefined => {
|
|
143
345
|
return objectPropertiesSectionMap.get(element);
|
|
144
346
|
};
|
|
145
347
|
|
|
146
348
|
export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow {
|
|
147
|
-
private readonly
|
|
349
|
+
private readonly root: ObjectTree;
|
|
148
350
|
editable: boolean;
|
|
149
351
|
readonly #objectTreeElement: RootElement;
|
|
150
352
|
titleElement: Element;
|
|
@@ -153,14 +355,14 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
|
|
|
153
355
|
object: SDK.RemoteObject.RemoteObject, title?: string|Element|null, linkifier?: Components.Linkifier.Linkifier,
|
|
154
356
|
showOverflow?: boolean) {
|
|
155
357
|
super();
|
|
156
|
-
this.
|
|
358
|
+
this.root = new ObjectTree(object);
|
|
157
359
|
this.editable = true;
|
|
158
360
|
if (!showOverflow) {
|
|
159
361
|
this.setHideOverflow(true);
|
|
160
362
|
}
|
|
161
363
|
this.setFocusable(true);
|
|
162
364
|
this.setShowSelectionOnKeyboardFocus(true);
|
|
163
|
-
this.#objectTreeElement = new RootElement(
|
|
365
|
+
this.#objectTreeElement = new RootElement(this.root, linkifier);
|
|
164
366
|
this.appendChild(this.#objectTreeElement);
|
|
165
367
|
if (typeof title === 'string' || !title) {
|
|
166
368
|
this.titleElement = this.element.createChild('span');
|
|
@@ -197,7 +399,7 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
|
|
|
197
399
|
const shadowRoot = UI.UIUtils.createShadowRootWithCoreStyles(titleElement, {cssFile: objectValueStyles});
|
|
198
400
|
const propertyValue =
|
|
199
401
|
ObjectPropertiesSection.createPropertyValue(object, /* wasThrown */ false, /* showPreview */ true);
|
|
200
|
-
shadowRoot.appendChild(propertyValue
|
|
402
|
+
shadowRoot.appendChild(propertyValue);
|
|
201
403
|
const objectPropertiesSection = new ObjectPropertiesSection(object, titleElement, linkifier);
|
|
202
404
|
objectPropertiesSection.editable = false;
|
|
203
405
|
if (skipProto) {
|
|
@@ -210,8 +412,16 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
|
|
|
210
412
|
return objectPropertiesSection;
|
|
211
413
|
}
|
|
212
414
|
|
|
415
|
+
// The RemoteObjectProperty overload is kept for web test compatibility for now.
|
|
213
416
|
static compareProperties(
|
|
214
|
-
propertyA: SDK.RemoteObject.RemoteObjectProperty,
|
|
417
|
+
propertyA: ObjectTreeNode|SDK.RemoteObject.RemoteObjectProperty,
|
|
418
|
+
propertyB: ObjectTreeNode|SDK.RemoteObject.RemoteObjectProperty): number {
|
|
419
|
+
if (propertyA instanceof ObjectTreeNode) {
|
|
420
|
+
propertyA = propertyA.property;
|
|
421
|
+
}
|
|
422
|
+
if (propertyB instanceof ObjectTreeNode) {
|
|
423
|
+
propertyB = propertyB.property;
|
|
424
|
+
}
|
|
215
425
|
if (!propertyA.synthetic && propertyB.synthetic) {
|
|
216
426
|
return 1;
|
|
217
427
|
}
|
|
@@ -269,7 +479,7 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
|
|
|
269
479
|
}
|
|
270
480
|
|
|
271
481
|
static valueElementForFunctionDescription(description?: string, includePreview?: boolean, defaultName?: string):
|
|
272
|
-
|
|
482
|
+
HTMLElement {
|
|
273
483
|
const valueElement = document.createElement('span');
|
|
274
484
|
valueElement.classList.add('object-value-function');
|
|
275
485
|
description = description || '';
|
|
@@ -352,12 +562,11 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
|
|
|
352
562
|
|
|
353
563
|
static createPropertyValueWithCustomSupport(
|
|
354
564
|
value: SDK.RemoteObject.RemoteObject, wasThrown: boolean, showPreview: boolean,
|
|
355
|
-
linkifier?: Components.Linkifier.Linkifier, isSyntheticProperty?: boolean,
|
|
356
|
-
variableName?: string): ObjectPropertyValue {
|
|
565
|
+
linkifier?: Components.Linkifier.Linkifier, isSyntheticProperty?: boolean, variableName?: string): HTMLElement {
|
|
357
566
|
if (value.customPreview()) {
|
|
358
567
|
const result = (new CustomPreviewComponent(value)).element;
|
|
359
568
|
result.classList.add('object-properties-section-custom-section');
|
|
360
|
-
return
|
|
569
|
+
return result;
|
|
361
570
|
}
|
|
362
571
|
return ObjectPropertiesSection.createPropertyValue(
|
|
363
572
|
value, wasThrown, showPreview, linkifier, isSyntheticProperty, variableName);
|
|
@@ -392,9 +601,8 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
|
|
|
392
601
|
|
|
393
602
|
static createPropertyValue(
|
|
394
603
|
value: SDK.RemoteObject.RemoteObject, wasThrown: boolean, showPreview: boolean,
|
|
395
|
-
linkifier?: Components.Linkifier.Linkifier, isSyntheticProperty = false,
|
|
396
|
-
|
|
397
|
-
let propertyValue;
|
|
604
|
+
linkifier?: Components.Linkifier.Linkifier, isSyntheticProperty = false, variableName?: string): HTMLElement {
|
|
605
|
+
let propertyValue: HTMLElement;
|
|
398
606
|
const type = value.type;
|
|
399
607
|
const subtype = value.subtype;
|
|
400
608
|
const description = value.description || '';
|
|
@@ -403,31 +611,31 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
|
|
|
403
611
|
const rawLocation = value.debuggerModel().createRawLocationByScriptId(
|
|
404
612
|
value.value.scriptId, value.value.lineNumber, value.value.columnNumber);
|
|
405
613
|
if (rawLocation && linkifier) {
|
|
406
|
-
return
|
|
614
|
+
return linkifier.linkifyRawLocation(rawLocation, Platform.DevToolsPath.EmptyUrlString);
|
|
407
615
|
}
|
|
408
|
-
propertyValue =
|
|
616
|
+
propertyValue = createUnknownInternalLocationElement();
|
|
409
617
|
} else if (type === 'string' && typeof description === 'string') {
|
|
410
618
|
propertyValue = createStringElement();
|
|
411
619
|
} else if (type === 'object' && subtype === 'trustedtype') {
|
|
412
620
|
propertyValue = createTrustedTypeElement();
|
|
413
621
|
} else if (type === 'function') {
|
|
414
|
-
propertyValue =
|
|
622
|
+
propertyValue = ObjectPropertiesSection.valueElementForFunctionDescription(description);
|
|
415
623
|
} else if (type === 'object' && subtype === 'node' && description) {
|
|
416
|
-
propertyValue =
|
|
624
|
+
propertyValue = createNodeElement();
|
|
417
625
|
} else {
|
|
418
626
|
const valueElement = document.createElement('span');
|
|
419
627
|
valueElement.classList.add('object-value-' + (subtype || type));
|
|
420
628
|
if (value.preview && showPreview) {
|
|
421
629
|
const previewFormatter = new RemoteObjectPreviewFormatter();
|
|
422
630
|
previewFormatter.appendObjectPreview(valueElement, value.preview, false /* isEntry */);
|
|
423
|
-
propertyValue =
|
|
424
|
-
UI.Tooltip.Tooltip.install(propertyValue
|
|
631
|
+
propertyValue = valueElement;
|
|
632
|
+
UI.Tooltip.Tooltip.install(propertyValue as HTMLElement, description || '');
|
|
425
633
|
} else if (description.length > maxRenderableStringLength) {
|
|
426
|
-
propertyValue = new ExpandableTextPropertyValue(valueElement, description, EXPANDABLE_MAX_LENGTH);
|
|
634
|
+
propertyValue = new ExpandableTextPropertyValue(valueElement, description, EXPANDABLE_MAX_LENGTH).element;
|
|
427
635
|
} else {
|
|
428
|
-
propertyValue =
|
|
429
|
-
propertyValue.
|
|
430
|
-
UI.Tooltip.Tooltip.install(propertyValue
|
|
636
|
+
propertyValue = valueElement;
|
|
637
|
+
propertyValue.textContent = description;
|
|
638
|
+
UI.Tooltip.Tooltip.install(propertyValue as HTMLElement, description);
|
|
431
639
|
}
|
|
432
640
|
if (!isSyntheticProperty) {
|
|
433
641
|
this.appendMemoryIcon(valueElement, value, variableName);
|
|
@@ -438,54 +646,53 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
|
|
|
438
646
|
const wrapperElement = document.createElement('span');
|
|
439
647
|
wrapperElement.classList.add('error');
|
|
440
648
|
wrapperElement.classList.add('value');
|
|
441
|
-
wrapperElement.appendChild(
|
|
442
|
-
|
|
443
|
-
propertyValue.element = wrapperElement;
|
|
649
|
+
wrapperElement.appendChild(uiI18n.getFormatLocalizedString(str_, UIStrings.exceptionS, {PH1: propertyValue}));
|
|
650
|
+
propertyValue = wrapperElement;
|
|
444
651
|
}
|
|
445
|
-
propertyValue.
|
|
652
|
+
propertyValue.classList.add('value');
|
|
446
653
|
return propertyValue;
|
|
447
654
|
|
|
448
|
-
function createUnknownInternalLocationElement():
|
|
655
|
+
function createUnknownInternalLocationElement(): HTMLElement {
|
|
449
656
|
const valueElement = document.createElement('span');
|
|
450
657
|
valueElement.textContent = '<' + i18nString(UIStrings.unknown) + '>';
|
|
451
658
|
UI.Tooltip.Tooltip.install(valueElement, description || '');
|
|
452
659
|
return valueElement;
|
|
453
660
|
}
|
|
454
661
|
|
|
455
|
-
function createStringElement():
|
|
662
|
+
function createStringElement(): HTMLElement {
|
|
456
663
|
const valueElement = document.createElement('span');
|
|
457
664
|
valueElement.classList.add('object-value-string');
|
|
458
665
|
const text = JSON.stringify(description);
|
|
459
|
-
let propertyValue;
|
|
666
|
+
let propertyValue: HTMLElement;
|
|
460
667
|
if (description.length > maxRenderableStringLength) {
|
|
461
|
-
propertyValue = new ExpandableTextPropertyValue(valueElement, text, EXPANDABLE_MAX_LENGTH);
|
|
668
|
+
propertyValue = new ExpandableTextPropertyValue(valueElement, text, EXPANDABLE_MAX_LENGTH).element;
|
|
462
669
|
} else {
|
|
463
670
|
UI.UIUtils.createTextChild(valueElement, text);
|
|
464
|
-
propertyValue =
|
|
671
|
+
propertyValue = valueElement;
|
|
465
672
|
UI.Tooltip.Tooltip.install(valueElement, description);
|
|
466
673
|
}
|
|
467
674
|
return propertyValue;
|
|
468
675
|
}
|
|
469
676
|
|
|
470
|
-
function createTrustedTypeElement():
|
|
677
|
+
function createTrustedTypeElement(): HTMLElement {
|
|
471
678
|
const valueElement = document.createElement('span');
|
|
472
679
|
valueElement.classList.add('object-value-trustedtype');
|
|
473
680
|
const text = `${className} "${description}"`;
|
|
474
681
|
let propertyValue;
|
|
475
682
|
if (text.length > maxRenderableStringLength) {
|
|
476
|
-
propertyValue = new ExpandableTextPropertyValue(valueElement, text, EXPANDABLE_MAX_LENGTH);
|
|
683
|
+
propertyValue = new ExpandableTextPropertyValue(valueElement, text, EXPANDABLE_MAX_LENGTH).element;
|
|
477
684
|
} else {
|
|
478
685
|
const contentString = createStringElement();
|
|
479
686
|
UI.UIUtils.createTextChild(valueElement, `${className} `);
|
|
480
|
-
valueElement.appendChild(contentString
|
|
481
|
-
propertyValue =
|
|
687
|
+
valueElement.appendChild(contentString);
|
|
688
|
+
propertyValue = valueElement;
|
|
482
689
|
UI.Tooltip.Tooltip.install(valueElement, text);
|
|
483
690
|
}
|
|
484
691
|
|
|
485
692
|
return propertyValue;
|
|
486
693
|
}
|
|
487
694
|
|
|
488
|
-
function createNodeElement():
|
|
695
|
+
function createNodeElement(): HTMLElement {
|
|
489
696
|
const valueElement = document.createElement('span');
|
|
490
697
|
valueElement.classList.add('object-value-node');
|
|
491
698
|
createSpansForNodeTitle(valueElement, (description));
|
|
@@ -558,8 +765,8 @@ export class ObjectPropertiesSection extends UI.TreeOutline.TreeOutlineInShadow
|
|
|
558
765
|
|
|
559
766
|
private contextMenuEventFired(event: Event): void {
|
|
560
767
|
const contextMenu = new UI.ContextMenu.ContextMenu(event);
|
|
561
|
-
contextMenu.appendApplicableItems(this.
|
|
562
|
-
if (this.object instanceof SDK.RemoteObject.LocalJSONObject) {
|
|
768
|
+
contextMenu.appendApplicableItems(this.root);
|
|
769
|
+
if (this.root.object instanceof SDK.RemoteObject.LocalJSONObject) {
|
|
563
770
|
contextMenu.viewSection().appendItem(
|
|
564
771
|
i18nString(UIStrings.expandRecursively),
|
|
565
772
|
this.#objectTreeElement.expandRecursively.bind(this.#objectTreeElement, EXPANDABLE_MAX_DEPTH),
|
|
@@ -604,27 +811,17 @@ export const enum ObjectPropertiesMode {
|
|
|
604
811
|
}
|
|
605
812
|
|
|
606
813
|
export class RootElement extends UI.TreeOutline.TreeElement {
|
|
607
|
-
private readonly object:
|
|
814
|
+
private readonly object: ObjectTree;
|
|
608
815
|
private readonly linkifier: Components.Linkifier.Linkifier|undefined;
|
|
609
816
|
private readonly emptyPlaceholder: string|null|undefined;
|
|
610
|
-
private readonly propertiesMode: ObjectPropertiesMode;
|
|
611
|
-
private readonly extraProperties: SDK.RemoteObject.RemoteObjectProperty[];
|
|
612
|
-
private readonly targetObject: SDK.RemoteObject.RemoteObject|undefined;
|
|
613
817
|
override toggleOnClick: boolean;
|
|
614
|
-
constructor(
|
|
615
|
-
object: SDK.RemoteObject.RemoteObject, linkifier?: Components.Linkifier.Linkifier, emptyPlaceholder?: string|null,
|
|
616
|
-
propertiesMode: ObjectPropertiesMode = ObjectPropertiesMode.OWN_AND_INTERNAL_AND_INHERITED,
|
|
617
|
-
extraProperties: SDK.RemoteObject.RemoteObjectProperty[] = [],
|
|
618
|
-
targetObject: SDK.RemoteObject.RemoteObject = object) {
|
|
818
|
+
constructor(object: ObjectTree, linkifier?: Components.Linkifier.Linkifier, emptyPlaceholder?: string|null) {
|
|
619
819
|
const contentElement = document.createElement('slot');
|
|
620
820
|
super(contentElement);
|
|
621
821
|
|
|
622
822
|
this.object = object;
|
|
623
823
|
this.linkifier = linkifier;
|
|
624
824
|
this.emptyPlaceholder = emptyPlaceholder;
|
|
625
|
-
this.propertiesMode = propertiesMode;
|
|
626
|
-
this.extraProperties = extraProperties;
|
|
627
|
-
this.targetObject = targetObject;
|
|
628
825
|
|
|
629
826
|
this.setExpandable(true);
|
|
630
827
|
this.selectable = true;
|
|
@@ -651,7 +848,7 @@ export class RootElement extends UI.TreeOutline.TreeElement {
|
|
|
651
848
|
|
|
652
849
|
private onContextMenu(event: Event): void {
|
|
653
850
|
const contextMenu = new UI.ContextMenu.ContextMenu(event);
|
|
654
|
-
contextMenu.appendApplicableItems(this.object);
|
|
851
|
+
contextMenu.appendApplicableItems(this.object.object);
|
|
655
852
|
|
|
656
853
|
if (this.object instanceof SDK.RemoteObject.LocalJSONObject) {
|
|
657
854
|
const {value} = this.object;
|
|
@@ -676,8 +873,7 @@ export class RootElement extends UI.TreeOutline.TreeElement {
|
|
|
676
873
|
const treeOutline = (this.treeOutline as ObjectPropertiesSection | null);
|
|
677
874
|
const skipProto = treeOutline ? Boolean(treeOutline.skipProtoInternal) : false;
|
|
678
875
|
return await ObjectPropertyTreeElement.populate(
|
|
679
|
-
this, this.object, skipProto, false, this.linkifier, this.emptyPlaceholder
|
|
680
|
-
this.extraProperties, this.targetObject);
|
|
876
|
+
this, this.object, skipProto, false, this.linkifier, this.emptyPlaceholder);
|
|
681
877
|
}
|
|
682
878
|
}
|
|
683
879
|
|
|
@@ -688,7 +884,7 @@ export class RootElement extends UI.TreeOutline.TreeElement {
|
|
|
688
884
|
export const InitialVisibleChildrenLimit = 200;
|
|
689
885
|
|
|
690
886
|
export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
691
|
-
property:
|
|
887
|
+
property: ObjectTreeNode;
|
|
692
888
|
override toggleOnClick: boolean;
|
|
693
889
|
private highlightChanges: UI.UIUtils.HighlightChange[];
|
|
694
890
|
private linkifier: Components.Linkifier.Linkifier|undefined;
|
|
@@ -699,9 +895,9 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
699
895
|
readOnly!: boolean;
|
|
700
896
|
private prompt!: ObjectPropertyPrompt|undefined;
|
|
701
897
|
private editableDiv!: HTMLElement;
|
|
702
|
-
propertyValue?:
|
|
898
|
+
propertyValue?: HTMLElement;
|
|
703
899
|
expandedValueElement?: Element|null;
|
|
704
|
-
constructor(property:
|
|
900
|
+
constructor(property: ObjectTreeNode, linkifier?: Components.Linkifier.Linkifier) {
|
|
705
901
|
// Pass an empty title, the title gets made later in onattach.
|
|
706
902
|
super();
|
|
707
903
|
|
|
@@ -716,52 +912,30 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
716
912
|
}
|
|
717
913
|
|
|
718
914
|
static async populate(
|
|
719
|
-
treeElement: UI.TreeOutline.TreeElement,
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
case ObjectPropertiesMode.ALL:
|
|
733
|
-
({properties} = await value.getAllProperties(false /* accessorPropertiesOnly */, true /* generatePreview */));
|
|
734
|
-
break;
|
|
735
|
-
case ObjectPropertiesMode.OWN_AND_INTERNAL_AND_INHERITED:
|
|
736
|
-
({properties, internalProperties} =
|
|
737
|
-
await SDK.RemoteObject.RemoteObject.loadFromObjectPerProto(value, true /* generatePreview */));
|
|
738
|
-
break;
|
|
739
|
-
}
|
|
740
|
-
treeElement.removeChildren();
|
|
741
|
-
if (!properties) {
|
|
742
|
-
return;
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
if (extraProperties !== undefined) {
|
|
746
|
-
properties.push(...extraProperties);
|
|
915
|
+
treeElement: UI.TreeOutline.TreeElement,
|
|
916
|
+
value: ObjectTreeNodeBase,
|
|
917
|
+
skipProto: boolean,
|
|
918
|
+
skipGettersAndSetters: boolean,
|
|
919
|
+
linkifier?: Components.Linkifier.Linkifier,
|
|
920
|
+
emptyPlaceholder?: string|null,
|
|
921
|
+
): Promise<void> {
|
|
922
|
+
const properties = await value.children();
|
|
923
|
+
if (properties.arrayRanges) {
|
|
924
|
+
await ArrayGroupingTreeElement.populate(treeElement, properties, linkifier);
|
|
925
|
+
} else {
|
|
926
|
+
ObjectPropertyTreeElement.populateWithProperties(
|
|
927
|
+
treeElement, properties, skipProto, skipGettersAndSetters, linkifier, emptyPlaceholder);
|
|
747
928
|
}
|
|
748
|
-
|
|
749
|
-
ObjectPropertyTreeElement.populateWithProperties(
|
|
750
|
-
treeElement, properties, internalProperties, skipProto, skipGettersAndSetters, targetValue || value, linkifier,
|
|
751
|
-
emptyPlaceholder);
|
|
752
929
|
}
|
|
753
930
|
|
|
754
931
|
static populateWithProperties(
|
|
755
|
-
treeNode: UI.TreeOutline.TreeElement, properties:
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
const entriesProperty = internalProperties.find(property => property.name === '[[Entries]]');
|
|
932
|
+
treeNode: UI.TreeOutline.TreeElement, {properties, internalProperties}: NodeChildren, skipProto: boolean,
|
|
933
|
+
skipGettersAndSetters: boolean, linkifier?: Components.Linkifier.Linkifier,
|
|
934
|
+
emptyPlaceholder?: string|null): void {
|
|
935
|
+
properties?.sort(ObjectPropertiesSection.compareProperties);
|
|
936
|
+
|
|
937
|
+
const entriesProperty = internalProperties?.find(({property}) => property.name === '[[Entries]]');
|
|
763
938
|
if (entriesProperty) {
|
|
764
|
-
parentMap.set(entriesProperty, value);
|
|
765
939
|
const treeElement = new ObjectPropertyTreeElement(entriesProperty, linkifier);
|
|
766
940
|
treeElement.setExpandable(true);
|
|
767
941
|
treeElement.expand();
|
|
@@ -769,34 +943,30 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
769
943
|
}
|
|
770
944
|
|
|
771
945
|
const tailProperties = [];
|
|
772
|
-
for (
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
|
|
776
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
777
|
-
if (!ObjectPropertiesSection.isDisplayableProperty(property, (treeNode as any).property)) {
|
|
946
|
+
for (const property of properties ?? []) {
|
|
947
|
+
if (treeNode instanceof ObjectPropertyTreeElement &&
|
|
948
|
+
!ObjectPropertiesSection.isDisplayableProperty(property.property, treeNode.property?.property)) {
|
|
778
949
|
continue;
|
|
779
950
|
}
|
|
780
951
|
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
tailProperties.push(getterProperty);
|
|
952
|
+
// FIXME move into node
|
|
953
|
+
if (property.property.isOwn && !skipGettersAndSetters) {
|
|
954
|
+
if (property.property.getter) {
|
|
955
|
+
const getterProperty = new SDK.RemoteObject.RemoteObjectProperty(
|
|
956
|
+
'get ' + property.property.name, property.property.getter, false);
|
|
957
|
+
tailProperties.push(new ObjectTreeNode(getterProperty, property.propertiesMode, property.parent));
|
|
787
958
|
}
|
|
788
|
-
if (property.setter) {
|
|
789
|
-
const setterProperty =
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
tailProperties.push(setterProperty);
|
|
959
|
+
if (property.property.setter) {
|
|
960
|
+
const setterProperty = new SDK.RemoteObject.RemoteObjectProperty(
|
|
961
|
+
'set ' + property.property.name, property.property.setter, false);
|
|
962
|
+
tailProperties.push(new ObjectTreeNode(setterProperty, property.propertiesMode, property.parent));
|
|
793
963
|
}
|
|
794
964
|
}
|
|
795
965
|
|
|
796
|
-
const canShowProperty = property.getter || !property.isAccessorProperty();
|
|
966
|
+
const canShowProperty = property.property.getter || !property.property.isAccessorProperty();
|
|
797
967
|
if (canShowProperty) {
|
|
798
968
|
const element = new ObjectPropertyTreeElement(property, linkifier);
|
|
799
|
-
if (property.name === 'memories' && property.
|
|
969
|
+
if (property.property.name === 'memories' && property.object?.className === 'Memories') {
|
|
800
970
|
element.updateExpandable();
|
|
801
971
|
if (element.isExpandable()) {
|
|
802
972
|
element.expand();
|
|
@@ -809,13 +979,12 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
809
979
|
treeNode.appendChild(new ObjectPropertyTreeElement(tailProperties[i], linkifier));
|
|
810
980
|
}
|
|
811
981
|
|
|
812
|
-
for (const property of internalProperties) {
|
|
813
|
-
parentMap.set(property, value);
|
|
982
|
+
for (const property of internalProperties ?? []) {
|
|
814
983
|
const treeElement = new ObjectPropertyTreeElement(property, linkifier);
|
|
815
|
-
if (property.name === '[[Entries]]') {
|
|
984
|
+
if (property.property.name === '[[Entries]]') {
|
|
816
985
|
continue;
|
|
817
986
|
}
|
|
818
|
-
if (property.name === '[[Prototype]]' && skipProto) {
|
|
987
|
+
if (property.property.name === '[[Prototype]]' && skipProto) {
|
|
819
988
|
continue;
|
|
820
989
|
}
|
|
821
990
|
treeNode.appendChild(treeElement);
|
|
@@ -877,8 +1046,8 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
877
1046
|
this.revertHighlightChanges();
|
|
878
1047
|
|
|
879
1048
|
this.applySearch(regex, this.nameElement, cssClasses);
|
|
880
|
-
if (this.property.
|
|
881
|
-
const valueType = this.property.
|
|
1049
|
+
if (this.property.object) {
|
|
1050
|
+
const valueType = this.property.object.type;
|
|
882
1051
|
if (valueType !== 'object') {
|
|
883
1052
|
this.applySearch(regex, this.valueElement, cssClasses);
|
|
884
1053
|
}
|
|
@@ -929,14 +1098,13 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
929
1098
|
}
|
|
930
1099
|
|
|
931
1100
|
override async onpopulate(): Promise<void> {
|
|
932
|
-
const propertyValue = (this.property.value as SDK.RemoteObject.RemoteObject);
|
|
933
|
-
console.assert(typeof propertyValue !== 'undefined');
|
|
934
1101
|
const treeOutline = (this.treeOutline as ObjectPropertiesSection | null);
|
|
935
1102
|
const skipProto = treeOutline ? Boolean(treeOutline.skipProtoInternal) : false;
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
1103
|
+
this.removeChildren();
|
|
1104
|
+
this.property.removeChildren();
|
|
1105
|
+
|
|
1106
|
+
if (this.property.object) {
|
|
1107
|
+
await ObjectPropertyTreeElement.populate(this, this.property, skipProto, false, this.linkifier);
|
|
940
1108
|
if (this.childCount() > this.maxNumPropertiesToShow) {
|
|
941
1109
|
this.createShowAllPropertiesButton();
|
|
942
1110
|
}
|
|
@@ -947,16 +1115,16 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
947
1115
|
const target = (event.target as HTMLElement);
|
|
948
1116
|
const inEditableElement = target.isSelfOrDescendant(this.valueElement) ||
|
|
949
1117
|
(this.expandedValueElement && target.isSelfOrDescendant(this.expandedValueElement));
|
|
950
|
-
if (this.property.
|
|
951
|
-
(this.property.writable || this.property.setter)) {
|
|
1118
|
+
if (this.property.object && !this.property.object.customPreview() && inEditableElement &&
|
|
1119
|
+
(this.property.property.writable || this.property.property.setter)) {
|
|
952
1120
|
this.startEditing();
|
|
953
1121
|
}
|
|
954
1122
|
return false;
|
|
955
1123
|
}
|
|
956
1124
|
|
|
957
1125
|
override onenter(): boolean {
|
|
958
|
-
if (this.property.
|
|
959
|
-
(this.property.writable || this.property.setter)) {
|
|
1126
|
+
if (this.property.object && !this.property.object.customPreview() &&
|
|
1127
|
+
(this.property.property.writable || this.property.property.setter)) {
|
|
960
1128
|
this.startEditing();
|
|
961
1129
|
return true;
|
|
962
1130
|
}
|
|
@@ -1011,46 +1179,47 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
1011
1179
|
|
|
1012
1180
|
update(): void {
|
|
1013
1181
|
this.nameElement =
|
|
1014
|
-
(ObjectPropertiesSection.createNameElement(this.property.name, this.property.private) as HTMLElement);
|
|
1015
|
-
if (!this.property.enumerable) {
|
|
1182
|
+
(ObjectPropertiesSection.createNameElement(this.property.name, this.property.property.private) as HTMLElement);
|
|
1183
|
+
if (!this.property.property.enumerable) {
|
|
1016
1184
|
this.nameElement.classList.add('object-properties-section-dimmed');
|
|
1017
1185
|
}
|
|
1018
|
-
if (this.property.isOwn) {
|
|
1186
|
+
if (this.property.property.isOwn) {
|
|
1019
1187
|
this.nameElement.classList.add('own-property');
|
|
1020
1188
|
}
|
|
1021
|
-
if (this.property.synthetic) {
|
|
1189
|
+
if (this.property.property.synthetic) {
|
|
1022
1190
|
this.nameElement.classList.add('synthetic-property');
|
|
1023
1191
|
}
|
|
1024
1192
|
|
|
1025
1193
|
this.updatePropertyPath();
|
|
1026
1194
|
|
|
1027
|
-
const isInternalEntries = this.property.synthetic && this.property.name === '[[Entries]]';
|
|
1195
|
+
const isInternalEntries = this.property.property.synthetic && this.property.name === '[[Entries]]';
|
|
1028
1196
|
if (isInternalEntries) {
|
|
1029
1197
|
this.valueElement = document.createElement('span');
|
|
1030
1198
|
this.valueElement.classList.add('value');
|
|
1031
|
-
} else if (this.property.
|
|
1199
|
+
} else if (this.property.object) {
|
|
1032
1200
|
const showPreview = this.property.name !== '[[Prototype]]';
|
|
1033
1201
|
this.propertyValue = ObjectPropertiesSection.createPropertyValueWithCustomSupport(
|
|
1034
|
-
this.property.
|
|
1035
|
-
this.path() /* variableName */);
|
|
1036
|
-
this.valueElement =
|
|
1037
|
-
} else if (this.property.getter) {
|
|
1202
|
+
this.property.object, this.property.property.wasThrown, showPreview, this.linkifier,
|
|
1203
|
+
this.property.property.synthetic, this.path() /* variableName */);
|
|
1204
|
+
this.valueElement = this.propertyValue;
|
|
1205
|
+
} else if (this.property.property.getter) {
|
|
1038
1206
|
this.valueElement = document.createElement('span');
|
|
1039
1207
|
const element = this.valueElement.createChild('span');
|
|
1040
1208
|
element.textContent = i18nString(UIStrings.dots);
|
|
1041
1209
|
element.classList.add('object-value-calculate-value-button');
|
|
1042
1210
|
UI.Tooltip.Tooltip.install(element, i18nString(UIStrings.invokePropertyGetter));
|
|
1043
|
-
const
|
|
1044
|
-
const getter = this.property.getter;
|
|
1211
|
+
const getter = this.property.property.getter;
|
|
1045
1212
|
element.addEventListener('click', (event: Event) => {
|
|
1046
1213
|
event.consume();
|
|
1047
1214
|
const invokeGetter = `
|
|
1048
1215
|
function invokeGetter(getter) {
|
|
1049
1216
|
return Reflect.apply(getter, this, []);
|
|
1050
1217
|
}`;
|
|
1051
|
-
// @ts-expect-error No way to teach TypeScript to preserve the Function-ness of `getter`.
|
|
1052
1218
|
// Also passing a string instead of a Function to avoid coverage implementation messing with it.
|
|
1053
|
-
void
|
|
1219
|
+
void this.property.parent
|
|
1220
|
+
?.object
|
|
1221
|
+
// @ts-expect-error No way to teach TypeScript to preserve the Function-ness of `getter`.
|
|
1222
|
+
?.callFunction(invokeGetter, [SDK.RemoteObject.RemoteObject.toCallArgument(getter)])
|
|
1054
1223
|
.then(this.onInvokeGetterClick.bind(this));
|
|
1055
1224
|
}, false);
|
|
1056
1225
|
} else {
|
|
@@ -1061,8 +1230,9 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
1061
1230
|
}
|
|
1062
1231
|
|
|
1063
1232
|
const valueText = this.valueElement.textContent;
|
|
1064
|
-
if (this.property.
|
|
1065
|
-
this.expandedValueElement =
|
|
1233
|
+
if (this.property.object && valueText && !this.property.property.wasThrown) {
|
|
1234
|
+
this.expandedValueElement =
|
|
1235
|
+
this.createExpandedValueElement(this.property.object, this.property.property.synthetic);
|
|
1066
1236
|
}
|
|
1067
1237
|
|
|
1068
1238
|
const adorner: Element|string = '';
|
|
@@ -1091,7 +1261,7 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
1091
1261
|
|
|
1092
1262
|
const name = this.property.name;
|
|
1093
1263
|
|
|
1094
|
-
if (this.property.synthetic) {
|
|
1264
|
+
if (this.property.property.synthetic) {
|
|
1095
1265
|
UI.Tooltip.Tooltip.install(this.nameElement, name);
|
|
1096
1266
|
return;
|
|
1097
1267
|
}
|
|
@@ -1101,11 +1271,11 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
1101
1271
|
const isInteger = /^(?:0|[1-9]\d*)$/;
|
|
1102
1272
|
|
|
1103
1273
|
const parentPath = (this.parent instanceof ObjectPropertyTreeElement && this.parent.nameElement &&
|
|
1104
|
-
!this.parent.property.synthetic) ?
|
|
1274
|
+
!this.parent.property.property.synthetic) ?
|
|
1105
1275
|
this.parent.nameElement.title :
|
|
1106
1276
|
'';
|
|
1107
1277
|
|
|
1108
|
-
if (this.property.private || useDotNotation.test(name)) {
|
|
1278
|
+
if (this.property.property.private || useDotNotation.test(name)) {
|
|
1109
1279
|
UI.Tooltip.Tooltip.install(this.nameElement, parentPath ? `${parentPath}.${name}` : name);
|
|
1110
1280
|
} else if (isInteger.test(name)) {
|
|
1111
1281
|
UI.Tooltip.Tooltip.install(this.nameElement, `${parentPath}[${name}]`);
|
|
@@ -1114,17 +1284,17 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
1114
1284
|
}
|
|
1115
1285
|
}
|
|
1116
1286
|
|
|
1117
|
-
|
|
1287
|
+
getContextMenu(event: Event): UI.ContextMenu.ContextMenu {
|
|
1118
1288
|
const contextMenu = new UI.ContextMenu.ContextMenu(event);
|
|
1119
1289
|
contextMenu.appendApplicableItems(this);
|
|
1120
|
-
if (this.property.symbol) {
|
|
1121
|
-
contextMenu.appendApplicableItems(this.property.symbol);
|
|
1122
|
-
}
|
|
1123
|
-
if (this.property.
|
|
1124
|
-
contextMenu.appendApplicableItems(this.property.
|
|
1125
|
-
if (
|
|
1126
|
-
const
|
|
1127
|
-
|
|
1290
|
+
if (this.property.property.symbol) {
|
|
1291
|
+
contextMenu.appendApplicableItems(this.property.property.symbol);
|
|
1292
|
+
}
|
|
1293
|
+
if (this.property.object) {
|
|
1294
|
+
contextMenu.appendApplicableItems(this.property.object);
|
|
1295
|
+
if (this.property.parent?.object instanceof SDK.RemoteObject.LocalJSONObject) {
|
|
1296
|
+
const propertyValue = typeof this.property.object === 'object' ? JSON.stringify(this.property.object, null, 2) :
|
|
1297
|
+
this.property.object;
|
|
1128
1298
|
const copyValueHandler = (): void => {
|
|
1129
1299
|
Host.userMetrics.actionTaken(Host.UserMetrics.Action.NetworkPanelCopyValue);
|
|
1130
1300
|
Host.InspectorFrontendHost.InspectorFrontendHostInstance.copyText((propertyValue as string | undefined));
|
|
@@ -1133,13 +1303,13 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
1133
1303
|
i18nString(UIStrings.copyValue), copyValueHandler, {jslogContext: 'copy-value'});
|
|
1134
1304
|
}
|
|
1135
1305
|
}
|
|
1136
|
-
if (!this.property.synthetic && this.nameElement?.title) {
|
|
1306
|
+
if (!this.property.property.synthetic && this.nameElement?.title) {
|
|
1137
1307
|
const copyPathHandler = Host.InspectorFrontendHost.InspectorFrontendHostInstance.copyText.bind(
|
|
1138
1308
|
Host.InspectorFrontendHost.InspectorFrontendHostInstance, this.nameElement.title);
|
|
1139
1309
|
contextMenu.clipboardSection().appendItem(
|
|
1140
1310
|
i18nString(UIStrings.copyPropertyPath), copyPathHandler, {jslogContext: 'copy-property-path'});
|
|
1141
1311
|
}
|
|
1142
|
-
if (
|
|
1312
|
+
if (this.property.parent?.object instanceof SDK.RemoteObject.LocalJSONObject) {
|
|
1143
1313
|
contextMenu.viewSection().appendItem(
|
|
1144
1314
|
i18nString(UIStrings.expandRecursively), this.expandRecursively.bind(this, EXPANDABLE_MAX_DEPTH),
|
|
1145
1315
|
{jslogContext: 'expand-recursively'});
|
|
@@ -1147,9 +1317,11 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
1147
1317
|
i18nString(UIStrings.collapseChildren), this.collapseChildren.bind(this),
|
|
1148
1318
|
{jslogContext: 'collapse-children'});
|
|
1149
1319
|
}
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1320
|
+
return contextMenu;
|
|
1321
|
+
}
|
|
1322
|
+
|
|
1323
|
+
private contextMenuFired(event: Event): void {
|
|
1324
|
+
const contextMenu = this.getContextMenu(event);
|
|
1153
1325
|
void contextMenu.show();
|
|
1154
1326
|
}
|
|
1155
1327
|
|
|
@@ -1160,9 +1332,9 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
1160
1332
|
}
|
|
1161
1333
|
this.editableDiv = this.rowContainer.createChild('span', 'editable-div');
|
|
1162
1334
|
|
|
1163
|
-
if (this.property.
|
|
1164
|
-
let text: string|(string | undefined) = this.property.
|
|
1165
|
-
if (this.property.
|
|
1335
|
+
if (this.property.object) {
|
|
1336
|
+
let text: string|(string | undefined) = this.property.object.description;
|
|
1337
|
+
if (this.property.object.type === 'string' && typeof text === 'string') {
|
|
1166
1338
|
text = `"${text}"`;
|
|
1167
1339
|
}
|
|
1168
1340
|
|
|
@@ -1233,13 +1405,13 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
1233
1405
|
}
|
|
1234
1406
|
|
|
1235
1407
|
private async applyExpression(expression: string): Promise<void> {
|
|
1236
|
-
const property = SDK.RemoteObject.RemoteObject.toCallArgument(this.property.symbol || this.property.name);
|
|
1408
|
+
const property = SDK.RemoteObject.RemoteObject.toCallArgument(this.property.property.symbol || this.property.name);
|
|
1237
1409
|
expression = JavaScriptREPL.wrapObjectLiteral(expression.trim());
|
|
1238
1410
|
|
|
1239
|
-
if (this.property.synthetic) {
|
|
1411
|
+
if (this.property.property.synthetic) {
|
|
1240
1412
|
let invalidate = false;
|
|
1241
1413
|
if (expression) {
|
|
1242
|
-
invalidate = await this.property.setSyntheticValue(expression);
|
|
1414
|
+
invalidate = await this.property.property.setSyntheticValue(expression);
|
|
1243
1415
|
}
|
|
1244
1416
|
if (invalidate) {
|
|
1245
1417
|
const parent = this.parent;
|
|
@@ -1253,7 +1425,7 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
1253
1425
|
return;
|
|
1254
1426
|
}
|
|
1255
1427
|
|
|
1256
|
-
const parentObject =
|
|
1428
|
+
const parentObject = this.property.parent?.object as SDK.RemoteObject.RemoteObject;
|
|
1257
1429
|
const errorPromise =
|
|
1258
1430
|
expression ? parentObject.setPropertyValue(property, expression) : parentObject.deleteProperty(property);
|
|
1259
1431
|
const error = await errorPromise;
|
|
@@ -1265,11 +1437,13 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
1265
1437
|
if (!expression) {
|
|
1266
1438
|
// The property was deleted, so remove this tree element.
|
|
1267
1439
|
this.parent?.removeChild(this);
|
|
1440
|
+
this.property.parent?.removeChild(this.property);
|
|
1268
1441
|
} else {
|
|
1269
1442
|
// Call updateSiblings since their value might be based on the value that just changed.
|
|
1270
1443
|
const parent = this.parent;
|
|
1271
1444
|
if (parent) {
|
|
1272
1445
|
parent.invalidateChildren();
|
|
1446
|
+
this.property.parent?.removeChildren();
|
|
1273
1447
|
void parent.onpopulate();
|
|
1274
1448
|
}
|
|
1275
1449
|
}
|
|
@@ -1279,8 +1453,8 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
1279
1453
|
if (!result.object) {
|
|
1280
1454
|
return;
|
|
1281
1455
|
}
|
|
1282
|
-
this.property.value = result.object;
|
|
1283
|
-
this.property.wasThrown = result.wasThrown || false;
|
|
1456
|
+
this.property.property.value = result.object;
|
|
1457
|
+
this.property.property.wasThrown = result.wasThrown || false;
|
|
1284
1458
|
|
|
1285
1459
|
this.update();
|
|
1286
1460
|
this.invalidateChildren();
|
|
@@ -1288,9 +1462,10 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
1288
1462
|
}
|
|
1289
1463
|
|
|
1290
1464
|
private updateExpandable(): void {
|
|
1291
|
-
if (this.property.
|
|
1465
|
+
if (this.property.object) {
|
|
1292
1466
|
this.setExpandable(
|
|
1293
|
-
!this.property.
|
|
1467
|
+
!this.property.object.customPreview() && this.property.object.hasChildren &&
|
|
1468
|
+
!this.property.property.wasThrown);
|
|
1294
1469
|
} else {
|
|
1295
1470
|
this.setExpandable(false);
|
|
1296
1471
|
}
|
|
@@ -1301,249 +1476,185 @@ export class ObjectPropertyTreeElement extends UI.TreeOutline.TreeElement {
|
|
|
1301
1476
|
}
|
|
1302
1477
|
}
|
|
1303
1478
|
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
object: SDK.RemoteObject.RemoteObject, fromIndex: number, toIndex: number, propertyCount: number,
|
|
1313
|
-
linkifier?: Components.Linkifier.Linkifier) {
|
|
1314
|
-
super(Platform.StringUtilities.sprintf('[%d … %d]', fromIndex, toIndex), true);
|
|
1315
|
-
this.toggleOnClick = true;
|
|
1316
|
-
this.fromIndex = fromIndex;
|
|
1317
|
-
this.toIndex = toIndex;
|
|
1318
|
-
this.object = object;
|
|
1319
|
-
this.propertyCount = propertyCount;
|
|
1320
|
-
this.linkifier = linkifier;
|
|
1321
|
-
}
|
|
1322
|
-
|
|
1323
|
-
static async populateArray(
|
|
1324
|
-
treeNode: UI.TreeOutline.TreeElement, object: SDK.RemoteObject.RemoteObject, fromIndex: number, toIndex: number,
|
|
1325
|
-
linkifier?: Components.Linkifier.Linkifier): Promise<void> {
|
|
1326
|
-
await ArrayGroupingTreeElement.populateRanges(treeNode, object, fromIndex, toIndex, true, linkifier);
|
|
1327
|
-
}
|
|
1479
|
+
async function arrayRangeGroups(object: SDK.RemoteObject.RemoteObject, fromIndex: number, toIndex: number):
|
|
1480
|
+
Promise<{ranges: number[][]}|null|undefined> {
|
|
1481
|
+
return await object.callFunctionJSON(packArrayRanges, [
|
|
1482
|
+
{value: fromIndex},
|
|
1483
|
+
{value: toIndex},
|
|
1484
|
+
{value: ArrayGroupingTreeElement.bucketThreshold},
|
|
1485
|
+
{value: ArrayGroupingTreeElement.sparseIterationThreshold},
|
|
1486
|
+
]);
|
|
1328
1487
|
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1488
|
+
/**
|
|
1489
|
+
* This function is called on the RemoteObject.
|
|
1490
|
+
* Note: must declare params as optional.
|
|
1491
|
+
*/
|
|
1492
|
+
function packArrayRanges(
|
|
1493
|
+
this: Object, fromIndex?: number, toIndex?: number, bucketThreshold?: number,
|
|
1494
|
+
sparseIterationThreshold?: number): {
|
|
1495
|
+
ranges: number[][],
|
|
1496
|
+
}|undefined {
|
|
1497
|
+
if (fromIndex === undefined || toIndex === undefined || sparseIterationThreshold === undefined ||
|
|
1498
|
+
bucketThreshold === undefined) {
|
|
1499
|
+
return;
|
|
1500
|
+
}
|
|
1501
|
+
let ownPropertyNames: string[]|null = null;
|
|
1502
|
+
const consecutiveRange = (toIndex - fromIndex >= sparseIterationThreshold) && ArrayBuffer.isView(this);
|
|
1338
1503
|
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
/**
|
|
1342
|
-
* Note: must declare params as optional.
|
|
1343
|
-
*/
|
|
1344
|
-
function packRanges(
|
|
1345
|
-
this: Object, fromIndex?: number, toIndex?: number, bucketThreshold?: number,
|
|
1346
|
-
sparseIterationThreshold?: number): {
|
|
1347
|
-
ranges: number[][],
|
|
1348
|
-
}|undefined {
|
|
1349
|
-
if (fromIndex === undefined || toIndex === undefined || sparseIterationThreshold === undefined ||
|
|
1350
|
-
bucketThreshold === undefined) {
|
|
1504
|
+
function* arrayIndexes(object: Object): Generator<number, void, unknown> {
|
|
1505
|
+
if (fromIndex === undefined || toIndex === undefined || sparseIterationThreshold === undefined) {
|
|
1351
1506
|
return;
|
|
1352
1507
|
}
|
|
1353
|
-
let ownPropertyNames: string[]|null = null;
|
|
1354
|
-
const consecutiveRange = (toIndex - fromIndex >= sparseIterationThreshold) && ArrayBuffer.isView(this);
|
|
1355
1508
|
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1509
|
+
if (toIndex - fromIndex < sparseIterationThreshold) {
|
|
1510
|
+
for (let i = fromIndex; i <= toIndex; ++i) {
|
|
1511
|
+
if (i in object) {
|
|
1512
|
+
yield i;
|
|
1513
|
+
}
|
|
1359
1514
|
}
|
|
1515
|
+
} else {
|
|
1516
|
+
ownPropertyNames = ownPropertyNames || Object.getOwnPropertyNames(object);
|
|
1517
|
+
for (let i = 0; i < ownPropertyNames.length; ++i) {
|
|
1518
|
+
const name = ownPropertyNames[i];
|
|
1360
1519
|
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
yield i;
|
|
1365
|
-
}
|
|
1366
|
-
}
|
|
1367
|
-
} else {
|
|
1368
|
-
ownPropertyNames = ownPropertyNames || Object.getOwnPropertyNames(object);
|
|
1369
|
-
for (let i = 0; i < ownPropertyNames.length; ++i) {
|
|
1370
|
-
const name = ownPropertyNames[i];
|
|
1371
|
-
|
|
1372
|
-
const index = Number(name) >>> 0;
|
|
1373
|
-
if ((String(index)) === name && fromIndex <= index && index <= toIndex) {
|
|
1374
|
-
yield index;
|
|
1375
|
-
}
|
|
1520
|
+
const index = Number(name) >>> 0;
|
|
1521
|
+
if ((String(index)) === name && fromIndex <= index && index <= toIndex) {
|
|
1522
|
+
yield index;
|
|
1376
1523
|
}
|
|
1377
1524
|
}
|
|
1378
1525
|
}
|
|
1526
|
+
}
|
|
1379
1527
|
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
}
|
|
1528
|
+
let count = 0;
|
|
1529
|
+
if (consecutiveRange) {
|
|
1530
|
+
count = toIndex - fromIndex + 1;
|
|
1531
|
+
} else {
|
|
1532
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1533
|
+
for (const ignored of arrayIndexes(this)) {
|
|
1534
|
+
++count;
|
|
1388
1535
|
}
|
|
1536
|
+
}
|
|
1389
1537
|
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1538
|
+
let bucketSize: number = count;
|
|
1539
|
+
if (count <= bucketThreshold) {
|
|
1540
|
+
bucketSize = count;
|
|
1541
|
+
} else {
|
|
1542
|
+
bucketSize = Math.pow(bucketThreshold, Math.ceil(Math.log(count) / Math.log(bucketThreshold)) - 1);
|
|
1543
|
+
}
|
|
1396
1544
|
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
}
|
|
1405
|
-
ranges.push([groupStart, groupEnd, groupEnd - groupStart + 1]);
|
|
1545
|
+
const ranges = [];
|
|
1546
|
+
if (consecutiveRange) {
|
|
1547
|
+
for (let i = fromIndex; i <= toIndex; i += bucketSize) {
|
|
1548
|
+
const groupStart = i;
|
|
1549
|
+
let groupEnd: number = groupStart + bucketSize - 1;
|
|
1550
|
+
if (groupEnd > toIndex) {
|
|
1551
|
+
groupEnd = toIndex;
|
|
1406
1552
|
}
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
if (++count === bucketSize) {
|
|
1417
|
-
ranges.push([groupStart, groupEnd, count]);
|
|
1418
|
-
count = 0;
|
|
1419
|
-
groupStart = -1;
|
|
1420
|
-
}
|
|
1553
|
+
ranges.push([groupStart, groupEnd, groupEnd - groupStart + 1]);
|
|
1554
|
+
}
|
|
1555
|
+
} else {
|
|
1556
|
+
count = 0;
|
|
1557
|
+
let groupStart = -1;
|
|
1558
|
+
let groupEnd = 0;
|
|
1559
|
+
for (const i of arrayIndexes(this)) {
|
|
1560
|
+
if (groupStart === -1) {
|
|
1561
|
+
groupStart = i;
|
|
1421
1562
|
}
|
|
1422
|
-
|
|
1563
|
+
groupEnd = i;
|
|
1564
|
+
if (++count === bucketSize) {
|
|
1423
1565
|
ranges.push([groupStart, groupEnd, count]);
|
|
1566
|
+
count = 0;
|
|
1567
|
+
groupStart = -1;
|
|
1424
1568
|
}
|
|
1425
1569
|
}
|
|
1426
|
-
|
|
1427
|
-
|
|
1570
|
+
if (count > 0) {
|
|
1571
|
+
ranges.push([groupStart, groupEnd, count]);
|
|
1572
|
+
}
|
|
1428
1573
|
}
|
|
1429
1574
|
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1575
|
+
return {ranges};
|
|
1576
|
+
}
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1579
|
+
/**
|
|
1580
|
+
* This function is called on the RemoteObject.
|
|
1581
|
+
*/
|
|
1582
|
+
function buildArrayFragment(
|
|
1583
|
+
this: Record<number, Object>,
|
|
1584
|
+
fromIndex?: number,
|
|
1585
|
+
toIndex?: number,
|
|
1586
|
+
sparseIterationThreshold?: number,
|
|
1587
|
+
): unknown {
|
|
1588
|
+
const result = Object.create(null);
|
|
1589
|
+
|
|
1590
|
+
if (fromIndex === undefined || toIndex === undefined || sparseIterationThreshold === undefined) {
|
|
1591
|
+
return;
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1594
|
+
if (toIndex - fromIndex < sparseIterationThreshold) {
|
|
1595
|
+
for (let i = fromIndex; i <= toIndex; ++i) {
|
|
1596
|
+
if (i in this) {
|
|
1597
|
+
result[i] = this[i];
|
|
1452
1598
|
}
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1599
|
+
}
|
|
1600
|
+
} else {
|
|
1601
|
+
const ownPropertyNames = Object.getOwnPropertyNames(this);
|
|
1602
|
+
for (let i = 0; i < ownPropertyNames.length; ++i) {
|
|
1603
|
+
const name = ownPropertyNames[i];
|
|
1604
|
+
const index = Number(name) >>> 0;
|
|
1605
|
+
if (String(index) === name && fromIndex <= index && index <= toIndex) {
|
|
1606
|
+
result[index] = this[index];
|
|
1457
1607
|
}
|
|
1458
1608
|
}
|
|
1459
1609
|
}
|
|
1610
|
+
return result;
|
|
1611
|
+
}
|
|
1460
1612
|
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
if (!
|
|
1613
|
+
export class ArrayGroupingTreeElement extends UI.TreeOutline.TreeElement {
|
|
1614
|
+
override toggleOnClick: boolean;
|
|
1615
|
+
private readonly linkifier: Components.Linkifier.Linkifier|undefined;
|
|
1616
|
+
readonly #child: ArrayGroupTreeNode;
|
|
1617
|
+
constructor(child: ArrayGroupTreeNode, linkifier?: Components.Linkifier.Linkifier) {
|
|
1618
|
+
super(Platform.StringUtilities.sprintf('[%d … %d]', child.range.fromIndex, child.range.toIndex), true);
|
|
1619
|
+
this.#child = child;
|
|
1620
|
+
this.toggleOnClick = true;
|
|
1621
|
+
this.linkifier = linkifier;
|
|
1622
|
+
}
|
|
1623
|
+
|
|
1624
|
+
static async populate(
|
|
1625
|
+
treeNode: UI.TreeOutline.TreeElement, children: NodeChildren,
|
|
1626
|
+
linkifier?: Components.Linkifier.Linkifier): Promise<void> {
|
|
1627
|
+
if (!children.arrayRanges) {
|
|
1476
1628
|
return;
|
|
1477
1629
|
}
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
const
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
function buildArrayFragment(
|
|
1487
|
-
this: Record<number, Object>,
|
|
1488
|
-
fromIndex?: number,
|
|
1489
|
-
toIndex?: number,
|
|
1490
|
-
sparseIterationThreshold?: number,
|
|
1491
|
-
): unknown {
|
|
1492
|
-
const result = Object.create(null);
|
|
1493
|
-
|
|
1494
|
-
if (fromIndex === undefined || toIndex === undefined || sparseIterationThreshold === undefined) {
|
|
1495
|
-
return;
|
|
1496
|
-
}
|
|
1497
|
-
|
|
1498
|
-
if (toIndex - fromIndex < sparseIterationThreshold) {
|
|
1499
|
-
for (let i = fromIndex; i <= toIndex; ++i) {
|
|
1500
|
-
if (i in this) {
|
|
1501
|
-
result[i] = this[i];
|
|
1502
|
-
}
|
|
1503
|
-
}
|
|
1504
|
-
} else {
|
|
1505
|
-
const ownPropertyNames = Object.getOwnPropertyNames(this);
|
|
1506
|
-
for (let i = 0; i < ownPropertyNames.length; ++i) {
|
|
1507
|
-
const name = ownPropertyNames[i];
|
|
1508
|
-
const index = Number(name) >>> 0;
|
|
1509
|
-
if (String(index) === name && fromIndex <= index && index <= toIndex) {
|
|
1510
|
-
result[index] = this[index];
|
|
1511
|
-
}
|
|
1630
|
+
if (children.arrayRanges.length === 1) {
|
|
1631
|
+
await ObjectPropertyTreeElement.populate(treeNode, children.arrayRanges[0], false, false, linkifier);
|
|
1632
|
+
} else {
|
|
1633
|
+
for (const child of children.arrayRanges) {
|
|
1634
|
+
if (child.singular) {
|
|
1635
|
+
await ObjectPropertyTreeElement.populate(treeNode, child, false, false, linkifier);
|
|
1636
|
+
} else {
|
|
1637
|
+
treeNode.appendChild(new ArrayGroupingTreeElement(child, linkifier));
|
|
1512
1638
|
}
|
|
1513
1639
|
}
|
|
1514
|
-
return result;
|
|
1515
1640
|
}
|
|
1516
|
-
}
|
|
1517
1641
|
|
|
1518
|
-
|
|
1519
|
-
this: ArrayGroupingTreeElement, treeNode: UI.TreeOutline.TreeElement, object: SDK.RemoteObject.RemoteObject,
|
|
1520
|
-
linkifier?: Components.Linkifier.Linkifier): Promise<void> {
|
|
1521
|
-
const {properties, internalProperties} = await SDK.RemoteObject.RemoteObject.loadFromObjectPerProto(
|
|
1522
|
-
object, true /* generatePreview */, true /* nonIndexedPropertiesOnly */);
|
|
1523
|
-
if (!properties) {
|
|
1524
|
-
return;
|
|
1525
|
-
}
|
|
1526
|
-
ObjectPropertyTreeElement.populateWithProperties(
|
|
1527
|
-
treeNode, properties, internalProperties, false, false, object, linkifier);
|
|
1642
|
+
ObjectPropertyTreeElement.populateWithProperties(treeNode, children, false, false, linkifier);
|
|
1528
1643
|
}
|
|
1529
1644
|
|
|
1530
1645
|
override async onpopulate(): Promise<void> {
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
return;
|
|
1535
|
-
}
|
|
1536
|
-
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
|
|
1537
|
-
// @ts-expect-error
|
|
1538
|
-
await ArrayGroupingTreeElement.populateAsFragment(this, this.object, this.fromIndex, this.toIndex, this.linkifier);
|
|
1646
|
+
this.removeChildren();
|
|
1647
|
+
this.#child.removeChildren();
|
|
1648
|
+
await ObjectPropertyTreeElement.populate(this, this.#child, false, false, this.linkifier);
|
|
1539
1649
|
}
|
|
1540
1650
|
|
|
1541
1651
|
override onattach(): void {
|
|
1542
1652
|
this.listItemElement.classList.add('object-properties-section-name');
|
|
1543
1653
|
}
|
|
1544
1654
|
|
|
1545
|
-
|
|
1546
|
-
|
|
1655
|
+
// These should be module constants but they are modified by layout tests.
|
|
1656
|
+
static bucketThreshold = 100;
|
|
1657
|
+
static sparseIterationThreshold = 250000;
|
|
1547
1658
|
}
|
|
1548
1659
|
|
|
1549
1660
|
export class ObjectPropertyPrompt extends UI.TextPrompt.TextPrompt {
|
|
@@ -1614,12 +1725,8 @@ export class ObjectPropertiesSectionsTreeExpandController {
|
|
|
1614
1725
|
let result;
|
|
1615
1726
|
while (current !== rootElement) {
|
|
1616
1727
|
let currentName = '';
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
if ((current as any).property) {
|
|
1620
|
-
// TODO(crbug.com/1172300) Ignored during the jsdoc to ts migration)
|
|
1621
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1622
|
-
currentName = (current as any).property.name;
|
|
1728
|
+
if (current instanceof ObjectPropertyTreeElement) {
|
|
1729
|
+
currentName = current.property.name;
|
|
1623
1730
|
} else {
|
|
1624
1731
|
currentName = typeof current.title === 'string' ? current.title : current.title.textContent || '';
|
|
1625
1732
|
}
|
|
@@ -1667,74 +1774,86 @@ export class Renderer implements UI.UIUtils.Renderer {
|
|
|
1667
1774
|
}
|
|
1668
1775
|
}
|
|
1669
1776
|
|
|
1670
|
-
export class
|
|
1671
|
-
element: Element;
|
|
1672
|
-
constructor(element: Element) {
|
|
1673
|
-
this.element = element;
|
|
1674
|
-
}
|
|
1675
|
-
|
|
1676
|
-
appendApplicableItems(_event: Event, _contextMenu: UI.ContextMenu.ContextMenu, _object: Object): void {
|
|
1677
|
-
}
|
|
1678
|
-
}
|
|
1679
|
-
|
|
1680
|
-
export class ExpandableTextPropertyValue extends ObjectPropertyValue {
|
|
1777
|
+
export class ExpandableTextPropertyValue {
|
|
1681
1778
|
private readonly text: string;
|
|
1682
1779
|
private readonly maxLength: number;
|
|
1683
|
-
private expandElement: Element|null;
|
|
1684
1780
|
private readonly maxDisplayableTextLength: number;
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1781
|
+
readonly #byteCount: number;
|
|
1782
|
+
#expanded = false;
|
|
1783
|
+
#element: HTMLElement;
|
|
1784
|
+
|
|
1785
|
+
constructor(element: HTMLElement, text: string, maxLength: number) {
|
|
1786
|
+
this.#element = element;
|
|
1691
1787
|
this.text = text;
|
|
1692
1788
|
this.maxLength = maxLength;
|
|
1693
|
-
container.textContent = text.slice(0, maxLength);
|
|
1694
|
-
UI.Tooltip.Tooltip.install(container as HTMLElement, `${text.slice(0, maxLength)}…`);
|
|
1695
|
-
|
|
1696
|
-
this.expandElement = container.createChild('button');
|
|
1697
1789
|
this.maxDisplayableTextLength = 10000000;
|
|
1790
|
+
this.#byteCount = Platform.StringUtilities.countWtf8Bytes(text);
|
|
1791
|
+
this.#render();
|
|
1792
|
+
}
|
|
1698
1793
|
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
if (this.text.length < this.maxDisplayableTextLength) {
|
|
1702
|
-
this.expandElementText = i18nString(UIStrings.showMoreS, {PH1: totalBytesText});
|
|
1703
|
-
this.expandElement.setAttribute('data-text', this.expandElementText);
|
|
1704
|
-
this.expandElement.setAttribute('jslog', `${VisualLogging.action('expand').track({click: true})}`);
|
|
1705
|
-
this.expandElement.classList.add('expandable-inline-button');
|
|
1706
|
-
this.expandElement.addEventListener('click', this.expandText.bind(this));
|
|
1707
|
-
} else {
|
|
1708
|
-
this.expandElement.setAttribute('data-text', i18nString(UIStrings.longTextWasTruncatedS, {PH1: totalBytesText}));
|
|
1709
|
-
this.expandElement.classList.add('undisplayable-text');
|
|
1710
|
-
}
|
|
1711
|
-
|
|
1712
|
-
this.copyButtonText = i18nString(UIStrings.copy);
|
|
1713
|
-
const copyButton = container.createChild('button', 'expandable-inline-button');
|
|
1714
|
-
copyButton.setAttribute('data-text', this.copyButtonText);
|
|
1715
|
-
copyButton.setAttribute('jslog', `${VisualLogging.action('copy').track({click: true})}`);
|
|
1716
|
-
copyButton.addEventListener('click', this.copyText.bind(this));
|
|
1794
|
+
get element(): HTMLElement {
|
|
1795
|
+
return this.#element;
|
|
1717
1796
|
}
|
|
1718
1797
|
|
|
1719
|
-
|
|
1720
|
-
|
|
1798
|
+
#render(): void {
|
|
1799
|
+
const totalBytesText = i18n.ByteUtilities.bytesToString(this.#byteCount);
|
|
1800
|
+
const onContextMenu = (e: Event): void => {
|
|
1801
|
+
const {target} = e;
|
|
1802
|
+
if (!(target instanceof Element)) {
|
|
1803
|
+
return;
|
|
1804
|
+
}
|
|
1805
|
+
const listItem = target.closest('li');
|
|
1806
|
+
const element = listItem && UI.TreeOutline.TreeElement.getTreeElementBylistItemNode(listItem);
|
|
1807
|
+
if (!(element instanceof ObjectPropertyTreeElement)) {
|
|
1808
|
+
return;
|
|
1809
|
+
}
|
|
1810
|
+
const contextMenu = element.getContextMenu(e);
|
|
1811
|
+
if (this.text.length < this.maxDisplayableTextLength && !this.#expanded) {
|
|
1812
|
+
contextMenu.clipboardSection().appendItem(
|
|
1813
|
+
i18nString(UIStrings.showMoreS, {PH1: totalBytesText}), this.expandText.bind(this),
|
|
1814
|
+
{jslogContext: 'show-more'});
|
|
1815
|
+
}
|
|
1721
1816
|
contextMenu.clipboardSection().appendItem(
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1817
|
+
i18nString(UIStrings.copy), this.copyText.bind(this), {jslogContext: 'copy'});
|
|
1818
|
+
void contextMenu.show();
|
|
1819
|
+
e.consume(true);
|
|
1820
|
+
};
|
|
1821
|
+
|
|
1822
|
+
const croppedText = this.text.slice(0, this.maxLength);
|
|
1823
|
+
|
|
1824
|
+
// eslint-disable-next-line @devtools/no-lit-render-outside-of-view
|
|
1825
|
+
render(
|
|
1826
|
+
// clang-format off
|
|
1827
|
+
html`<span title=${croppedText + '…'} @contextmenu=${onContextMenu}>
|
|
1828
|
+
${this.#expanded ? this.text : croppedText}
|
|
1829
|
+
<button
|
|
1830
|
+
?hidden=${this.#expanded}
|
|
1831
|
+
@click=${this.#canExpand ? this.expandText.bind(this) : undefined}
|
|
1832
|
+
jslog=${ifDefined(this.#canExpand ? VisualLogging.action('expand').track({click: true}) : undefined)}
|
|
1833
|
+
class=${this.#canExpand ? 'expandable-inline-button' : 'undisplayable-text'}
|
|
1834
|
+
data-text=${this.#canExpand ? i18nString(UIStrings.showMoreS, {PH1: totalBytesText}) :
|
|
1835
|
+
i18nString(UIStrings.longTextWasTruncatedS, {PH1: totalBytesText})}
|
|
1836
|
+
></button>
|
|
1837
|
+
<button
|
|
1838
|
+
class=expandable-inline-button
|
|
1839
|
+
@click=${this.copyText.bind(this)}
|
|
1840
|
+
data-text=${i18nString(UIStrings.copy)}
|
|
1841
|
+
jslog=${VisualLogging.action('copy').track({click: true})}
|
|
1842
|
+
></button>
|
|
1843
|
+
</span>`,
|
|
1844
|
+
// clang-format on
|
|
1845
|
+
this.#element);
|
|
1846
|
+
}
|
|
1847
|
+
|
|
1848
|
+
get #canExpand(): boolean {
|
|
1849
|
+
return this.text.length < this.maxDisplayableTextLength;
|
|
1725
1850
|
}
|
|
1726
1851
|
|
|
1727
1852
|
private expandText(): void {
|
|
1728
|
-
if (!this
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
if (this.expandElement.parentElement) {
|
|
1733
|
-
this.expandElement.parentElement.insertBefore(
|
|
1734
|
-
document.createTextNode(this.text.slice(this.maxLength)), this.expandElement);
|
|
1853
|
+
if (!this.#expanded) {
|
|
1854
|
+
this.#expanded = true;
|
|
1855
|
+
this.#render();
|
|
1735
1856
|
}
|
|
1736
|
-
this.expandElement.remove();
|
|
1737
|
-
this.expandElement = null;
|
|
1738
1857
|
}
|
|
1739
1858
|
|
|
1740
1859
|
private copyText(): void {
|