tor-browser

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

ToolboxController.js (6792B)


      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 "use strict";
      5 
      6 const {
      7  Component,
      8  createFactory,
      9 } = require("resource://devtools/client/shared/vendor/react.mjs");
     10 const ToolboxToolbar = createFactory(
     11  require("resource://devtools/client/framework/components/ToolboxToolbar.js")
     12 );
     13 const ELEMENT_PICKER_ID = "command-button-pick";
     14 
     15 /**
     16 * This component serves as a state controller for the toolbox React component. It's a
     17 * thin layer for translating events and state of the outside world into the React update
     18 * cycle. This solution was used to keep the amount of code changes to a minimimum while
     19 * adapting the existing codebase to start using React.
     20 */
     21 class ToolboxController extends Component {
     22  constructor(props, context) {
     23    super(props, context);
     24 
     25    // See the ToolboxToolbar propTypes for documentation on each of these items in
     26    // state, and for the definitions of the props that are expected to be passed in.
     27    this.state = {
     28      focusedButton: ELEMENT_PICKER_ID,
     29      toolboxButtons: [],
     30      visibleToolboxButtonCount: 0,
     31      currentToolId: null,
     32      highlightedTools: new Set(),
     33      panelDefinitions: [],
     34      hostTypes: [],
     35      currentHostType: undefined,
     36      areDockOptionsEnabled: true,
     37      canCloseToolbox: true,
     38      isSplitConsoleActive: false,
     39      disableAutohide: undefined,
     40      alwaysOnTop: undefined,
     41      pseudoLocale: undefined,
     42      canRender: false,
     43      buttonIds: [],
     44      checkedButtonsUpdated: () => {
     45        this.forceUpdate();
     46      },
     47    };
     48 
     49    this.setFocusedButton = this.setFocusedButton.bind(this);
     50    this.setToolboxButtons = this.setToolboxButtons.bind(this);
     51    this.setCurrentToolId = this.setCurrentToolId.bind(this);
     52    this.highlightTool = this.highlightTool.bind(this);
     53    this.unhighlightTool = this.unhighlightTool.bind(this);
     54    this.setHostTypes = this.setHostTypes.bind(this);
     55    this.setCurrentHostType = this.setCurrentHostType.bind(this);
     56    this.setDockOptionsEnabled = this.setDockOptionsEnabled.bind(this);
     57    this.setCanCloseToolbox = this.setCanCloseToolbox.bind(this);
     58    this.setIsSplitConsoleActive = this.setIsSplitConsoleActive.bind(this);
     59    this.setDisableAutohide = this.setDisableAutohide.bind(this);
     60    this.setCanRender = this.setCanRender.bind(this);
     61    this.setPanelDefinitions = this.setPanelDefinitions.bind(this);
     62    this.updateButtonIds = this.updateButtonIds.bind(this);
     63    this.updateFocusedButton = this.updateFocusedButton.bind(this);
     64    this.setDebugTargetData = this.setDebugTargetData.bind(this);
     65  }
     66 
     67  shouldComponentUpdate() {
     68    return this.state.canRender;
     69  }
     70 
     71  componentWillUnmount() {
     72    this.state.toolboxButtons.forEach(button => {
     73      button.off("updatechecked", this.state.checkedButtonsUpdated);
     74    });
     75  }
     76 
     77  /**
     78   * The button and tab ids must be known in order to be able to focus left and right
     79   * using the arrow keys.
     80   */
     81  updateButtonIds() {
     82    const { toolboxButtons, panelDefinitions, canCloseToolbox } = this.state;
     83 
     84    // This is a little gnarly, but go through all of the state and extract the IDs.
     85    this.setState({
     86      buttonIds: [
     87        ...toolboxButtons
     88          .filter(btn => btn.isInStartContainer)
     89          .map(({ id }) => id),
     90        ...panelDefinitions.map(({ id }) => id),
     91        ...toolboxButtons
     92          .filter(btn => !btn.isInStartContainer)
     93          .map(({ id }) => id),
     94        canCloseToolbox ? "toolbox-close" : null,
     95      ].filter(id => id),
     96    });
     97 
     98    this.updateFocusedButton();
     99  }
    100 
    101  updateFocusedButton() {
    102    this.setFocusedButton(this.state.focusedButton);
    103  }
    104 
    105  setFocusedButton(focusedButton) {
    106    const { buttonIds } = this.state;
    107 
    108    focusedButton =
    109      focusedButton && buttonIds.includes(focusedButton)
    110        ? focusedButton
    111        : buttonIds[0];
    112    if (this.state.focusedButton !== focusedButton) {
    113      this.setState({
    114        focusedButton,
    115      });
    116    }
    117  }
    118 
    119  setCurrentToolId(currentToolId) {
    120    this.setState({ currentToolId }, () => {
    121      // Also set the currently focused button to this tool.
    122      this.setFocusedButton(currentToolId);
    123    });
    124  }
    125 
    126  setCanRender() {
    127    this.setState({ canRender: true }, this.updateButtonIds);
    128  }
    129 
    130  highlightTool(highlightedTool) {
    131    const { highlightedTools } = this.state;
    132    highlightedTools.add(highlightedTool);
    133    this.setState({ highlightedTools });
    134  }
    135 
    136  unhighlightTool(id) {
    137    const { highlightedTools } = this.state;
    138    if (highlightedTools.has(id)) {
    139      highlightedTools.delete(id);
    140      this.setState({ highlightedTools });
    141    }
    142  }
    143 
    144  setDockOptionsEnabled(areDockOptionsEnabled) {
    145    this.setState({ areDockOptionsEnabled });
    146  }
    147 
    148  setHostTypes(hostTypes) {
    149    this.setState({ hostTypes });
    150  }
    151 
    152  setCurrentHostType(currentHostType) {
    153    this.setState({ currentHostType });
    154  }
    155 
    156  setCanCloseToolbox(canCloseToolbox) {
    157    this.setState({ canCloseToolbox }, this.updateButtonIds);
    158  }
    159 
    160  setIsSplitConsoleActive(isSplitConsoleActive) {
    161    this.setState({ isSplitConsoleActive });
    162  }
    163 
    164  /**
    165   * @param {bool | undefined} disableAutohide
    166   */
    167  setDisableAutohide(disableAutohide) {
    168    this.setState({ disableAutohide });
    169  }
    170 
    171  /**
    172   * @param {bool | undefined} alwaysOnTop
    173   */
    174  setAlwaysOnTop(alwaysOnTop) {
    175    this.setState({ alwaysOnTop });
    176  }
    177 
    178  /**
    179   * @param {bool} focusedState
    180   */
    181  setFocusedState(focusedState) {
    182    // We only care about the focused state when the toolbox is always on top
    183    if (this.state.alwaysOnTop) {
    184      this.setState({ focusedState });
    185    }
    186  }
    187 
    188  /**
    189   * @param {"bidi" | "accented" | "none" | undefined} pseudoLocale
    190   */
    191  setPseudoLocale(pseudoLocale) {
    192    this.setState({ pseudoLocale });
    193  }
    194 
    195  setPanelDefinitions(panelDefinitions) {
    196    this.setState({ panelDefinitions }, this.updateButtonIds);
    197  }
    198 
    199  get panelDefinitions() {
    200    return this.state.panelDefinitions;
    201  }
    202 
    203  setToolboxButtons(toolboxButtons) {
    204    // Listen for updates of the checked attribute.
    205    this.state.toolboxButtons.forEach(button => {
    206      button.off("updatechecked", this.state.checkedButtonsUpdated);
    207    });
    208    toolboxButtons.forEach(button => {
    209      button.on("updatechecked", this.state.checkedButtonsUpdated);
    210    });
    211 
    212    const visibleToolboxButtonCount = toolboxButtons.filter(
    213      button => button.isVisible
    214    ).length;
    215 
    216    this.setState(
    217      { toolboxButtons, visibleToolboxButtonCount },
    218      this.updateButtonIds
    219    );
    220  }
    221 
    222  setDebugTargetData(data) {
    223    this.setState({ debugTargetData: data });
    224  }
    225 
    226  render() {
    227    return ToolboxToolbar(Object.assign({}, this.props, this.state));
    228  }
    229 }
    230 
    231 module.exports = ToolboxController;