tor-browser

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

HSplitBox.js (4790B)


      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 file,
      3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 "use strict";
      6 
      7 // A box with a start and a end pane, separated by a dragable splitter that
      8 // allows the user to resize the relative widths of the panes.
      9 //
     10 //     +-----------------------+---------------------+
     11 //     |                       |                     |
     12 //     |                       |                     |
     13 //     |                       S                     |
     14 //     |      Start Pane       p     End Pane        |
     15 //     |                       l                     |
     16 //     |                       i                     |
     17 //     |                       t                     |
     18 //     |                       t                     |
     19 //     |                       e                     |
     20 //     |                       r                     |
     21 //     |                       |                     |
     22 //     |                       |                     |
     23 //     +-----------------------+---------------------+
     24 
     25 const {
     26  Component,
     27 } = require("resource://devtools/client/shared/vendor/react.mjs");
     28 const PropTypes = require("resource://devtools/client/shared/vendor/react-prop-types.mjs");
     29 const dom = require("resource://devtools/client/shared/vendor/react-dom-factories.js");
     30 
     31 class HSplitBox extends Component {
     32  static get propTypes() {
     33    return {
     34      // The contents of the start pane.
     35      start: PropTypes.any.isRequired,
     36 
     37      // The contents of the end pane.
     38      end: PropTypes.any.isRequired,
     39 
     40      // The relative width of the start pane, expressed as a number between 0 and
     41      // 1. The relative width of the end pane is 1 - startWidth. For example,
     42      // with startWidth = .5, both panes are of equal width; with startWidth =
     43      // .25, the start panel will take up 1/4 width and the end panel will take
     44      // up 3/4 width.
     45      startWidth: PropTypes.number,
     46 
     47      // A minimum css width value for the start and end panes.
     48      minStartWidth: PropTypes.any,
     49      minEndWidth: PropTypes.any,
     50 
     51      // A callback fired when the user drags the splitter to resize the relative
     52      // pane widths. The function is passed the startWidth value that would put
     53      // the splitter underneath the users mouse.
     54      onResize: PropTypes.func.isRequired,
     55    };
     56  }
     57 
     58  static get defaultProps() {
     59    return {
     60      startWidth: 0.5,
     61      minStartWidth: "20px",
     62      minEndWidth: "20px",
     63    };
     64  }
     65 
     66  constructor(props) {
     67    super(props);
     68 
     69    this.state = {
     70      mouseDown: false,
     71    };
     72 
     73    this._onMouseDown = this._onMouseDown.bind(this);
     74    this._onMouseUp = this._onMouseUp.bind(this);
     75    this._onMouseMove = this._onMouseMove.bind(this);
     76  }
     77 
     78  componentDidMount() {
     79    document.defaultView.addEventListener("mouseup", this._onMouseUp, true);
     80    document.defaultView.addEventListener("mousemove", this._onMouseMove, true);
     81  }
     82 
     83  componentWillUnmount() {
     84    document.defaultView.removeEventListener("mouseup", this._onMouseUp, true);
     85    document.defaultView.removeEventListener(
     86      "mousemove",
     87      this._onMouseMove,
     88      true
     89    );
     90  }
     91 
     92  _onMouseDown(event) {
     93    if (event.button !== 0) {
     94      return;
     95    }
     96 
     97    this.setState({ mouseDown: true });
     98    event.preventDefault();
     99  }
    100 
    101  _onMouseUp(event) {
    102    if (event.button !== 0 || !this.state.mouseDown) {
    103      return;
    104    }
    105 
    106    this.setState({ mouseDown: false });
    107    event.preventDefault();
    108  }
    109 
    110  _onMouseMove(event) {
    111    if (!this.state.mouseDown) {
    112      return;
    113    }
    114 
    115    const rect = this.refs.box.getBoundingClientRect();
    116    const { left, right } = rect;
    117    const width = right - left;
    118    const direction = this.refs.box.ownerDocument.dir;
    119    const relative =
    120      direction == "rtl" ? right - event.clientX : event.clientX - left;
    121    this.props.onResize(relative / width);
    122 
    123    event.preventDefault();
    124  }
    125 
    126  render() {
    127    const { start, end, startWidth, minStartWidth, minEndWidth } = this.props;
    128 
    129    // Values outside of [0, 1] have no effect thanks to flex + minWidth.
    130    const clampedStartWidth = Math.min(Math.max(startWidth, 0), 1);
    131 
    132    return dom.div(
    133      {
    134        className: "h-split-box",
    135        ref: "box",
    136      },
    137 
    138      dom.div(
    139        {
    140          className: "h-split-box-pane",
    141          style: { flex: clampedStartWidth, minWidth: minStartWidth },
    142        },
    143        start
    144      ),
    145 
    146      dom.div({
    147        className: "devtools-side-splitter",
    148        onMouseDown: this._onMouseDown,
    149      }),
    150 
    151      dom.div(
    152        {
    153          className: "h-split-box-pane",
    154          style: { flex: 1 - clampedStartWidth, minWidth: minEndWidth },
    155        },
    156        end
    157      )
    158    );
    159  }
    160 }
    161 
    162 module.exports = HSplitBox;