Commit a2de6939 authored by Zeynep Cankara's avatar Zeynep Cankara Committed by Commit Bot

[tools][system-analyzer] Add helper class

This CL adds a helper class for commonly used
helper methods inside web components, decreasing
the amount of duplicated code across the app.

Bug: v8:10667, v8:10644

Change-Id: I754396a9b3598d0930a82fc487857e946bfd3805
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2299359Reviewed-by: 's avatarCamillo Bruni <cbruni@chromium.org>
Commit-Queue: Zeynep Cankara <zcankara@google.com>
Cr-Commit-Position: refs/heads/master@{#68899}
parent c7e58ce9
......@@ -29,3 +29,67 @@ function defineCustomElement(name, generator) {
.then(
templateText => customElements.define(name, generator(templateText)));
}
// DOM Helpers
function removeAllChildren(node) {
let range = document.createRange();
range.selectNodeContents(node);
range.deleteContents();
}
function $(id) {
return document.querySelector(id)
}
function div(classes) {
let node = document.createElement('div');
if (classes !== void 0) {
if (typeof classes === 'string') {
node.classList.add(classes);
} else {
classes.forEach(cls => node.classList.add(cls));
}
}
return node;
}
class V8CustomElement extends HTMLElement {
constructor(templateText) {
super();
const shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.innerHTML = templateText;
}
$(id) {
return this.shadowRoot.querySelector(id);
}
querySelectorAll(query) {
return this.shadowRoot.querySelectorAll(query);
}
div(classes) {return div(classes)}
table(className) {
let node = document.createElement('table')
if (className) node.classList.add(className)
return node;
}
td(textOrNode) {
let node = document.createElement('td');
if (typeof textOrNode === 'object') {
node.appendChild(textOrNode);
} else {
node.innerText = textOrNode;
}
return node;
}
tr(){
return document.createElement('tr');
}
removeAllChildren(node) { return removeAllChildren(node); }
}
export {defineCustomElement, V8CustomElement, removeAllChildren, $, div};
......@@ -4,13 +4,12 @@
import {Group} from './ic-model.mjs';
import CustomIcProcessor from "./ic-processor.mjs";
import {defineCustomElement, V8CustomElement} from './helper.mjs';
defineCustomElement('ic-panel', (templateText) =>
class ICPanel extends HTMLElement {
class ICPanel extends V8CustomElement {
constructor() {
super();
const shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.innerHTML = templateText;
super(templateText);
this.groupKey.addEventListener(
'change', e => this.updateTable(e));
this.$('#filterICTimeBtn').addEventListener(
......@@ -20,14 +19,6 @@ defineCustomElement('ic-panel', (templateText) =>
this._endTime = 0;
}
$(id) {
return this.shadowRoot.querySelector(id);
}
querySelectorAll(query) {
return this.shadowRoot.querySelectorAll(query);
}
set entries(value){
this._entries = value;
}
......@@ -108,12 +99,6 @@ defineCustomElement('ic-panel', (templateText) =>
return a;
}
removeAllChildren(node) {
while (node.firstChild) {
node.removeChild(node.firstChild);
}
}
td(tr, content, className) {
let node = document.createElement("td");
if (typeof content == "object") {
......
......@@ -13,7 +13,7 @@ found in the LICENSE file. -->
<script type="module" src="index.mjs"></script>
<script type="module" src="index.mjs"></script>
<link rel="stylesheet" type="text/css" href="./index.css">
<script src="helper.js"></script>
<script type="module" src="helper.mjs"></script>
<script src="../splaytree.js"></script>
<script src="../codemap.js"></script>
......
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {defineCustomElement, V8CustomElement} from './helper.mjs';
defineCustomElement('log-file-reader', (templateText) =>
class LogFileReader extends HTMLElement {
class LogFileReader extends V8CustomElement {
constructor() {
super();
const shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.innerHTML = templateText;
super(templateText);
this.addEventListener('click', e => this.handleClick(e));
this.addEventListener('dragover', e => this.handleDragOver(e));
this.addEventListener('drop', e => this.handleChange(e));
......@@ -15,10 +14,6 @@ defineCustomElement('log-file-reader', (templateText) =>
this.$('#fileReader').addEventListener('keydown', e => this.handleKeyEvent(e));
}
$(id) {
return this.shadowRoot.querySelector(id);
}
get section() {
return this.$('#fileReaderSection');
}
......
......@@ -3,6 +3,9 @@
// found in the LICENSE file.
import {kChunkWidth, kChunkHeight} from './map-processor.mjs';
import {div, removeAllChildren, $} from './helper.mjs';
class State {
constructor(mapPanelId, timelinePanelId) {
......@@ -68,60 +71,6 @@ class State {
}
}
// =========================================================================
// DOM Helper
function $(id) {
return document.querySelector(id)
}
function removeAllChildren(node) {
while (node.lastChild) {
node.removeChild(node.lastChild);
}
}
function selectOption(select, match) {
let options = select.options;
for (let i = 0; i < options.length; i++) {
if (match(i, options[i])) {
select.selectedIndex = i;
return;
}
}
}
function div(classes) {
let node = document.createElement('div');
if (classes !== void 0) {
if (typeof classes === 'string') {
node.classList.add(classes);
} else {
classes.forEach(cls => node.classList.add(cls));
}
}
return node;
}
function table(className) {
let node = document.createElement('table')
if (className) node.classList.add(className)
return node;
}
function td(textOrNode) {
let node = document.createElement('td');
if (typeof textOrNode === 'object') {
node.appendChild(textOrNode);
} else {
node.innerText = textOrNode;
}
return node;
}
function tr() {
return document.createElement('tr');
}
class Navigation {
constructor(state, view) {
this.state = state;
......@@ -695,4 +644,4 @@ function transitionTypeToColor(type) {
return '#9B6EDC';
}
export { State, div, table, tr, td};
\ No newline at end of file
export { State };
\ No newline at end of file
......@@ -3,27 +3,18 @@
// found in the LICENSE file.
import "./stats-panel.mjs";
import {V8Map} from "./map-processor.mjs";
import {defineCustomElement, V8CustomElement} from './helper.mjs';
defineCustomElement('map-panel', (templateText) =>
class MapPanel extends HTMLElement {
class MapPanel extends V8CustomElement {
constructor() {
super();
const shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.innerHTML = templateText;
super(templateText);
this.transitionView.addEventListener(
'mousemove', e => this.handleTransitionViewChange(e));
this.$('#searchBarBtn').addEventListener(
'click', e => this.handleSearchBar(e));
}
$(id) {
return this.shadowRoot.querySelector(id);
}
querySelectorAll(query) {
return this.shadowRoot.querySelectorAll(query);
}
get transitionView() {
return this.$('#transitionView');
}
......
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {div, table, tr, td} from './map-model.mjs';
import {V8CustomElement, defineCustomElement} from './helper.mjs';
defineCustomElement('stats-panel', (templateText) =>
class StatsPanel extends HTMLElement {
class StatsPanel extends V8CustomElement {
constructor() {
super();
const shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.innerHTML = templateText;
super(templateText);
this.timeline_ = undefined;
}
$(id) {
return this.shadowRoot.querySelector(id);
}
querySelectorAll(query) {
return this.shadowRoot.querySelectorAll(query);
}
get stats() {
return this.$('#stats');
}
// decouple stats panel
removeAllChildren(node) {
while (node.lastChild) {
node.removeChild(node.lastChild);
}
}
set timeline(value){
this.timeline_ = value;
}
......@@ -68,18 +50,18 @@ defineCustomElement('stats-panel', (templateText) =>
];
let text = '';
let tableNode = table('transitionType');
let tableNode = this.table('transitionType');
tableNode.innerHTML =
'<thead><tr><td>Color</td><td>Type</td><td>Count</td><td>Percent</td></tr></thead>';
let name, filter;
//TODO(zc) timeline
let total = this.timeline.size();
pairs.forEach(([name, color, filter]) => {
let row = tr();
let row = this.tr();
if (color !== null) {
row.appendChild(td(div(['colorbox', color])));
row.appendChild(this.td(this.div(['colorbox', color])));
} else {
row.appendChild(td(''));
row.appendChild(this.td(''));
}
row.onclick = (e) => {
// lazily compute the stats
......@@ -90,32 +72,32 @@ defineCustomElement('stats-panel', (templateText) =>
this.dispatchEvent(new CustomEvent(
'change', {bubbles: true, composed: true, detail: node.maps}));
};
row.appendChild(td(name));
row.appendChild(this.td(name));
let count = this.timeline.count(filter);
row.appendChild(td(count));
row.appendChild(this.td(count));
let percent = Math.round(count / total * 1000) / 10;
row.appendChild(td(percent.toFixed(1) + '%'));
row.appendChild(this.td(percent.toFixed(1) + '%'));
tableNode.appendChild(row);
});
this.stats.appendChild(tableNode);
}
updateNamedTransitionsStats() {
let tableNode = table('transitionTable');
let tableNode = this.table('transitionTable');
let nameMapPairs = Array.from(this.timeline.transitions.entries());
tableNode.innerHTML =
'<thead><tr><td>Propery Name</td><td>#</td></tr></thead>';
nameMapPairs.sort((a, b) => b[1].length - a[1].length).forEach(([
name, maps
]) => {
let row = tr();
let row = this.tr();
row.maps = maps;
row.addEventListener(
'click',
e => this.dispatchEvent(new CustomEvent(
'change', {bubbles: true, composed: true, detail: e.target.parentNode.maps.map(map => map.to)})));
row.appendChild(td(name));
row.appendChild(td(maps.length));
row.appendChild(this.td(name));
row.appendChild(this.td(maps.length));
tableNode.appendChild(row);
});
this.stats.appendChild(tableNode);
......
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {defineCustomElement, V8CustomElement} from './helper.mjs';
defineCustomElement('timeline-panel', (templateText) =>
class TimelinePanel extends HTMLElement {
class TimelinePanel extends V8CustomElement {
constructor() {
super();
const shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.innerHTML = templateText;
super(templateText);
this.timelineOverview.addEventListener(
'mousemove', e => this.handleTimelineIndicatorMove(e));
}
$(id) {
return this.shadowRoot.querySelector(id);
}
querySelectorAll(query) {
return this.shadowRoot.querySelectorAll(query);
}
get timelineOverview() {
return this.$('#timelineOverview');
}
......@@ -41,7 +31,6 @@ defineCustomElement('timeline-panel', (templateText) =>
return this.$('#timeline');
}
handleTimelineIndicatorMove(event) {
if (event.buttons == 0) return;
let timelineTotalWidth = this.timelineCanvas.offsetWidth;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment