[tools] Add V8CustomElement.update method

Drive-by-fix:
- Remove duplicated LazyTable
- Introduce more pseudo private _* fields
- Remove MapPanel.mapDetails getter
- Rename MapDetails.setSelectedMap to .map

Bug: v8:10644
Change-Id: I0f976ab86f24de2677e024e386e7d4169c9abbb3
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2523192
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Reviewed-by: Sathya Gunasekaran  <gsathya@chromium.org>
Cr-Commit-Position: refs/heads/master@{#71093}
This commit is contained in:
Camillo Bruni 2020-11-10 14:21:40 +01:00 committed by Commit Bot
parent 7555761b9b
commit 6c69379497
9 changed files with 67 additions and 83 deletions

View File

@ -177,11 +177,15 @@ function $(id) {
} }
class V8CustomElement extends HTMLElement { class V8CustomElement extends HTMLElement {
_updateTimeoutId;
_updateCallback = this._update.bind(this);
constructor(templateText) { constructor(templateText) {
super(); super();
const shadowRoot = this.attachShadow({mode: 'open'}); const shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.innerHTML = templateText; shadowRoot.innerHTML = templateText;
} }
$(id) { $(id) {
return this.shadowRoot.querySelector(id); return this.shadowRoot.querySelector(id);
} }
@ -189,30 +193,16 @@ class V8CustomElement extends HTMLElement {
querySelectorAll(query) { querySelectorAll(query) {
return this.shadowRoot.querySelectorAll(query); return this.shadowRoot.querySelectorAll(query);
} }
}
class LazyTable { update() {
constructor(table, rowData, rowElementCreator) { // Use timeout tasks to asynchronously update the UI without blocking.
this._table = table; clearTimeout(this._updateTimeoutId);
this._rowData = rowData; const kDelayMs = 5;
this._rowElementCreator = rowElementCreator; this._updateTimeoutId = setTimeout(this._updateCallback, kDelayMs);
const tbody = table.querySelector('tbody');
table.replaceChild(document.createElement('tbody'), tbody);
table.querySelector('tfoot td').onclick = (e) => this._addMoreRows();
this._addMoreRows();
} }
_nextRowDataSlice() { _update() {
return this._rowData.splice(0, 100); throw Error('Subclass responsibility');
}
_addMoreRows() {
const fragment = new DocumentFragment();
for (let row of this._nextRowDataSlice()) {
const tr = this._rowElementCreator(row);
fragment.appendChild(tr);
}
this._table.querySelector('tbody').appendChild(fragment);
} }
} }

View File

@ -21,7 +21,7 @@ DOM.defineCustomElement(
console.assert(value !== undefined, 'timeline undefined!'); console.assert(value !== undefined, 'timeline undefined!');
this._timeline = value; this._timeline = value;
this.selectedLogEntries = this._timeline.all; this.selectedLogEntries = this._timeline.all;
this.updateCount(); this.update();
} }
get groupKey() { get groupKey() {
return this.$('#group-key'); return this.$('#group-key');
@ -48,22 +48,21 @@ DOM.defineCustomElement(
this.update(); this.update();
} }
async update() { _update() {
await delay(1); this._updateCount();
this.updateCount(); this._updateTable();
this.updateTable();
} }
updateCount() { _updateCount() {
this.count.innerHTML = `length=${this._selectedLogEntries.length}`; this.count.innerHTML = `length=${this._selectedLogEntries.length}`;
} }
updateTable(event) { _updateTable(event) {
let select = this.groupKey; let select = this.groupKey;
let key = select.options[select.selectedIndex].text; let key = select.options[select.selectedIndex].text;
DOM.removeAllChildren(this.tableBody); DOM.removeAllChildren(this.tableBody);
let groups = Group.groupBy(this._selectedLogEntries, key, true); let groups = Group.groupBy(this._selectedLogEntries, key, true);
this.render(groups, this.tableBody); this._render(groups, this.tableBody);
} }
escapeHtml(unsafe) { escapeHtml(unsafe) {
@ -102,7 +101,7 @@ DOM.defineCustomElement(
this.dispatchEvent(new FocusEvent(sourcePosition)); this.dispatchEvent(new FocusEvent(sourcePosition));
} }
render(groups, parent) { _render(groups, parent) {
const fragment = document.createDocumentFragment(); const fragment = document.createDocumentFragment();
const max = Math.min(1000, groups.length) const max = Math.min(1000, groups.length)
const detailsClickHandler = this.handleDetailsClick.bind(this); const detailsClickHandler = this.handleDetailsClick.bind(this);
@ -176,7 +175,7 @@ DOM.defineCustomElement(
`Grouped by ${key} [top ${max} out of ${children.length}]`; `Grouped by ${key} [top ${max} out of ${children.length}]`;
td.appendChild(div); td.appendChild(div);
const table = DOM.table(); const table = DOM.table();
this.render(children.slice(0, max), table, false) this._render(children.slice(0, max), table, false)
td.appendChild(table); td.appendChild(table);
} }

View File

@ -17,11 +17,11 @@ DOM.defineCustomElement('log-file-reader',
} }
set error(message) { set error(message) {
this.updateLabel(message); this._updateLabel(message);
this.root.className = 'fail'; this.root.className = 'fail';
} }
updateLabel(text) { _updateLabel(text) {
this.$('#label').innerText = text; this.$('#label').innerText = text;
} }
@ -73,7 +73,7 @@ DOM.defineCustomElement('log-file-reader',
handleFileLoad(e, file) { handleFileLoad(e, file) {
const chunk = e.target.result; const chunk = e.target.result;
this.updateLabel(`Finished loading '${file.name}'.`); this._updateLabel(`Finished loading '${file.name}'.`);
this.dispatchEvent(new CustomEvent('fileuploadend', { this.dispatchEvent(new CustomEvent('fileuploadend', {
bubbles: true, bubbles: true,
composed: true, composed: true,

View File

@ -21,7 +21,7 @@ DOM.defineCustomElement('map-panel',
handleUpdateMapDetails(e) { handleUpdateMapDetails(e) {
if (e.entry instanceof MapLogEntry) { if (e.entry instanceof MapLogEntry) {
this.mapDetailsPanel.mapDetails = e.entry; this.mapDetailsPanel.map = e.entry;
} }
} }
@ -41,10 +41,6 @@ DOM.defineCustomElement('map-panel',
return this.$('#searchBar'); return this.$('#searchBar');
} }
get mapDetails() {
return this.mapDetailsPanel.mapDetails;
}
set timeline(timeline) { set timeline(timeline) {
this._timeline = timeline; this._timeline = timeline;
} }

View File

@ -7,13 +7,14 @@ import {DOM, V8CustomElement} from '../helper.mjs';
DOM.defineCustomElement( DOM.defineCustomElement(
'./map-panel/map-details', './map-panel/map-details',
(templateText) => class MapDetails extends V8CustomElement { (templateText) => class MapDetails extends V8CustomElement {
_map;
constructor() { constructor() {
super(templateText); super(templateText);
this._filePositionNode.addEventListener( this._filePositionNode.onclick = e => this._handleFilePositionClick(e);
'click', e => this.handleFilePositionClick(e));
this.selectedMap = undefined;
} }
get mapDetails() {
get _mapDetails() {
return this.$('#mapDetails'); return this.$('#mapDetails');
} }
@ -21,25 +22,26 @@ DOM.defineCustomElement(
return this.$('#filePositionNode'); return this.$('#filePositionNode');
} }
setSelectedMap(value) { set map(map) {
this.selectedMap = value; if (this._map === map) return;
this._map = map;
this.update();
} }
set mapDetails(map) { _update() {
let details = ''; let details = '';
let clickableDetails = ''; let clickableDetails = '';
if (map) { if (this._map) {
clickableDetails += `ID: ${map.id}`; clickableDetails = `ID: ${this._map.id}`;
clickableDetails += `\nSource location: ${map.filePosition}`; clickableDetails += `\nSource location: ${this._map.filePosition}`;
details += `\n${map.description}`; details = this._map.description;
this.setSelectedMap(map);
} }
this._filePositionNode.innerText = clickableDetails; this._filePositionNode.innerText = clickableDetails;
this._filePositionNode.classList.add('clickable'); this._filePositionNode.classList.add('clickable');
this.mapDetails.innerText = details; this._mapDetails.innerText = details;
} }
handleFilePositionClick() { _handleFilePositionClick(event) {
this.dispatchEvent(new FocusEvent(this.selectedMap.sourcePosition)); this.dispatchEvent(new FocusEvent(this._map.sourcePosition));
} }
}); });

View File

@ -10,7 +10,7 @@ DOM.defineCustomElement('./map-panel/map-transitions',
_map; _map;
_selectedMapLogEntries; _selectedMapLogEntries;
_displayedMapsInTree; _displayedMapsInTree;
_showMapsUpdateId;
constructor() { constructor() {
super(templateText); super(templateText);
this.transitionView.addEventListener( this.transitionView.addEventListener(
@ -45,7 +45,7 @@ DOM.defineCustomElement('./map-panel/map-transitions',
} }
} }
selectMap(map) { _selectMap(map) {
this.dispatchEvent(new SelectionEvent([map])); this.dispatchEvent(new SelectionEvent([map]));
} }
@ -53,14 +53,10 @@ DOM.defineCustomElement('./map-panel/map-transitions',
if (this.currentMap === this._map) return; if (this.currentMap === this._map) return;
this.currentMap = this._map; this.currentMap = this._map;
this.selectedMapLogEntries = [this._map]; this.selectedMapLogEntries = [this._map];
this.showMaps(); this.update();
} }
showMaps() { _update() {
clearTimeout(this._showMapsUpdateId);
this._showMapsUpdateId = setTimeout(() => this._showMaps(), 250);
}
_showMaps() {
this.transitionView.style.display = 'none'; this.transitionView.style.display = 'none';
DOM.removeAllChildren(this.transitionView); DOM.removeAllChildren(this.transitionView);
this._displayedMapsInTree = new Set(); this._displayedMapsInTree = new Set();
@ -73,7 +69,7 @@ DOM.defineCustomElement('./map-panel/map-transitions',
set selectedMapLogEntries(list) { set selectedMapLogEntries(list) {
this._selectedMapLogEntries = list; this._selectedMapLogEntries = list;
this.showMaps(); this.update();
} }
get selectedMapLogEntries() { get selectedMapLogEntries() {
@ -149,7 +145,7 @@ DOM.defineCustomElement('./map-panel/map-transitions',
let node = DOM.div('map'); let node = DOM.div('map');
if (map.edge) node.style.backgroundColor = typeToColor(map.edge); if (map.edge) node.style.backgroundColor = typeToColor(map.edge);
node.map = map; node.map = map;
node.addEventListener('click', () => this.selectMap(map)); node.addEventListener('click', () => this._selectMap(map));
if (map.children.length > 1) { if (map.children.length > 1) {
node.innerText = map.children.length; node.innerText = map.children.length;
let showSubtree = DOM.div('showSubtransitions'); let showSubtree = DOM.div('showSubtransitions');

View File

@ -32,7 +32,7 @@ DOM.defineCustomElement(
this._transitions = value; this._transitions = value;
} }
filterUniqueTransitions(filter) { _filterUniqueTransitions(filter) {
// Returns a list of Maps whose parent is not in the list. // Returns a list of Maps whose parent is not in the list.
return this._selectedLogEntries.filter((map) => { return this._selectedLogEntries.filter((map) => {
if (filter(map) === false) return false; if (filter(map) === false) return false;
@ -42,13 +42,12 @@ DOM.defineCustomElement(
}); });
} }
async update() { _update() {
await delay(1); this._updateGeneralStats();
this.updateGeneralStats(); this._updateNamedTransitionsStats();
this.updateNamedTransitionsStats();
} }
updateGeneralStats() { _updateGeneralStats() {
console.assert(this._timeline !== undefined, 'Timeline not set yet!'); console.assert(this._timeline !== undefined, 'Timeline not set yet!');
let pairs = [ let pairs = [
['Transitions', 'primary', (e) => e.edge && e.edge.isTransition()], ['Transitions', 'primary', (e) => e.edge && e.edge.isTransition()],
@ -89,12 +88,12 @@ DOM.defineCustomElement(
// lazily compute the stats // lazily compute the stats
let node = e.target.parentNode; let node = e.target.parentNode;
if (node.maps == undefined) { if (node.maps == undefined) {
node.maps = this.filterUniqueTransitions(filter); node.maps = this._filterUniqueTransitions(filter);
} }
this.dispatchEvent(new SelectionEvent(node.maps)); this.dispatchEvent(new SelectionEvent(node.maps));
}; };
row.appendChild(DOM.td(name)); row.appendChild(DOM.td(name));
let count = this.count(filter); let count = this._count(filter);
row.appendChild(DOM.td(count)); row.appendChild(DOM.td(count));
let percent = Math.round((count / total) * 1000) / 10; let percent = Math.round((count / total) * 1000) / 10;
row.appendChild(DOM.td(percent.toFixed(1) + '%')); row.appendChild(DOM.td(percent.toFixed(1) + '%'));
@ -103,7 +102,7 @@ DOM.defineCustomElement(
this.$('#typeTable').replaceChild(tbody, this.$('#typeTable tbody')); this.$('#typeTable').replaceChild(tbody, this.$('#typeTable tbody'));
} }
count(filter) { _count(filter) {
let count = 0; let count = 0;
for (const map of this._selectedLogEntries) { for (const map of this._selectedLogEntries) {
if (filter(map)) count++; if (filter(map)) count++;
@ -111,7 +110,7 @@ DOM.defineCustomElement(
return count; return count;
} }
updateNamedTransitionsStats() { _updateNamedTransitionsStats() {
let rowData = Array.from(this._transitions.entries()); let rowData = Array.from(this._transitions.entries());
rowData.sort((a, b) => b[1].length - a[1].length); rowData.sort((a, b) => b[1].length - a[1].length);
new LazyTable(this.$('#nameTable'), rowData, ([name, maps]) => { new LazyTable(this.$('#nameTable'), rowData, ([name, maps]) => {

View File

@ -50,7 +50,6 @@ DOM.defineCustomElement(
} }
for (const track of this.timelineTracks) { for (const track of this.timelineTracks) {
track.timeSelection = timeSelection; track.timeSelection = timeSelection;
;
} }
} }
}); });

View File

@ -167,9 +167,13 @@ DOM.defineCustomElement('./timeline/timeline-track',
set data(value) { set data(value) {
this._timeline = value; this._timeline = value;
this._resetTypeToColorCache(); this._resetTypeToColorCache();
this.updateChunks(); this.update();
this.updateTimeline(); }
this.renderLegend();
_update() {
this._updateChunks();
this._updateTimeline();
this._renderLegend();
} }
_resetTypeToColorCache() { _resetTypeToColorCache() {
@ -186,15 +190,14 @@ DOM.defineCustomElement('./timeline/timeline-track',
set nofChunks(count) { set nofChunks(count) {
this._nofChunks = count; this._nofChunks = count;
this.updateChunks(); this.update();
this.updateTimeline();
} }
get nofChunks() { get nofChunks() {
return this._nofChunks; return this._nofChunks;
} }
updateChunks() { _updateChunks() {
this._chunks = this.data.chunks(this.nofChunks); this._chunks = this.data.chunks(this.nofChunks);
} }
@ -219,7 +222,7 @@ DOM.defineCustomElement('./timeline/timeline-track',
return this._typeToColor.get(type); return this._typeToColor.get(type);
} }
renderLegend() { _renderLegend() {
let timelineLegendContent = this.timelineLegendContent; let timelineLegendContent = this.timelineLegendContent;
DOM.removeAllChildren(timelineLegendContent); DOM.removeAllChildren(timelineLegendContent);
this._timeline.uniqueTypes.forEach((entries, type) => { this._timeline.uniqueTypes.forEach((entries, type) => {
@ -308,7 +311,7 @@ DOM.defineCustomElement('./timeline/timeline-track',
node.style.backgroundImage = `url(${imageData})`; node.style.backgroundImage = `url(${imageData})`;
} }
updateTimeline() { _updateTimeline() {
let chunksNode = this.timelineChunks; let chunksNode = this.timelineChunks;
DOM.removeAllChildren(chunksNode); DOM.removeAllChildren(chunksNode);
let chunks = this.chunks; let chunks = this.chunks;