tor-browser

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

ExceptionPopup.js (3754B)


      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 import React, { Component } from "devtools/client/shared/vendor/react";
      6 import { div, span } from "devtools/client/shared/vendor/react-dom-factories";
      7 import PropTypes from "devtools/client/shared/vendor/react-prop-types";
      8 import { connect } from "devtools/client/shared/vendor/react-redux";
      9 
     10 const Reps = ChromeUtils.importESModule(
     11  "resource://devtools/client/shared/components/reps/index.mjs"
     12 );
     13 const {
     14  REPS: { StringRep },
     15 } = Reps;
     16 
     17 import actions from "../../../actions/index";
     18 
     19 import DebuggerImage from "../../shared/DebuggerImage";
     20 const classnames = require("resource://devtools/client/shared/classnames.js");
     21 const ANONYMOUS_FN_NAME = "<anonymous>";
     22 
     23 // The exception popup works in two modes:
     24 // a. when the stacktrace is closed the exception popup
     25 // gets closed when the mouse leaves the popup.
     26 // b. when the stacktrace is opened the exception popup
     27 // gets closed only by clicking outside the popup.
     28 class ExceptionPopup extends Component {
     29  constructor(props) {
     30    super(props);
     31    this.state = {
     32      isStacktraceExpanded: true,
     33    };
     34  }
     35 
     36  static get propTypes() {
     37    return {
     38      mouseout: PropTypes.func.isRequired,
     39      selectSourceURL: PropTypes.func.isRequired,
     40      exception: PropTypes.object.isRequired,
     41    };
     42  }
     43 
     44  onExceptionMessageClick() {
     45    const isStacktraceExpanded = this.state.isStacktraceExpanded;
     46    this.setState({ isStacktraceExpanded: !isStacktraceExpanded });
     47  }
     48 
     49  buildStackFrame(frame) {
     50    const { filename, lineNumber } = frame;
     51    const functionName = frame.functionName || ANONYMOUS_FN_NAME;
     52    return div(
     53      {
     54        className: "frame",
     55        onClick: () =>
     56          this.props.selectSourceURL(filename, {
     57            line: lineNumber,
     58          }),
     59      },
     60      span(
     61        {
     62          className: "title",
     63        },
     64        functionName
     65      ),
     66      span(
     67        {
     68          className: "location",
     69        },
     70        span(
     71          {
     72            className: "filename",
     73          },
     74          filename
     75        ),
     76        ":",
     77        span(
     78          {
     79            className: "line",
     80          },
     81          lineNumber
     82        )
     83      )
     84    );
     85  }
     86 
     87  renderStacktrace(stacktrace) {
     88    const isStacktraceExpanded = this.state.isStacktraceExpanded;
     89 
     90    if (stacktrace.length && isStacktraceExpanded) {
     91      return div(
     92        {
     93          className: "exception-stacktrace",
     94        },
     95        stacktrace.map(frame => this.buildStackFrame(frame))
     96      );
     97    }
     98    return null;
     99  }
    100 
    101  renderArrowIcon(stacktrace) {
    102    if (stacktrace.length) {
    103      return React.createElement(DebuggerImage, {
    104        name: "arrow",
    105        className: classnames({
    106          expanded: this.state.isStacktraceExpanded,
    107        }),
    108      });
    109    }
    110    return null;
    111  }
    112 
    113  render() {
    114    const {
    115      exception: { stacktrace, errorMessage },
    116      mouseout,
    117    } = this.props;
    118    return div(
    119      {
    120        className: "preview-popup exception-popup",
    121        dir: "ltr",
    122        onMouseLeave: () => mouseout(true, this.state.isStacktraceExpanded),
    123      },
    124      div(
    125        {
    126          className: "exception-message",
    127          onClick: () => this.onExceptionMessageClick(),
    128        },
    129        this.renderArrowIcon(stacktrace),
    130        StringRep.rep({
    131          object: errorMessage,
    132          useQuotes: false,
    133          className: "exception-text",
    134        })
    135      ),
    136      this.renderStacktrace(stacktrace)
    137    );
    138  }
    139 }
    140 
    141 const mapDispatchToProps = {
    142  selectSourceURL: actions.selectSourceURL,
    143 };
    144 
    145 export default connect(null, mapDispatchToProps)(ExceptionPopup);