11cb0ef41Sopenharmony_ci// Copyright 2020 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ciimport {FocusEvent, SelectRelatedEvent, ToolTipEvent} from '../events.mjs'; 51cb0ef41Sopenharmony_ciimport {CSSColor} from '../helper.mjs'; 61cb0ef41Sopenharmony_ciimport {DOM, V8CustomElement} from '../helper.mjs'; 71cb0ef41Sopenharmony_ci 81cb0ef41Sopenharmony_ciDOM.defineCustomElement('./view/map-panel/map-transitions', 91cb0ef41Sopenharmony_ci (templateText) => 101cb0ef41Sopenharmony_ci class MapTransitions extends V8CustomElement { 111cb0ef41Sopenharmony_ci _timeline; 121cb0ef41Sopenharmony_ci _map; 131cb0ef41Sopenharmony_ci _edgeToColor = new Map(); 141cb0ef41Sopenharmony_ci _selectedLogEntries; 151cb0ef41Sopenharmony_ci _displayedMapsInTree; 161cb0ef41Sopenharmony_ci _toggleSubtreeHandler = this._handleToggleSubtree.bind(this); 171cb0ef41Sopenharmony_ci _mapClickHandler = this._handleMapClick.bind(this); 181cb0ef41Sopenharmony_ci _mapDoubleClickHandler = this._handleMapDoubleClick.bind(this); 191cb0ef41Sopenharmony_ci _mouseoverMapHandler = this._handleMouseoverMap.bind(this); 201cb0ef41Sopenharmony_ci 211cb0ef41Sopenharmony_ci constructor() { 221cb0ef41Sopenharmony_ci super(templateText); 231cb0ef41Sopenharmony_ci this.currentNode = this.transitionView; 241cb0ef41Sopenharmony_ci } 251cb0ef41Sopenharmony_ci 261cb0ef41Sopenharmony_ci get transitionView() { 271cb0ef41Sopenharmony_ci return this.$('#transitionView'); 281cb0ef41Sopenharmony_ci } 291cb0ef41Sopenharmony_ci 301cb0ef41Sopenharmony_ci set timeline(timeline) { 311cb0ef41Sopenharmony_ci this._timeline = timeline; 321cb0ef41Sopenharmony_ci this._edgeToColor.clear(); 331cb0ef41Sopenharmony_ci timeline.getBreakdown().forEach(breakdown => { 341cb0ef41Sopenharmony_ci this._edgeToColor.set(breakdown.key, CSSColor.at(breakdown.id)); 351cb0ef41Sopenharmony_ci }); 361cb0ef41Sopenharmony_ci } 371cb0ef41Sopenharmony_ci 381cb0ef41Sopenharmony_ci set selectedLogEntries(list) { 391cb0ef41Sopenharmony_ci this._selectedLogEntries = list; 401cb0ef41Sopenharmony_ci this.requestUpdate(); 411cb0ef41Sopenharmony_ci } 421cb0ef41Sopenharmony_ci 431cb0ef41Sopenharmony_ci _update() { 441cb0ef41Sopenharmony_ci this.transitionView.style.display = 'none'; 451cb0ef41Sopenharmony_ci DOM.removeAllChildren(this.transitionView); 461cb0ef41Sopenharmony_ci if (this._selectedLogEntries.length == 0) return; 471cb0ef41Sopenharmony_ci this._displayedMapsInTree = new Set(); 481cb0ef41Sopenharmony_ci // Limit view to 200 maps for performance reasons. 491cb0ef41Sopenharmony_ci this._selectedLogEntries.slice(0, 200).forEach( 501cb0ef41Sopenharmony_ci (map) => this._addMapAndParentTransitions(map)); 511cb0ef41Sopenharmony_ci this._displayedMapsInTree = undefined; 521cb0ef41Sopenharmony_ci this.transitionView.style.display = ''; 531cb0ef41Sopenharmony_ci } 541cb0ef41Sopenharmony_ci 551cb0ef41Sopenharmony_ci _addMapAndParentTransitions(map) { 561cb0ef41Sopenharmony_ci if (map === undefined) return; 571cb0ef41Sopenharmony_ci if (this._displayedMapsInTree.has(map)) return; 581cb0ef41Sopenharmony_ci this._displayedMapsInTree.add(map); 591cb0ef41Sopenharmony_ci this.currentNode = this.transitionView; 601cb0ef41Sopenharmony_ci let parents = map.getParents(); 611cb0ef41Sopenharmony_ci if (parents.length > 0) { 621cb0ef41Sopenharmony_ci this._addTransitionTo(parents.pop()); 631cb0ef41Sopenharmony_ci parents.reverse().forEach((each) => this._addTransitionTo(each)); 641cb0ef41Sopenharmony_ci } 651cb0ef41Sopenharmony_ci let mapNode = this._addSubtransitions(map); 661cb0ef41Sopenharmony_ci // Mark and show the selected map. 671cb0ef41Sopenharmony_ci mapNode.classList.add('selected'); 681cb0ef41Sopenharmony_ci if (this.selectedMap == map) { 691cb0ef41Sopenharmony_ci setTimeout( 701cb0ef41Sopenharmony_ci () => mapNode.scrollIntoView({ 711cb0ef41Sopenharmony_ci behavior: 'smooth', 721cb0ef41Sopenharmony_ci block: 'nearest', 731cb0ef41Sopenharmony_ci inline: 'nearest', 741cb0ef41Sopenharmony_ci }), 751cb0ef41Sopenharmony_ci 1); 761cb0ef41Sopenharmony_ci } 771cb0ef41Sopenharmony_ci } 781cb0ef41Sopenharmony_ci 791cb0ef41Sopenharmony_ci _addSubtransitions(map) { 801cb0ef41Sopenharmony_ci let mapNode = this._addTransitionTo(map); 811cb0ef41Sopenharmony_ci // Draw outgoing linear transition line. 821cb0ef41Sopenharmony_ci let current = map; 831cb0ef41Sopenharmony_ci while (current.children.length == 1) { 841cb0ef41Sopenharmony_ci current = current.children[0].to; 851cb0ef41Sopenharmony_ci this._addTransitionTo(current); 861cb0ef41Sopenharmony_ci } 871cb0ef41Sopenharmony_ci return mapNode; 881cb0ef41Sopenharmony_ci } 891cb0ef41Sopenharmony_ci 901cb0ef41Sopenharmony_ci _addTransitionEdge(map) { 911cb0ef41Sopenharmony_ci let classes = ['transitionEdge']; 921cb0ef41Sopenharmony_ci let edge = DOM.div(classes); 931cb0ef41Sopenharmony_ci edge.style.backgroundColor = this._edgeToColor.get(map.edge.type); 941cb0ef41Sopenharmony_ci let labelNode = DOM.div('transitionLabel'); 951cb0ef41Sopenharmony_ci labelNode.innerText = map.edge.toString(); 961cb0ef41Sopenharmony_ci edge.appendChild(labelNode); 971cb0ef41Sopenharmony_ci return edge; 981cb0ef41Sopenharmony_ci } 991cb0ef41Sopenharmony_ci 1001cb0ef41Sopenharmony_ci _addTransitionTo(map) { 1011cb0ef41Sopenharmony_ci // transition[ transitions[ transition[...], transition[...], ...]]; 1021cb0ef41Sopenharmony_ci this._displayedMapsInTree?.add(map); 1031cb0ef41Sopenharmony_ci let transition = DOM.div('transition'); 1041cb0ef41Sopenharmony_ci if (map.isDeprecated()) transition.classList.add('deprecated'); 1051cb0ef41Sopenharmony_ci if (map.edge) { 1061cb0ef41Sopenharmony_ci transition.appendChild(this._addTransitionEdge(map)); 1071cb0ef41Sopenharmony_ci } 1081cb0ef41Sopenharmony_ci let mapNode = this._addMapNode(map); 1091cb0ef41Sopenharmony_ci transition.appendChild(mapNode); 1101cb0ef41Sopenharmony_ci 1111cb0ef41Sopenharmony_ci let subtree = DOM.div('transitions'); 1121cb0ef41Sopenharmony_ci transition.appendChild(subtree); 1131cb0ef41Sopenharmony_ci 1141cb0ef41Sopenharmony_ci this.currentNode.appendChild(transition); 1151cb0ef41Sopenharmony_ci this.currentNode = subtree; 1161cb0ef41Sopenharmony_ci 1171cb0ef41Sopenharmony_ci return mapNode; 1181cb0ef41Sopenharmony_ci } 1191cb0ef41Sopenharmony_ci 1201cb0ef41Sopenharmony_ci _addMapNode(map) { 1211cb0ef41Sopenharmony_ci let node = DOM.div('map'); 1221cb0ef41Sopenharmony_ci if (map.edge) 1231cb0ef41Sopenharmony_ci node.style.backgroundColor = this._edgeToColor.get(map.edge.type); 1241cb0ef41Sopenharmony_ci node.map = map; 1251cb0ef41Sopenharmony_ci node.onclick = this._mapClickHandler 1261cb0ef41Sopenharmony_ci node.ondblclick = this._mapDoubleClickHandler 1271cb0ef41Sopenharmony_ci node.onmouseover = this._mouseoverMapHandler 1281cb0ef41Sopenharmony_ci if (map.children.length > 1) { 1291cb0ef41Sopenharmony_ci node.innerText = map.children.length; 1301cb0ef41Sopenharmony_ci const showSubtree = DOM.div('showSubtransitions'); 1311cb0ef41Sopenharmony_ci showSubtree.onclick = this._toggleSubtreeHandler 1321cb0ef41Sopenharmony_ci node.appendChild(showSubtree); 1331cb0ef41Sopenharmony_ci } 1341cb0ef41Sopenharmony_ci else if (map.children.length == 0) { 1351cb0ef41Sopenharmony_ci node.innerHTML = '●'; 1361cb0ef41Sopenharmony_ci } 1371cb0ef41Sopenharmony_ci this.currentNode.appendChild(node); 1381cb0ef41Sopenharmony_ci return node; 1391cb0ef41Sopenharmony_ci } 1401cb0ef41Sopenharmony_ci 1411cb0ef41Sopenharmony_ci _handleMapClick(event) { 1421cb0ef41Sopenharmony_ci const map = event.currentTarget.map; 1431cb0ef41Sopenharmony_ci this.dispatchEvent(new FocusEvent(map)); 1441cb0ef41Sopenharmony_ci } 1451cb0ef41Sopenharmony_ci 1461cb0ef41Sopenharmony_ci _handleMapDoubleClick(event) { 1471cb0ef41Sopenharmony_ci this.dispatchEvent(new SelectRelatedEvent(event.currentTarget.map)); 1481cb0ef41Sopenharmony_ci } 1491cb0ef41Sopenharmony_ci 1501cb0ef41Sopenharmony_ci _handleMouseoverMap(event) { 1511cb0ef41Sopenharmony_ci this.dispatchEvent( 1521cb0ef41Sopenharmony_ci new ToolTipEvent(event.currentTarget.map, event.currentTarget)); 1531cb0ef41Sopenharmony_ci } 1541cb0ef41Sopenharmony_ci 1551cb0ef41Sopenharmony_ci _handleToggleSubtree(event) { 1561cb0ef41Sopenharmony_ci event.stopImmediatePropagation(); 1571cb0ef41Sopenharmony_ci const node = event.currentTarget.parentElement; 1581cb0ef41Sopenharmony_ci const map = node.map; 1591cb0ef41Sopenharmony_ci event.target.classList.toggle('opened'); 1601cb0ef41Sopenharmony_ci const transitionsNode = node.parentElement.querySelector('.transitions'); 1611cb0ef41Sopenharmony_ci const subtransitionNodes = transitionsNode.children; 1621cb0ef41Sopenharmony_ci if (subtransitionNodes.length <= 1) { 1631cb0ef41Sopenharmony_ci // Add subtransitions except the one that's already shown. 1641cb0ef41Sopenharmony_ci let visibleTransitionMap = subtransitionNodes.length == 1 ? 1651cb0ef41Sopenharmony_ci transitionsNode.querySelector('.map').map : 1661cb0ef41Sopenharmony_ci undefined; 1671cb0ef41Sopenharmony_ci map.children.forEach((edge) => { 1681cb0ef41Sopenharmony_ci if (edge.to != visibleTransitionMap) { 1691cb0ef41Sopenharmony_ci this.currentNode = transitionsNode; 1701cb0ef41Sopenharmony_ci this._addSubtransitions(edge.to); 1711cb0ef41Sopenharmony_ci } 1721cb0ef41Sopenharmony_ci }); 1731cb0ef41Sopenharmony_ci } else { 1741cb0ef41Sopenharmony_ci // remove all but the first (currently selected) subtransition 1751cb0ef41Sopenharmony_ci for (let i = subtransitionNodes.length - 1; i > 0; i--) { 1761cb0ef41Sopenharmony_ci transitionsNode.removeChild(subtransitionNodes[i]); 1771cb0ef41Sopenharmony_ci } 1781cb0ef41Sopenharmony_ci } 1791cb0ef41Sopenharmony_ci return false; 1801cb0ef41Sopenharmony_ci } 1811cb0ef41Sopenharmony_ci}); 182