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