tor-browser

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

DeviceSelector.js (4680B)


      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 "use strict";
      6 
      7 const {
      8  createFactory,
      9  PureComponent,
     10 } = require("resource://devtools/client/shared/vendor/react.mjs");
     11 const dom = require("resource://devtools/client/shared/vendor/react-dom-factories.js");
     12 const { hr } = dom;
     13 const PropTypes = require("resource://devtools/client/shared/vendor/react-prop-types.mjs");
     14 
     15 const {
     16  getStr,
     17 } = require("resource://devtools/client/responsive/utils/l10n.js");
     18 const {
     19  parseUserAgent,
     20 } = require("resource://devtools/client/responsive/utils/ua.js");
     21 const Types = require("resource://devtools/client/responsive/types.js");
     22 
     23 const MenuButton = createFactory(
     24  require("resource://devtools/client/shared/components/menu/MenuButton.js")
     25 );
     26 
     27 loader.lazyGetter(this, "MenuItem", () => {
     28  const menuItemClass = require("resource://devtools/client/shared/components/menu/MenuItem.js");
     29  const menuItem = createFactory(menuItemClass);
     30  menuItem.DUMMY_ICON = menuItemClass.DUMMY_ICON;
     31  return menuItem;
     32 });
     33 
     34 loader.lazyGetter(this, "MenuList", () => {
     35  return createFactory(
     36    require("resource://devtools/client/shared/components/menu/MenuList.js")
     37  );
     38 });
     39 
     40 class DeviceSelector extends PureComponent {
     41  static get propTypes() {
     42    return {
     43      devices: PropTypes.shape(Types.devices).isRequired,
     44      onChangeDevice: PropTypes.func.isRequired,
     45      onUpdateDeviceModal: PropTypes.func.isRequired,
     46      selectedDevice: PropTypes.string.isRequired,
     47      viewportId: PropTypes.number.isRequired,
     48    };
     49  }
     50 
     51  getMenuProps(device) {
     52    if (!device) {
     53      return { icon: null, label: null, tooltip: null };
     54    }
     55 
     56    const { browser, os } = parseUserAgent(device.userAgent);
     57    let label = device.name;
     58    if (os) {
     59      label += ` ${os.name}`;
     60      if (os.version) {
     61        label += ` ${os.version}`;
     62      }
     63    }
     64 
     65    let icon = null;
     66    let tooltip = label;
     67    if (browser) {
     68      icon = `chrome://devtools/skin/images/browsers/${browser.name.toLowerCase()}.svg`;
     69      tooltip += ` ${browser.name} ${browser.version}`;
     70    }
     71 
     72    return { icon, label, tooltip };
     73  }
     74 
     75  getSelectedDevice() {
     76    const { devices, selectedDevice } = this.props;
     77 
     78    if (!selectedDevice) {
     79      return null;
     80    }
     81 
     82    for (const type of devices.types) {
     83      for (const device of devices[type]) {
     84        if (selectedDevice === device.name) {
     85          return device;
     86        }
     87      }
     88    }
     89 
     90    return null;
     91  }
     92 
     93  renderMenuList() {
     94    const {
     95      devices,
     96      onChangeDevice,
     97      onUpdateDeviceModal,
     98      selectedDevice,
     99      viewportId,
    100    } = this.props;
    101 
    102    const menuItems = [];
    103 
    104    for (const type of devices.types) {
    105      for (const device of devices[type]) {
    106        if (device.displayed) {
    107          const { icon, label, tooltip } = this.getMenuProps(device);
    108 
    109          menuItems.push(
    110            MenuItem({
    111              key: label,
    112              className: "device-selector-item",
    113              checked: selectedDevice === device.name,
    114              label,
    115              icon: icon || MenuItem.DUMMY_ICON,
    116              tooltip,
    117              onClick: () => onChangeDevice(viewportId, device, type),
    118            })
    119          );
    120        }
    121      }
    122    }
    123 
    124    menuItems.sort(function (a, b) {
    125      return a.props.label.localeCompare(b.props.label);
    126    });
    127 
    128    if (menuItems.length) {
    129      menuItems.push(hr({ key: "separator" }));
    130    }
    131 
    132    menuItems.push(
    133      MenuItem({
    134        key: "edit-device",
    135        label: getStr("responsive.editDeviceList2"),
    136        onClick: () => onUpdateDeviceModal(true, viewportId),
    137      })
    138    );
    139 
    140    return MenuList({}, menuItems);
    141  }
    142 
    143  render() {
    144    const { devices } = this.props;
    145    const selectedDevice = this.getSelectedDevice();
    146    let { icon, label, tooltip } = this.getMenuProps(selectedDevice);
    147 
    148    if (!selectedDevice) {
    149      label = getStr("responsive.responsiveMode");
    150    }
    151 
    152    // MenuButton is expected to be used in the toolbox document usually,
    153    // but since RDM's frame also loads theme-switching.js, we can create
    154    // MenuButtons (& HTMLTooltips) in the RDM frame document.
    155    const toolboxDoc = window.document;
    156 
    157    return MenuButton(
    158      {
    159        id: "device-selector",
    160        menuId: "device-selector-menu",
    161        toolboxDoc,
    162        className: "devtools-button devtools-dropdown-button",
    163        label,
    164        icon,
    165        title: tooltip,
    166        disabled: devices.listState !== Types.loadableState.LOADED,
    167      },
    168      () => this.renderMenuList()
    169    );
    170  }
    171 }
    172 
    173 module.exports = DeviceSelector;