tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

AnimationTarget.js (5077B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 "use strict";
      6 
      7 const {
      8  Component,
      9 } = require("resource://devtools/client/shared/vendor/react.mjs");
     10 const {
     11  connect,
     12 } = require("resource://devtools/client/shared/vendor/react-redux.js");
     13 const PropTypes = require("resource://devtools/client/shared/vendor/react-prop-types.mjs");
     14 const dom = require("resource://devtools/client/shared/vendor/react-dom-factories.js");
     15 const {
     16  translateNodeFrontToGrip,
     17 } = require("resource://devtools/client/inspector/shared/utils.js");
     18 
     19 const { REPS, MODE } = ChromeUtils.importESModule(
     20  "resource://devtools/client/shared/components/reps/index.mjs"
     21 );
     22 const { Rep } = REPS;
     23 const ElementNode = REPS.ElementNode;
     24 
     25 const {
     26  getInspectorStr,
     27 } = require("resource://devtools/client/inspector/animation/utils/l10n.js");
     28 
     29 const {
     30  highlightNode,
     31  unhighlightNode,
     32 } = require("resource://devtools/client/inspector/boxmodel/actions/box-model-highlighter.js");
     33 
     34 class AnimationTarget extends Component {
     35  static get propTypes() {
     36    return {
     37      animation: PropTypes.object.isRequired,
     38      dispatch: PropTypes.func.isRequired,
     39      getNodeFromActor: PropTypes.func.isRequired,
     40      highlightedNode: PropTypes.string.isRequired,
     41      setHighlightedNode: PropTypes.func.isRequired,
     42      setSelectedNode: PropTypes.func.isRequired,
     43    };
     44  }
     45 
     46  constructor(props) {
     47    super(props);
     48 
     49    this.state = {
     50      nodeFront: null,
     51    };
     52  }
     53 
     54  // FIXME: https://bugzilla.mozilla.org/show_bug.cgi?id=1774507
     55  UNSAFE_componentWillMount() {
     56    this.updateNodeFront(this.props.animation);
     57  }
     58 
     59  // FIXME: https://bugzilla.mozilla.org/show_bug.cgi?id=1774507
     60  UNSAFE_componentWillReceiveProps(nextProps) {
     61    if (this.props.animation.actorID !== nextProps.animation.actorID) {
     62      this.updateNodeFront(nextProps.animation);
     63    }
     64  }
     65 
     66  shouldComponentUpdate(nextProps, nextState) {
     67    return (
     68      this.state.nodeFront !== nextState.nodeFront ||
     69      this.props.highlightedNode !== nextState.highlightedNode
     70    );
     71  }
     72 
     73  async updateNodeFront(animation) {
     74    const { getNodeFromActor } = this.props;
     75 
     76    // Try and get it from the playerFront directly.
     77    let nodeFront = animation.animationTargetNodeFront;
     78 
     79    // Next, get it from the walkerActor if it wasn't found.
     80    if (!nodeFront) {
     81      try {
     82        nodeFront = await getNodeFromActor(animation.actorID);
     83      } catch (e) {
     84        // If an error occured while getting the nodeFront and if it can't be
     85        // attributed to the panel having been destroyed in the meantime, this
     86        // error needs to be logged and render needs to stop.
     87        console.error(e);
     88        this.setState({ nodeFront: null });
     89        return;
     90      }
     91    }
     92 
     93    this.setState({ nodeFront });
     94  }
     95 
     96  async ensureNodeFront() {
     97    if (!this.state.nodeFront.actorID) {
     98      // In case of no actorID, the node front had been destroyed.
     99      // This will occur when the pseudo element was re-generated.
    100      await this.updateNodeFront(this.props.animation);
    101    }
    102  }
    103 
    104  async highlight() {
    105    await this.ensureNodeFront();
    106 
    107    if (this.state.nodeFront) {
    108      this.props.dispatch(
    109        highlightNode(this.state.nodeFront, {
    110          hideInfoBar: true,
    111          hideGuides: true,
    112        })
    113      );
    114    }
    115  }
    116 
    117  async select() {
    118    await this.ensureNodeFront();
    119 
    120    if (this.state.nodeFront) {
    121      this.props.setSelectedNode(this.state.nodeFront);
    122    }
    123  }
    124 
    125  render() {
    126    const { dispatch, highlightedNode, setHighlightedNode } = this.props;
    127    const { nodeFront } = this.state;
    128 
    129    if (!nodeFront) {
    130      return dom.div({
    131        className: "animation-target",
    132      });
    133    }
    134 
    135    const isHighlighted = nodeFront.actorID === highlightedNode;
    136 
    137    return dom.div(
    138      {
    139        className: "animation-target" + (isHighlighted ? " highlighting" : ""),
    140      },
    141      Rep({
    142        defaultRep: ElementNode,
    143        mode: MODE.TINY,
    144        inspectIconTitle: getInspectorStr(
    145          "inspector.nodePreview.highlightNodeLabel"
    146        ),
    147        inspectIconClassName: "highlight-node",
    148        object: translateNodeFrontToGrip(nodeFront),
    149        onDOMNodeClick: () => this.select(),
    150        onDOMNodeMouseOut: () => {
    151          if (!isHighlighted) {
    152            dispatch(unhighlightNode());
    153          }
    154        },
    155        onDOMNodeMouseOver: () => {
    156          if (!isHighlighted) {
    157            this.highlight();
    158          }
    159        },
    160        onInspectIconClick: (_, e) => {
    161          e.stopPropagation();
    162 
    163          if (!isHighlighted) {
    164            // At first, hide highlighter which was created by onDOMNodeMouseOver.
    165            dispatch(unhighlightNode());
    166          }
    167 
    168          setHighlightedNode(isHighlighted ? null : nodeFront);
    169        },
    170      })
    171    );
    172  }
    173 }
    174 
    175 const mapStateToProps = state => {
    176  return {
    177    highlightedNode: state.animations.highlightedNode,
    178  };
    179 };
    180 
    181 module.exports = connect(mapStateToProps)(AnimationTarget);