tor-browser

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

Breakpoint.js (7568B)


      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, { PureComponent } from "devtools/client/shared/vendor/react";
      6 import {
      7  div,
      8  input,
      9  span,
     10 } from "devtools/client/shared/vendor/react-dom-factories";
     11 import PropTypes from "devtools/client/shared/vendor/react-prop-types";
     12 import { connect } from "devtools/client/shared/vendor/react-redux";
     13 import actions from "../../../actions/index";
     14 
     15 import { CloseButton } from "../../shared/Button/index";
     16 
     17 import {
     18  getSelectedText,
     19  makeBreakpointId,
     20 } from "../../../utils/breakpoint/index";
     21 import { getSelectedLocation } from "../../../utils/selected-location";
     22 import { isLineBlackboxed } from "../../../utils/source";
     23 
     24 import {
     25  getSelectedFrame,
     26  getSelectedSource,
     27  isSourceMapIgnoreListEnabled,
     28  isSourceOnSourceMapIgnoreList,
     29  getBlackBoxRanges,
     30 } from "../../../selectors/index";
     31 
     32 const classnames = require("resource://devtools/client/shared/classnames.js");
     33 
     34 class Breakpoint extends PureComponent {
     35  static get propTypes() {
     36    return {
     37      breakpoint: PropTypes.object.isRequired,
     38      disableBreakpoint: PropTypes.func.isRequired,
     39      editor: PropTypes.object.isRequired,
     40      enableBreakpoint: PropTypes.func.isRequired,
     41      openConditionalPanel: PropTypes.func.isRequired,
     42      removeBreakpoint: PropTypes.func.isRequired,
     43      selectSpecificLocation: PropTypes.func.isRequired,
     44      selectedBreakpointLocation: PropTypes.object.isRequired,
     45      isCurrentlyPausedAtBreakpoint: PropTypes.bool.isRequired,
     46      source: PropTypes.object.isRequired,
     47      checkSourceOnIgnoreList: PropTypes.func.isRequired,
     48      isBreakpointLineBlackboxed: PropTypes.bool,
     49      showBreakpointContextMenu: PropTypes.func.isRequired,
     50      breakpointText: PropTypes.string.isRequired,
     51    };
     52  }
     53 
     54  onContextMenu = event => {
     55    event.preventDefault();
     56 
     57    this.props.showBreakpointContextMenu(
     58      event,
     59      this.props.breakpoint,
     60      this.props.source
     61    );
     62  };
     63 
     64  stopClicks = event => event.stopPropagation();
     65 
     66  onDoubleClick = () => {
     67    const { breakpoint, openConditionalPanel } = this.props;
     68    if (breakpoint.options.condition) {
     69      openConditionalPanel(this.props.selectedBreakpointLocation);
     70    } else if (breakpoint.options.logValue) {
     71      openConditionalPanel(this.props.selectedBreakpointLocation, true);
     72    }
     73  };
     74 
     75  onKeyDown = event => {
     76    // Handling only the Enter/Space keys, bail if another key was pressed
     77    if (event.key !== "Enter" && event.key !== " ") {
     78      return;
     79    }
     80 
     81    if (event.shiftKey) {
     82      this.onDoubleClick();
     83      return;
     84    }
     85    this.selectBreakpoint(event);
     86  };
     87 
     88  selectBreakpoint = event => {
     89    // Ignore double click as we have a dedicated double click listener
     90    if (event.type == "click" && event.detail > 1) {
     91      return;
     92    }
     93    event.preventDefault();
     94    const { selectSpecificLocation } = this.props;
     95    selectSpecificLocation(this.props.selectedBreakpointLocation);
     96  };
     97 
     98  removeBreakpoint = event => {
     99    const { removeBreakpoint, breakpoint } = this.props;
    100    event.stopPropagation();
    101    removeBreakpoint(breakpoint);
    102  };
    103 
    104  handleBreakpointCheckbox = () => {
    105    const { breakpoint, enableBreakpoint, disableBreakpoint } = this.props;
    106    if (breakpoint.disabled) {
    107      enableBreakpoint(breakpoint);
    108    } else {
    109      disableBreakpoint(breakpoint);
    110    }
    111  };
    112 
    113  getBreakpointLocation() {
    114    const { source } = this.props;
    115    const { column, line } = this.props.selectedBreakpointLocation;
    116 
    117    const isWasm = source?.isWasm;
    118    // column is 0-based everywhere, but we want to display 1-based to the user.
    119    const columnVal = column ? `:${column + 1}` : "";
    120    const bpLocation = isWasm
    121      ? `0x${line.toString(16).toUpperCase()}`
    122      : `${line}${columnVal}`;
    123 
    124    return bpLocation;
    125  }
    126 
    127  highlightText(text = "", editor) {
    128    const htmlString = editor.highlightText(document, text);
    129    return { __html: htmlString };
    130  }
    131 
    132  render() {
    133    const { breakpoint, editor, isBreakpointLineBlackboxed, breakpointText } =
    134      this.props;
    135    const labelId = `${breakpoint.id}-label`;
    136    return div(
    137      {
    138        className: classnames({
    139          breakpoint,
    140          paused: this.props.isCurrentlyPausedAtBreakpoint,
    141          disabled: breakpoint.disabled,
    142          "is-conditional": !!breakpoint.options.condition,
    143          "is-log": !!breakpoint.options.logValue,
    144        }),
    145        onClick: this.selectBreakpoint,
    146        onDoubleClick: this.onDoubleClick,
    147        onContextMenu: this.onContextMenu,
    148        onKeyDown: this.onKeyDown,
    149        role: "button",
    150        tabIndex: 0,
    151        title: breakpointText,
    152      },
    153      input({
    154        id: breakpoint.id,
    155        type: "checkbox",
    156        className: "breakpoint-checkbox",
    157        checked: !breakpoint.disabled,
    158        disabled: isBreakpointLineBlackboxed,
    159        onChange: this.handleBreakpointCheckbox,
    160        onClick: this.stopClicks,
    161        "aria-labelledby": labelId,
    162      }),
    163      span(
    164        {
    165          id: labelId,
    166          className: "breakpoint-label cm-s-mozilla devtools-monospace",
    167        },
    168        span({
    169          className: "cm-highlighted",
    170          dangerouslySetInnerHTML: this.highlightText(breakpointText, editor),
    171        })
    172      ),
    173      div(
    174        {
    175          className: "breakpoint-line-close",
    176        },
    177        div(
    178          {
    179            className: "breakpoint-line devtools-monospace",
    180          },
    181          this.getBreakpointLocation()
    182        ),
    183        React.createElement(CloseButton, {
    184          handleClick: this.removeBreakpoint,
    185          tooltip: L10N.getStr("breakpoints.removeBreakpointTooltip"),
    186        })
    187      )
    188    );
    189  }
    190 }
    191 
    192 function isCurrentlyPausedAtBreakpoint(
    193  state,
    194  selectedBreakpointLocation,
    195  selectedSource
    196 ) {
    197  const frame = getSelectedFrame(state);
    198  if (!frame) {
    199    return false;
    200  }
    201  const bpId = makeBreakpointId(selectedBreakpointLocation);
    202  const frameId = makeBreakpointId(getSelectedLocation(frame, selectedSource));
    203  return bpId == frameId;
    204 }
    205 
    206 function getBreakpointText(breakpoint, selectedSource) {
    207  const { condition, logValue } = breakpoint.options;
    208  return logValue || condition || getSelectedText(breakpoint, selectedSource);
    209 }
    210 
    211 const mapStateToProps = (state, props) => {
    212  const { breakpoint, source } = props;
    213  const selectedSource = getSelectedSource(state);
    214  const selectedBreakpointLocation = getSelectedLocation(
    215    breakpoint,
    216    selectedSource
    217  );
    218  const blackboxedRangesForSource = getBlackBoxRanges(state)[source.url];
    219  const isSourceOnIgnoreList =
    220    isSourceMapIgnoreListEnabled(state) &&
    221    isSourceOnSourceMapIgnoreList(state, source);
    222  return {
    223    selectedBreakpointLocation,
    224    isCurrentlyPausedAtBreakpoint: isCurrentlyPausedAtBreakpoint(
    225      state,
    226      selectedBreakpointLocation,
    227      selectedSource
    228    ),
    229    isBreakpointLineBlackboxed: isLineBlackboxed(
    230      blackboxedRangesForSource,
    231      breakpoint.location.line,
    232      isSourceOnIgnoreList
    233    ),
    234    breakpointText: getBreakpointText(breakpoint, selectedSource),
    235  };
    236 };
    237 
    238 export default connect(mapStateToProps, {
    239  enableBreakpoint: actions.enableBreakpoint,
    240  removeBreakpoint: actions.removeBreakpoint,
    241  disableBreakpoint: actions.disableBreakpoint,
    242  selectSpecificLocation: actions.selectSpecificLocation,
    243  openConditionalPanel: actions.openConditionalPanel,
    244  showBreakpointContextMenu: actions.showBreakpointContextMenu,
    245 })(Breakpoint);