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;