tor-browser

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

Draggable.js (3232B)


      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 const {
      8  createRef,
      9  Component,
     10 } = require("resource://devtools/client/shared/vendor/react.mjs");
     11 const PropTypes = require("resource://devtools/client/shared/vendor/react-prop-types.mjs");
     12 const dom = require("resource://devtools/client/shared/vendor/react-dom-factories.js");
     13 const {
     14  canPointerEventDrag,
     15 } = require("resource://devtools/client/shared/events.js");
     16 
     17 class Draggable extends Component {
     18  static get propTypes() {
     19    return {
     20      onMove: PropTypes.func.isRequired,
     21      onDoubleClick: PropTypes.func,
     22      onStart: PropTypes.func,
     23      onStop: PropTypes.func,
     24      style: PropTypes.object,
     25      title: PropTypes.string,
     26      className: PropTypes.string,
     27    };
     28  }
     29 
     30  constructor(props) {
     31    super(props);
     32 
     33    this.draggableEl = createRef();
     34 
     35    this.startDragging = this.startDragging.bind(this);
     36    this.stopDragging = this.stopDragging.bind(this);
     37    this.onDoubleClick = this.onDoubleClick.bind(this);
     38    this.onMove = this.onMove.bind(this);
     39 
     40    this.mouseX = 0;
     41    this.mouseY = 0;
     42  }
     43  startDragging(ev) {
     44    if (!canPointerEventDrag(ev)) {
     45      return;
     46    }
     47 
     48    const xDiff = Math.abs(this.mouseX - ev.clientX);
     49    const yDiff = Math.abs(this.mouseY - ev.clientY);
     50 
     51    // This allows for double-click.
     52    if (this.props.onDoubleClick && xDiff + yDiff <= 1) {
     53      return;
     54    }
     55    this.mouseX = ev.clientX;
     56    this.mouseY = ev.clientY;
     57 
     58    if (this.isDragging) {
     59      return;
     60    }
     61    this.isDragging = true;
     62 
     63    // "pointermove" is fired when the button state is changed too.  Therefore,
     64    // we should listen to "mousemove" to handle the pointer position changes.
     65    this.draggableEl.current.addEventListener("mousemove", this.onMove);
     66    this.draggableEl.current.setPointerCapture(ev.pointerId);
     67    this.draggableEl.current.addEventListener(
     68      "mousedown",
     69      event => event.preventDefault(),
     70      { once: true }
     71    );
     72 
     73    this.props.onStart && this.props.onStart();
     74  }
     75 
     76  onDoubleClick() {
     77    if (this.props.onDoubleClick) {
     78      this.props.onDoubleClick();
     79    }
     80  }
     81 
     82  onMove(ev) {
     83    if (!this.isDragging) {
     84      return;
     85    }
     86 
     87    ev.preventDefault();
     88    // Use viewport coordinates so, moving mouse over iframes
     89    // doesn't mangle (relative) coordinates.
     90    this.props.onMove(ev.clientX, ev.clientY);
     91  }
     92 
     93  stopDragging() {
     94    if (!this.isDragging) {
     95      return;
     96    }
     97    this.isDragging = false;
     98    this.draggableEl.current.removeEventListener("mousemove", this.onMove);
     99    this.draggableEl.current.addEventListener(
    100      "mouseup",
    101      event => event.preventDefault(),
    102      { once: true }
    103    );
    104    this.props.onStop && this.props.onStop();
    105  }
    106 
    107  render() {
    108    return dom.div({
    109      ref: this.draggableEl,
    110      role: "presentation",
    111      style: this.props.style,
    112      title: this.props.title,
    113      className: this.props.className,
    114      onPointerDown: this.startDragging,
    115      onPointerUp: this.stopDragging,
    116      onDoubleClick: this.onDoubleClick,
    117    });
    118  }
    119 }
    120 
    121 module.exports = Draggable;