chrome-devtools-frontend 1.0.1702515 → 1.0.1703574
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/front_end/core/common/ParsedURL.ts +5 -1
- package/front_end/core/text_utils/Markdown.ts +73 -0
- package/front_end/core/text_utils/text_utils.ts +2 -0
- package/front_end/generated/InspectorBackendCommands.ts +3 -1
- package/front_end/generated/protocol-mapping.d.ts +8 -0
- package/front_end/generated/protocol-proxy-api.d.ts +6 -0
- package/front_end/generated/protocol.ts +22 -0
- package/front_end/models/comment_manager/CD4ABridge.ts +5 -0
- package/front_end/models/issues_manager/MarkdownIssueDescription.ts +4 -47
- package/front_end/models/persistence/AutomaticFileSystemWorkspaceBinding.ts +1 -1
- package/front_end/panels/common/CommentsStatusBarPill.ts +40 -7
- package/front_end/panels/common/commentsStatusBarPill.css +13 -0
- package/front_end/panels/issues/IssueView.ts +5 -1
- package/front_end/panels/sources/SourcesView.ts +127 -147
- package/front_end/panels/sources/TabbedEditorContainer.ts +266 -207
- package/front_end/third_party/chromium/README.chromium +1 -1
- package/front_end/ui/components/markdown_view/MarkdownPlaceholderLitRenderer.ts +7 -65
- package/front_end/ui/legacy/TabbedPane.ts +51 -40
- package/front_end/ui/legacy/components/object_ui/ObjectPropertiesSection.ts +342 -373
- package/front_end/ui/visual_logging/KnownContextValues.ts +1 -0
- package/package.json +2 -1
|
@@ -383,6 +383,139 @@ const ARRAY_LOAD_THRESHOLD = 100;
|
|
|
383
383
|
const ARRAY_BUCKET_THRESHOLD = 100;
|
|
384
384
|
const ARRAY_SPARSE_ITERATION_THRESHOLD = 250000;
|
|
385
385
|
|
|
386
|
+
async function arrayRangeGroups(object: SDK.RemoteObject.RemoteObject, fromIndex: number,
|
|
387
|
+
toIndex: number): Promise<{ranges: number[][]}|null|undefined> {
|
|
388
|
+
return await object.callFunctionJSON(packArrayRanges, [
|
|
389
|
+
{value: fromIndex},
|
|
390
|
+
{value: toIndex},
|
|
391
|
+
{value: ARRAY_BUCKET_THRESHOLD},
|
|
392
|
+
{value: ARRAY_SPARSE_ITERATION_THRESHOLD},
|
|
393
|
+
]);
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* This function is called on the RemoteObject.
|
|
397
|
+
* Note: must declare params as optional.
|
|
398
|
+
*/
|
|
399
|
+
function packArrayRanges(this: Object, fromIndex?: number, toIndex?: number, bucketThreshold?: number,
|
|
400
|
+
sparseIterationThreshold?: number): {
|
|
401
|
+
ranges: number[][],
|
|
402
|
+
}|undefined {
|
|
403
|
+
if (fromIndex === undefined || toIndex === undefined || sparseIterationThreshold === undefined ||
|
|
404
|
+
bucketThreshold === undefined) {
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
let ownPropertyNames: string[]|null = null;
|
|
408
|
+
const consecutiveRange = (toIndex - fromIndex >= sparseIterationThreshold) && ArrayBuffer.isView(this);
|
|
409
|
+
|
|
410
|
+
function* arrayIndexes(object: Object): Generator<number, void, unknown> {
|
|
411
|
+
if (fromIndex === undefined || toIndex === undefined || sparseIterationThreshold === undefined) {
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
if (toIndex - fromIndex < sparseIterationThreshold) {
|
|
416
|
+
for (let i = fromIndex; i <= toIndex; ++i) {
|
|
417
|
+
if (i in object) {
|
|
418
|
+
yield i;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
} else {
|
|
422
|
+
ownPropertyNames = ownPropertyNames || Object.getOwnPropertyNames(object);
|
|
423
|
+
for (let i = 0; i < ownPropertyNames.length; ++i) {
|
|
424
|
+
const name = ownPropertyNames[i];
|
|
425
|
+
|
|
426
|
+
const index = Number(name) >>> 0;
|
|
427
|
+
if ((String(index)) === name && fromIndex <= index && index <= toIndex) {
|
|
428
|
+
yield index;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
let count = 0;
|
|
435
|
+
if (consecutiveRange) {
|
|
436
|
+
count = toIndex - fromIndex + 1;
|
|
437
|
+
} else {
|
|
438
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
439
|
+
for (const ignored of arrayIndexes(this)) {
|
|
440
|
+
++count;
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
let bucketSize: number = count;
|
|
445
|
+
if (count <= bucketThreshold) {
|
|
446
|
+
bucketSize = count;
|
|
447
|
+
} else {
|
|
448
|
+
bucketSize = Math.pow(bucketThreshold, Math.ceil(Math.log(count) / Math.log(bucketThreshold)) - 1);
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
const ranges = [];
|
|
452
|
+
if (consecutiveRange) {
|
|
453
|
+
for (let i = fromIndex; i <= toIndex; i += bucketSize) {
|
|
454
|
+
const groupStart = i;
|
|
455
|
+
let groupEnd: number = groupStart + bucketSize - 1;
|
|
456
|
+
if (groupEnd > toIndex) {
|
|
457
|
+
groupEnd = toIndex;
|
|
458
|
+
}
|
|
459
|
+
ranges.push([groupStart, groupEnd, groupEnd - groupStart + 1]);
|
|
460
|
+
}
|
|
461
|
+
} else {
|
|
462
|
+
count = 0;
|
|
463
|
+
let groupStart = -1;
|
|
464
|
+
let groupEnd = 0;
|
|
465
|
+
for (const i of arrayIndexes(this)) {
|
|
466
|
+
if (groupStart === -1) {
|
|
467
|
+
groupStart = i;
|
|
468
|
+
}
|
|
469
|
+
groupEnd = i;
|
|
470
|
+
if (++count === bucketSize) {
|
|
471
|
+
ranges.push([groupStart, groupEnd, count]);
|
|
472
|
+
count = 0;
|
|
473
|
+
groupStart = -1;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
if (count > 0) {
|
|
477
|
+
ranges.push([groupStart, groupEnd, count]);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
return {ranges};
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
/**
|
|
486
|
+
* This function is called on the RemoteObject.
|
|
487
|
+
*/
|
|
488
|
+
function buildArrayFragment(
|
|
489
|
+
this: Record<number, Object>,
|
|
490
|
+
fromIndex?: number,
|
|
491
|
+
toIndex?: number,
|
|
492
|
+
sparseIterationThreshold?: number,
|
|
493
|
+
): unknown {
|
|
494
|
+
const result = Object.create(null);
|
|
495
|
+
|
|
496
|
+
if (fromIndex === undefined || toIndex === undefined || sparseIterationThreshold === undefined) {
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
if (toIndex - fromIndex < sparseIterationThreshold) {
|
|
501
|
+
for (let i = fromIndex; i <= toIndex; ++i) {
|
|
502
|
+
if (i in this) {
|
|
503
|
+
result[i] = this[i];
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
} else {
|
|
507
|
+
const ownPropertyNames = Object.getOwnPropertyNames(this);
|
|
508
|
+
for (let i = 0; i < ownPropertyNames.length; ++i) {
|
|
509
|
+
const name = ownPropertyNames[i];
|
|
510
|
+
const index = Number(name) >>> 0;
|
|
511
|
+
if (String(index) === name && fromIndex <= index && index <= toIndex) {
|
|
512
|
+
result[index] = this[index];
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
return result;
|
|
517
|
+
}
|
|
518
|
+
|
|
386
519
|
export abstract class ObjectTreeNodeBase extends Common.ObjectWrapper.ObjectWrapper<ObjectTreeNodeBase.EventTypes> {
|
|
387
520
|
#children?: NodeChildren;
|
|
388
521
|
protected readonly options: ObjectTreeOptions;
|
|
@@ -1249,11 +1382,6 @@ export interface ContextMenuHandlers {
|
|
|
1249
1382
|
onShowAllToggled: (node: ObjectTreeNodeBase) => void;
|
|
1250
1383
|
}
|
|
1251
1384
|
|
|
1252
|
-
interface StateHandlers extends ContextMenuHandlers {
|
|
1253
|
-
onShowAllProperties: (node: ObjectTreeNode) => void;
|
|
1254
|
-
onExpand: (node: ObjectTreeNodeBase, expanded: boolean) => void;
|
|
1255
|
-
}
|
|
1256
|
-
|
|
1257
1385
|
export function populateObjectTreeContextMenu(contextMenu: UI.ContextMenu.ContextMenu,
|
|
1258
1386
|
objectOrProperty: ObjectTree|ObjectTreeNode,
|
|
1259
1387
|
handlers: ContextMenuHandlers): void {
|
|
@@ -1311,7 +1439,9 @@ export function populateObjectTreeContextMenu(contextMenu: UI.ContextMenu.Contex
|
|
|
1311
1439
|
{checked: objectOrProperty.includeNullOrUndefinedValues, jslogContext: 'show-all'});
|
|
1312
1440
|
}
|
|
1313
1441
|
|
|
1314
|
-
interface ObjectTreeViewInput extends
|
|
1442
|
+
interface ObjectTreeViewInput extends ContextMenuHandlers {
|
|
1443
|
+
onShowAllProperties: (node: ObjectTreeNode) => void;
|
|
1444
|
+
onExpand: (node: ObjectTreeNodeBase, expanded: boolean) => void;
|
|
1315
1445
|
renderAsSubtree: boolean;
|
|
1316
1446
|
objectTree?: ObjectTree;
|
|
1317
1447
|
linkifier?: Components.Linkifier.Linkifier;
|
|
@@ -1327,67 +1457,225 @@ const OBJECT_TREE_DEFAULT_VIEW: ObjectTreeView = (input, output, target) => {
|
|
|
1327
1457
|
return;
|
|
1328
1458
|
}
|
|
1329
1459
|
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1460
|
+
function renderProperty(property: ObjectTreeNode): LitTemplate {
|
|
1461
|
+
const onContextMenu = (e: Event): void => {
|
|
1462
|
+
const contextMenu = new UI.ContextMenu.ContextMenu(e);
|
|
1463
|
+
populateObjectTreeContextMenu(contextMenu, property, input);
|
|
1464
|
+
void contextMenu.show();
|
|
1465
|
+
};
|
|
1333
1466
|
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
};
|
|
1467
|
+
const onExpand = (e: UI.TreeOutline.TreeViewElement.ExpandEvent): void => {
|
|
1468
|
+
input.onExpand(property, e.detail.expanded);
|
|
1469
|
+
e.consume(true);
|
|
1470
|
+
};
|
|
1471
|
+
const childCount = (property.children?.properties?.length ?? 0) +
|
|
1472
|
+
(property.children?.internalProperties?.length ?? 0) + (property.children?.accessors?.length ?? 0) +
|
|
1473
|
+
(property.children?.arrayRanges?.length ?? 0);
|
|
1338
1474
|
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
#skipProto = false;
|
|
1345
|
-
#skipGettersAndSetters = false;
|
|
1346
|
-
readonly #view: ObjectTreeView;
|
|
1475
|
+
const showAllChildren = childCount <= InitialVisibleChildrenLimit || property.showAllChildren;
|
|
1476
|
+
const children = (): Iterable<LitTemplate> => {
|
|
1477
|
+
const nodes = createNodes(property, false, false, undefined, p => !isDisplayableProperty(p, property.property));
|
|
1478
|
+
return showAllChildren ? nodes : nodes.take(InitialVisibleChildrenLimit);
|
|
1479
|
+
};
|
|
1347
1480
|
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1481
|
+
const expandable = property.object && !property.object.customPreview() && property.object.hasChildren &&
|
|
1482
|
+
!property.property.wasThrown;
|
|
1483
|
+
|
|
1484
|
+
// clang-format off
|
|
1485
|
+
return html`<li
|
|
1486
|
+
?hidden=${property.isFiltered}
|
|
1487
|
+
?open=${property.expanded}
|
|
1488
|
+
@contextmenu=${onContextMenu}
|
|
1489
|
+
@expand=${onExpand}
|
|
1490
|
+
data-object-property-name-for-test=${property.name}
|
|
1491
|
+
toggle-on-click
|
|
1492
|
+
role=treeitem>
|
|
1493
|
+
${widget(ObjectPropertyWidget, {property, linkifier: input.linkifier, editable: !property.readOnly, expanded: property.expanded})}
|
|
1494
|
+
${expandable ? html`
|
|
1495
|
+
<ul role=group>
|
|
1496
|
+
${children()}
|
|
1497
|
+
${showAllChildren ? nothing : html`
|
|
1498
|
+
<li role=treeitem @select=${() => input.onShowAllProperties(property)}>
|
|
1499
|
+
<div
|
|
1500
|
+
class=object-value-calculate-value-button
|
|
1501
|
+
title=${i18nString(UIStrings.showAllD, {PH1: childCount})}>
|
|
1502
|
+
${i18nString(UIStrings.dots)}
|
|
1503
|
+
</div>
|
|
1504
|
+
</li>`}
|
|
1505
|
+
</ul>` : nothing}
|
|
1506
|
+
</li>`;
|
|
1507
|
+
// clang-format on
|
|
1351
1508
|
}
|
|
1352
1509
|
|
|
1353
|
-
|
|
1354
|
-
const
|
|
1355
|
-
|
|
1510
|
+
function renderArrayGroup(child: ArrayGroupTreeNode): LitTemplate {
|
|
1511
|
+
const onExpand = (e: UI.TreeOutline.TreeViewElement.ExpandEvent): void => {
|
|
1512
|
+
input.onExpand(child, e.detail.expanded);
|
|
1513
|
+
e.consume(true);
|
|
1514
|
+
};
|
|
1356
1515
|
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1516
|
+
// clang-format off
|
|
1517
|
+
return html`<li
|
|
1518
|
+
class=object-properties-section-name
|
|
1519
|
+
role=treeitem
|
|
1520
|
+
toggle-on-click
|
|
1521
|
+
?open=${child.expanded}
|
|
1522
|
+
@expand=${onExpand}>
|
|
1523
|
+
${Platform.StringUtilities.sprintf('[%d … %d]', child.range.fromIndex, child.range.toIndex)}
|
|
1524
|
+
<ul role=group>
|
|
1525
|
+
${ifExpanded(() => createNodes(child, false, false))}
|
|
1526
|
+
</ul>
|
|
1527
|
+
</li>`;
|
|
1528
|
+
// clang-format on
|
|
1529
|
+
}
|
|
1362
1530
|
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1531
|
+
function*
|
|
1532
|
+
createNodes(
|
|
1533
|
+
value: ObjectTreeNodeBase,
|
|
1534
|
+
skipProto: boolean,
|
|
1535
|
+
skipGettersAndSetters: boolean,
|
|
1536
|
+
emptyPlaceholder?: LitTemplate,
|
|
1537
|
+
isNotDisplayablePropertyCallback?: (property: SDK.RemoteObject.RemoteObjectProperty) => boolean,
|
|
1538
|
+
): Generator<LitTemplate> {
|
|
1539
|
+
const properties = value.children;
|
|
1540
|
+
if (!properties) {
|
|
1541
|
+
return;
|
|
1542
|
+
}
|
|
1543
|
+
if (properties.arrayRanges) {
|
|
1544
|
+
if (properties.arrayRanges.length === 1) {
|
|
1545
|
+
yield* createNodes(properties.arrayRanges[0], false, false, undefined, isNotDisplayablePropertyCallback);
|
|
1546
|
+
} else {
|
|
1547
|
+
for (const child of properties.arrayRanges) {
|
|
1548
|
+
if (child.singular) {
|
|
1549
|
+
yield* createNodes(child, false, false, undefined, isNotDisplayablePropertyCallback);
|
|
1550
|
+
} else {
|
|
1551
|
+
yield renderArrayGroup(child);
|
|
1368
1552
|
}
|
|
1369
1553
|
}
|
|
1370
1554
|
}
|
|
1371
|
-
}
|
|
1372
1555
|
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
child.addEventListener(ObjectTreeNodeBase.Events.FILTER_CHANGED, this.requestUpdate, this);
|
|
1379
|
-
child.addEventListener(ObjectTreeNodeBase.Events.EXPANDED_CHANGED, this.requestUpdate, this);
|
|
1380
|
-
child.addEventListener(ObjectTreeNodeBase.Events.VALUE_CHANGED, this.requestUpdate, this);
|
|
1381
|
-
child.addEventListener(ObjectTreeNodeBase.Events.CHILDREN_CHANGED, this.requestUpdate, this);
|
|
1382
|
-
if (child.expanded) {
|
|
1383
|
-
await this.#populateChildrenIfNeeded(child);
|
|
1384
|
-
}
|
|
1556
|
+
yield* createPropertyNodes(properties, false, false, undefined, isNotDisplayablePropertyCallback);
|
|
1557
|
+
} else {
|
|
1558
|
+
yield*
|
|
1559
|
+
createPropertyNodes(properties, skipProto, skipGettersAndSetters, emptyPlaceholder,
|
|
1560
|
+
isNotDisplayablePropertyCallback);
|
|
1385
1561
|
}
|
|
1562
|
+
}
|
|
1386
1563
|
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1564
|
+
function*
|
|
1565
|
+
createPropertyNodes({properties, internalProperties, accessors, arrayRanges}: NodeChildren, skipProto: boolean,
|
|
1566
|
+
skipGettersAndSetters: boolean, emptyPlaceholder?: LitTemplate,
|
|
1567
|
+
isNotDisplayablePropertyCallback?: (property: SDK.RemoteObject.RemoteObjectProperty) =>
|
|
1568
|
+
boolean): Generator<LitTemplate> {
|
|
1569
|
+
let empty = true;
|
|
1570
|
+
// Arrays with large numbers of elements are paginated into arrayRanges.
|
|
1571
|
+
// If we have array ranges, the object is not empty.
|
|
1572
|
+
if (arrayRanges && arrayRanges.length > 0) {
|
|
1573
|
+
empty = false;
|
|
1574
|
+
}
|
|
1575
|
+
|
|
1576
|
+
const entriesProperty = internalProperties?.find(({property}) => property.name === '[[Entries]]');
|
|
1577
|
+
if (entriesProperty) {
|
|
1578
|
+
yield renderProperty(entriesProperty);
|
|
1579
|
+
empty = false;
|
|
1580
|
+
}
|
|
1581
|
+
|
|
1582
|
+
for (const property of properties ?? []) {
|
|
1583
|
+
if (isNotDisplayablePropertyCallback?.(property.property)) {
|
|
1584
|
+
continue;
|
|
1585
|
+
}
|
|
1586
|
+
|
|
1587
|
+
const canShowProperty = property.property.getter || !property.property.isAccessorProperty();
|
|
1588
|
+
if (canShowProperty) {
|
|
1589
|
+
yield renderProperty(property);
|
|
1590
|
+
empty = false;
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1594
|
+
if (!skipGettersAndSetters) {
|
|
1595
|
+
for (const accessor of accessors ?? []) {
|
|
1596
|
+
yield renderProperty(accessor);
|
|
1597
|
+
}
|
|
1598
|
+
}
|
|
1599
|
+
|
|
1600
|
+
for (const property of internalProperties ?? []) {
|
|
1601
|
+
if (property.property.name === '[[Entries]]') {
|
|
1602
|
+
continue;
|
|
1603
|
+
}
|
|
1604
|
+
if (property.property.name === '[[Prototype]]' && skipProto) {
|
|
1605
|
+
continue;
|
|
1606
|
+
}
|
|
1607
|
+
yield renderProperty(property);
|
|
1608
|
+
empty = false;
|
|
1609
|
+
}
|
|
1610
|
+
|
|
1611
|
+
if (empty) {
|
|
1612
|
+
yield html`<li role=treeitem>
|
|
1613
|
+
<div class=gray-info-message>${emptyPlaceholder || i18nString(UIStrings.noProperties)}</div>
|
|
1614
|
+
</li>`;
|
|
1615
|
+
}
|
|
1616
|
+
}
|
|
1617
|
+
|
|
1618
|
+
const nodes =
|
|
1619
|
+
Array.from(createNodes(objectTree, input.skipProto, input.skipGettersAndSetters, input.emptyPlaceholder));
|
|
1620
|
+
nodes.forEach(UI.UIUtils.HTMLElementWithLightDOMTemplate.patchLitTemplate);
|
|
1621
|
+
|
|
1622
|
+
render(nodes, target, {
|
|
1623
|
+
container: {classes: input.renderAsSubtree ? ['source-code', 'object-properties-section'] : []},
|
|
1624
|
+
});
|
|
1625
|
+
};
|
|
1626
|
+
|
|
1627
|
+
export class ObjectTreeWidget extends UI.Widget.Widget {
|
|
1628
|
+
#objectTree: ObjectTree|undefined = undefined;
|
|
1629
|
+
#linkifier: Components.Linkifier.Linkifier|undefined = undefined;
|
|
1630
|
+
#emptyPlaceholder?: LitTemplate;
|
|
1631
|
+
#renderAsSubtree = false;
|
|
1632
|
+
#skipProto = false;
|
|
1633
|
+
#skipGettersAndSetters = false;
|
|
1634
|
+
readonly #view: ObjectTreeView;
|
|
1635
|
+
|
|
1636
|
+
constructor(element?: HTMLElement, view: ObjectTreeView = OBJECT_TREE_DEFAULT_VIEW) {
|
|
1637
|
+
super(element);
|
|
1638
|
+
this.#view = view;
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1641
|
+
async #populateChildrenIfNeeded(node: ObjectTreeNodeBase): Promise<void> {
|
|
1642
|
+
const isFirstPopulation = !node.children;
|
|
1643
|
+
const children = await node.populateChildrenIfNeeded();
|
|
1644
|
+
|
|
1645
|
+
if (isFirstPopulation) {
|
|
1646
|
+
const entriesProperty = children.internalProperties?.find(({property}) => property.name === '[[Entries]]');
|
|
1647
|
+
if (entriesProperty) {
|
|
1648
|
+
entriesProperty.expanded = true;
|
|
1649
|
+
}
|
|
1650
|
+
|
|
1651
|
+
for (const property of children.properties ?? []) {
|
|
1652
|
+
const canShowProperty = property.property.getter || !property.property.isAccessorProperty();
|
|
1653
|
+
if (canShowProperty) {
|
|
1654
|
+
if (property.property.name === 'memories' && property.object?.className === 'Memories') {
|
|
1655
|
+
property.expanded = true;
|
|
1656
|
+
}
|
|
1657
|
+
}
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1660
|
+
|
|
1661
|
+
for (const child of node.treeNodeChildren()) {
|
|
1662
|
+
child.removeEventListener(ObjectTreeNodeBase.Events.FILTER_CHANGED, this.requestUpdate, this);
|
|
1663
|
+
child.removeEventListener(ObjectTreeNodeBase.Events.EXPANDED_CHANGED, this.requestUpdate, this);
|
|
1664
|
+
child.removeEventListener(ObjectTreeNodeBase.Events.VALUE_CHANGED, this.requestUpdate, this);
|
|
1665
|
+
child.removeEventListener(ObjectTreeNodeBase.Events.CHILDREN_CHANGED, this.requestUpdate, this);
|
|
1666
|
+
child.addEventListener(ObjectTreeNodeBase.Events.FILTER_CHANGED, this.requestUpdate, this);
|
|
1667
|
+
child.addEventListener(ObjectTreeNodeBase.Events.EXPANDED_CHANGED, this.requestUpdate, this);
|
|
1668
|
+
child.addEventListener(ObjectTreeNodeBase.Events.VALUE_CHANGED, this.requestUpdate, this);
|
|
1669
|
+
child.addEventListener(ObjectTreeNodeBase.Events.CHILDREN_CHANGED, this.requestUpdate, this);
|
|
1670
|
+
if (child.expanded) {
|
|
1671
|
+
await this.#populateChildrenIfNeeded(child);
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
if (!children.arrayRanges) {
|
|
1676
|
+
return;
|
|
1677
|
+
}
|
|
1678
|
+
if (children.arrayRanges.length === 1) {
|
|
1391
1679
|
await this.#populateChildrenIfNeeded(children.arrayRanges[0]);
|
|
1392
1680
|
} else {
|
|
1393
1681
|
await Promise.all(
|
|
@@ -1987,325 +2275,6 @@ export class ObjectPropertyWidget extends UI.Widget.Widget {
|
|
|
1987
2275
|
}
|
|
1988
2276
|
}
|
|
1989
2277
|
|
|
1990
|
-
class ObjectPropertyTreeElement {
|
|
1991
|
-
static #render(property: ObjectTreeNode, linkifier: Components.Linkifier.Linkifier|undefined,
|
|
1992
|
-
handlers: StateHandlers): LitTemplate {
|
|
1993
|
-
const onContextMenu = (e: Event): void => {
|
|
1994
|
-
const contextMenu = new UI.ContextMenu.ContextMenu(e);
|
|
1995
|
-
populateObjectTreeContextMenu(contextMenu, property, handlers);
|
|
1996
|
-
void contextMenu.show();
|
|
1997
|
-
};
|
|
1998
|
-
|
|
1999
|
-
const onExpand = (e: UI.TreeOutline.TreeViewElement.ExpandEvent): void => {
|
|
2000
|
-
handlers.onExpand(property, e.detail.expanded);
|
|
2001
|
-
e.consume(true);
|
|
2002
|
-
};
|
|
2003
|
-
const childCount = (property.children?.properties?.length ?? 0) +
|
|
2004
|
-
(property.children?.internalProperties?.length ?? 0) + (property.children?.accessors?.length ?? 0) +
|
|
2005
|
-
(property.children?.arrayRanges?.length ?? 0);
|
|
2006
|
-
|
|
2007
|
-
const showAllChildren = childCount <= InitialVisibleChildrenLimit || property.showAllChildren;
|
|
2008
|
-
const children = (): Iterable<LitTemplate> => {
|
|
2009
|
-
const nodes = ObjectPropertyTreeElement.createNodes(property, handlers, false, false, linkifier, undefined,
|
|
2010
|
-
p => !isDisplayableProperty(p, property.property));
|
|
2011
|
-
return showAllChildren ? nodes : nodes.take(InitialVisibleChildrenLimit);
|
|
2012
|
-
};
|
|
2013
|
-
|
|
2014
|
-
const expandable = property.object && !property.object.customPreview() && property.object.hasChildren &&
|
|
2015
|
-
!property.property.wasThrown;
|
|
2016
|
-
|
|
2017
|
-
// clang-format off
|
|
2018
|
-
return html`<li
|
|
2019
|
-
?hidden=${property.isFiltered}
|
|
2020
|
-
?open=${property.expanded}
|
|
2021
|
-
@contextmenu=${onContextMenu}
|
|
2022
|
-
@expand=${onExpand}
|
|
2023
|
-
data-object-property-name-for-test=${property.name}
|
|
2024
|
-
toggle-on-click
|
|
2025
|
-
role=treeitem>
|
|
2026
|
-
${widget(ObjectPropertyWidget, {property, linkifier, editable: !property.readOnly, expanded: property.expanded})}
|
|
2027
|
-
${expandable ? html`
|
|
2028
|
-
<ul role=group>
|
|
2029
|
-
${children()}
|
|
2030
|
-
${showAllChildren ? nothing : html`
|
|
2031
|
-
<li role=treeitem @select=${() => handlers.onShowAllProperties(property)}>
|
|
2032
|
-
<div
|
|
2033
|
-
class=object-value-calculate-value-button
|
|
2034
|
-
title=${i18nString(UIStrings.showAllD, {PH1: childCount})}>
|
|
2035
|
-
${i18nString(UIStrings.dots)}
|
|
2036
|
-
</div>
|
|
2037
|
-
</li>`}
|
|
2038
|
-
</ul>` : nothing}
|
|
2039
|
-
</li>`;
|
|
2040
|
-
// clang-format on
|
|
2041
|
-
}
|
|
2042
|
-
|
|
2043
|
-
static *
|
|
2044
|
-
createNodes(
|
|
2045
|
-
value: ObjectTreeNodeBase,
|
|
2046
|
-
handlers: StateHandlers,
|
|
2047
|
-
skipProto: boolean,
|
|
2048
|
-
skipGettersAndSetters: boolean,
|
|
2049
|
-
linkifier?: Components.Linkifier.Linkifier,
|
|
2050
|
-
emptyPlaceholder?: LitTemplate,
|
|
2051
|
-
isNotDisplayablePropertyCallback?: (property: SDK.RemoteObject.RemoteObjectProperty) => boolean,
|
|
2052
|
-
): Generator<LitTemplate> {
|
|
2053
|
-
const properties = value.children;
|
|
2054
|
-
if (!properties) {
|
|
2055
|
-
return;
|
|
2056
|
-
}
|
|
2057
|
-
if (properties.arrayRanges) {
|
|
2058
|
-
yield* ArrayGroupingTreeElement.createNodes(properties, handlers, linkifier, isNotDisplayablePropertyCallback);
|
|
2059
|
-
} else {
|
|
2060
|
-
yield*
|
|
2061
|
-
ObjectPropertyTreeElement.createPropertyNodes(properties, handlers, skipProto, skipGettersAndSetters,
|
|
2062
|
-
linkifier, emptyPlaceholder, isNotDisplayablePropertyCallback);
|
|
2063
|
-
}
|
|
2064
|
-
}
|
|
2065
|
-
|
|
2066
|
-
static *
|
|
2067
|
-
createPropertyNodes({properties, internalProperties, accessors, arrayRanges}: NodeChildren,
|
|
2068
|
-
handlers: StateHandlers, skipProto: boolean, skipGettersAndSetters: boolean,
|
|
2069
|
-
linkifier?: Components.Linkifier.Linkifier, emptyPlaceholder?: LitTemplate,
|
|
2070
|
-
isNotDisplayablePropertyCallback?:
|
|
2071
|
-
(property: SDK.RemoteObject.RemoteObjectProperty) => boolean): Generator<LitTemplate> {
|
|
2072
|
-
let empty = true;
|
|
2073
|
-
// Arrays with large numbers of elements are paginated into arrayRanges.
|
|
2074
|
-
// If we have array ranges, the object is not empty.
|
|
2075
|
-
if (arrayRanges && arrayRanges.length > 0) {
|
|
2076
|
-
empty = false;
|
|
2077
|
-
}
|
|
2078
|
-
const sortPropertiesAlphabetically = properties?.[0]?.sortPropertiesAlphabetically ?? true;
|
|
2079
|
-
properties?.sort((a, b) => compareProperties(a, b, sortPropertiesAlphabetically));
|
|
2080
|
-
|
|
2081
|
-
const entriesProperty = internalProperties?.find(({property}) => property.name === '[[Entries]]');
|
|
2082
|
-
if (entriesProperty) {
|
|
2083
|
-
yield ObjectPropertyTreeElement.#render(entriesProperty, linkifier, handlers);
|
|
2084
|
-
empty = false;
|
|
2085
|
-
}
|
|
2086
|
-
|
|
2087
|
-
for (const property of properties ?? []) {
|
|
2088
|
-
if (isNotDisplayablePropertyCallback?.(property.property)) {
|
|
2089
|
-
continue;
|
|
2090
|
-
}
|
|
2091
|
-
|
|
2092
|
-
const canShowProperty = property.property.getter || !property.property.isAccessorProperty();
|
|
2093
|
-
if (canShowProperty) {
|
|
2094
|
-
yield ObjectPropertyTreeElement.#render(property, linkifier, handlers);
|
|
2095
|
-
empty = false;
|
|
2096
|
-
}
|
|
2097
|
-
}
|
|
2098
|
-
|
|
2099
|
-
if (!skipGettersAndSetters) {
|
|
2100
|
-
for (const accessor of accessors ?? []) {
|
|
2101
|
-
yield ObjectPropertyTreeElement.#render(accessor, linkifier, handlers);
|
|
2102
|
-
}
|
|
2103
|
-
}
|
|
2104
|
-
|
|
2105
|
-
for (const property of internalProperties ?? []) {
|
|
2106
|
-
if (property.property.name === '[[Entries]]') {
|
|
2107
|
-
continue;
|
|
2108
|
-
}
|
|
2109
|
-
if (property.property.name === '[[Prototype]]' && skipProto) {
|
|
2110
|
-
continue;
|
|
2111
|
-
}
|
|
2112
|
-
yield ObjectPropertyTreeElement.#render(property, linkifier, handlers);
|
|
2113
|
-
empty = false;
|
|
2114
|
-
}
|
|
2115
|
-
|
|
2116
|
-
if (empty) {
|
|
2117
|
-
yield html`<li role=treeitem>
|
|
2118
|
-
<div class=gray-info-message>${emptyPlaceholder || i18nString(UIStrings.noProperties)}</div>
|
|
2119
|
-
</li>`;
|
|
2120
|
-
}
|
|
2121
|
-
}
|
|
2122
|
-
}
|
|
2123
|
-
|
|
2124
|
-
async function arrayRangeGroups(object: SDK.RemoteObject.RemoteObject, fromIndex: number,
|
|
2125
|
-
toIndex: number): Promise<{ranges: number[][]}|null|undefined> {
|
|
2126
|
-
return await object.callFunctionJSON(packArrayRanges, [
|
|
2127
|
-
{value: fromIndex},
|
|
2128
|
-
{value: toIndex},
|
|
2129
|
-
{value: ARRAY_BUCKET_THRESHOLD},
|
|
2130
|
-
{value: ARRAY_SPARSE_ITERATION_THRESHOLD},
|
|
2131
|
-
]);
|
|
2132
|
-
|
|
2133
|
-
/**
|
|
2134
|
-
* This function is called on the RemoteObject.
|
|
2135
|
-
* Note: must declare params as optional.
|
|
2136
|
-
*/
|
|
2137
|
-
function packArrayRanges(this: Object, fromIndex?: number, toIndex?: number, bucketThreshold?: number,
|
|
2138
|
-
sparseIterationThreshold?: number): {
|
|
2139
|
-
ranges: number[][],
|
|
2140
|
-
}|undefined {
|
|
2141
|
-
if (fromIndex === undefined || toIndex === undefined || sparseIterationThreshold === undefined ||
|
|
2142
|
-
bucketThreshold === undefined) {
|
|
2143
|
-
return;
|
|
2144
|
-
}
|
|
2145
|
-
let ownPropertyNames: string[]|null = null;
|
|
2146
|
-
const consecutiveRange = (toIndex - fromIndex >= sparseIterationThreshold) && ArrayBuffer.isView(this);
|
|
2147
|
-
|
|
2148
|
-
function* arrayIndexes(object: Object): Generator<number, void, unknown> {
|
|
2149
|
-
if (fromIndex === undefined || toIndex === undefined || sparseIterationThreshold === undefined) {
|
|
2150
|
-
return;
|
|
2151
|
-
}
|
|
2152
|
-
|
|
2153
|
-
if (toIndex - fromIndex < sparseIterationThreshold) {
|
|
2154
|
-
for (let i = fromIndex; i <= toIndex; ++i) {
|
|
2155
|
-
if (i in object) {
|
|
2156
|
-
yield i;
|
|
2157
|
-
}
|
|
2158
|
-
}
|
|
2159
|
-
} else {
|
|
2160
|
-
ownPropertyNames = ownPropertyNames || Object.getOwnPropertyNames(object);
|
|
2161
|
-
for (let i = 0; i < ownPropertyNames.length; ++i) {
|
|
2162
|
-
const name = ownPropertyNames[i];
|
|
2163
|
-
|
|
2164
|
-
const index = Number(name) >>> 0;
|
|
2165
|
-
if ((String(index)) === name && fromIndex <= index && index <= toIndex) {
|
|
2166
|
-
yield index;
|
|
2167
|
-
}
|
|
2168
|
-
}
|
|
2169
|
-
}
|
|
2170
|
-
}
|
|
2171
|
-
|
|
2172
|
-
let count = 0;
|
|
2173
|
-
if (consecutiveRange) {
|
|
2174
|
-
count = toIndex - fromIndex + 1;
|
|
2175
|
-
} else {
|
|
2176
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2177
|
-
for (const ignored of arrayIndexes(this)) {
|
|
2178
|
-
++count;
|
|
2179
|
-
}
|
|
2180
|
-
}
|
|
2181
|
-
|
|
2182
|
-
let bucketSize: number = count;
|
|
2183
|
-
if (count <= bucketThreshold) {
|
|
2184
|
-
bucketSize = count;
|
|
2185
|
-
} else {
|
|
2186
|
-
bucketSize = Math.pow(bucketThreshold, Math.ceil(Math.log(count) / Math.log(bucketThreshold)) - 1);
|
|
2187
|
-
}
|
|
2188
|
-
|
|
2189
|
-
const ranges = [];
|
|
2190
|
-
if (consecutiveRange) {
|
|
2191
|
-
for (let i = fromIndex; i <= toIndex; i += bucketSize) {
|
|
2192
|
-
const groupStart = i;
|
|
2193
|
-
let groupEnd: number = groupStart + bucketSize - 1;
|
|
2194
|
-
if (groupEnd > toIndex) {
|
|
2195
|
-
groupEnd = toIndex;
|
|
2196
|
-
}
|
|
2197
|
-
ranges.push([groupStart, groupEnd, groupEnd - groupStart + 1]);
|
|
2198
|
-
}
|
|
2199
|
-
} else {
|
|
2200
|
-
count = 0;
|
|
2201
|
-
let groupStart = -1;
|
|
2202
|
-
let groupEnd = 0;
|
|
2203
|
-
for (const i of arrayIndexes(this)) {
|
|
2204
|
-
if (groupStart === -1) {
|
|
2205
|
-
groupStart = i;
|
|
2206
|
-
}
|
|
2207
|
-
groupEnd = i;
|
|
2208
|
-
if (++count === bucketSize) {
|
|
2209
|
-
ranges.push([groupStart, groupEnd, count]);
|
|
2210
|
-
count = 0;
|
|
2211
|
-
groupStart = -1;
|
|
2212
|
-
}
|
|
2213
|
-
}
|
|
2214
|
-
if (count > 0) {
|
|
2215
|
-
ranges.push([groupStart, groupEnd, count]);
|
|
2216
|
-
}
|
|
2217
|
-
}
|
|
2218
|
-
|
|
2219
|
-
return {ranges};
|
|
2220
|
-
}
|
|
2221
|
-
}
|
|
2222
|
-
|
|
2223
|
-
/**
|
|
2224
|
-
* This function is called on the RemoteObject.
|
|
2225
|
-
*/
|
|
2226
|
-
function buildArrayFragment(
|
|
2227
|
-
this: Record<number, Object>,
|
|
2228
|
-
fromIndex?: number,
|
|
2229
|
-
toIndex?: number,
|
|
2230
|
-
sparseIterationThreshold?: number,
|
|
2231
|
-
): unknown {
|
|
2232
|
-
const result = Object.create(null);
|
|
2233
|
-
|
|
2234
|
-
if (fromIndex === undefined || toIndex === undefined || sparseIterationThreshold === undefined) {
|
|
2235
|
-
return;
|
|
2236
|
-
}
|
|
2237
|
-
|
|
2238
|
-
if (toIndex - fromIndex < sparseIterationThreshold) {
|
|
2239
|
-
for (let i = fromIndex; i <= toIndex; ++i) {
|
|
2240
|
-
if (i in this) {
|
|
2241
|
-
result[i] = this[i];
|
|
2242
|
-
}
|
|
2243
|
-
}
|
|
2244
|
-
} else {
|
|
2245
|
-
const ownPropertyNames = Object.getOwnPropertyNames(this);
|
|
2246
|
-
for (let i = 0; i < ownPropertyNames.length; ++i) {
|
|
2247
|
-
const name = ownPropertyNames[i];
|
|
2248
|
-
const index = Number(name) >>> 0;
|
|
2249
|
-
if (String(index) === name && fromIndex <= index && index <= toIndex) {
|
|
2250
|
-
result[index] = this[index];
|
|
2251
|
-
}
|
|
2252
|
-
}
|
|
2253
|
-
}
|
|
2254
|
-
return result;
|
|
2255
|
-
}
|
|
2256
|
-
|
|
2257
|
-
class ArrayGroupingTreeElement {
|
|
2258
|
-
static #render(child: ArrayGroupTreeNode, linkifier: Components.Linkifier.Linkifier|undefined,
|
|
2259
|
-
handlers: StateHandlers): LitTemplate {
|
|
2260
|
-
const onExpand = (e: UI.TreeOutline.TreeViewElement.ExpandEvent): void => {
|
|
2261
|
-
handlers.onExpand(child, e.detail.expanded);
|
|
2262
|
-
e.consume(true);
|
|
2263
|
-
};
|
|
2264
|
-
|
|
2265
|
-
// clang-format off
|
|
2266
|
-
return html`<li
|
|
2267
|
-
class=object-properties-section-name
|
|
2268
|
-
role=treeitem
|
|
2269
|
-
toggle-on-click
|
|
2270
|
-
?open=${child.expanded}
|
|
2271
|
-
@expand=${onExpand}>
|
|
2272
|
-
${Platform.StringUtilities.sprintf('[%d … %d]', child.range.fromIndex, child.range.toIndex)}
|
|
2273
|
-
<ul role=group>
|
|
2274
|
-
${ifExpanded(() => ObjectPropertyTreeElement.createNodes(child, handlers, false, false, linkifier))}
|
|
2275
|
-
</ul>
|
|
2276
|
-
</li>`;
|
|
2277
|
-
// clang-format on
|
|
2278
|
-
}
|
|
2279
|
-
|
|
2280
|
-
static *
|
|
2281
|
-
createNodes(children: NodeChildren, handlers: StateHandlers, linkifier?: Components.Linkifier.Linkifier,
|
|
2282
|
-
isNotDisplayablePropertyCallback?: (property: SDK.RemoteObject.RemoteObjectProperty) => boolean):
|
|
2283
|
-
Generator<LitTemplate> {
|
|
2284
|
-
if (!children.arrayRanges) {
|
|
2285
|
-
return;
|
|
2286
|
-
}
|
|
2287
|
-
if (children.arrayRanges.length === 1) {
|
|
2288
|
-
yield*
|
|
2289
|
-
ObjectPropertyTreeElement.createNodes(children.arrayRanges[0], handlers, false, false, linkifier, undefined,
|
|
2290
|
-
isNotDisplayablePropertyCallback);
|
|
2291
|
-
} else {
|
|
2292
|
-
for (const child of children.arrayRanges) {
|
|
2293
|
-
if (child.singular) {
|
|
2294
|
-
yield*
|
|
2295
|
-
ObjectPropertyTreeElement.createNodes(child, handlers, false, false, linkifier, undefined,
|
|
2296
|
-
isNotDisplayablePropertyCallback);
|
|
2297
|
-
} else {
|
|
2298
|
-
yield ArrayGroupingTreeElement.#render(child, linkifier, handlers);
|
|
2299
|
-
}
|
|
2300
|
-
}
|
|
2301
|
-
}
|
|
2302
|
-
|
|
2303
|
-
yield*
|
|
2304
|
-
ObjectPropertyTreeElement.createPropertyNodes(children, handlers, false, false, linkifier, undefined,
|
|
2305
|
-
isNotDisplayablePropertyCallback);
|
|
2306
|
-
}
|
|
2307
|
-
}
|
|
2308
|
-
|
|
2309
2278
|
interface ExpandableTextViewInput {
|
|
2310
2279
|
copyText: () => void;
|
|
2311
2280
|
expandText: () => void;
|