DeviceForm.js (6602B)
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 createRef, 10 PureComponent, 11 } = require("resource://devtools/client/shared/vendor/react.mjs"); 12 const dom = require("resource://devtools/client/shared/vendor/react-dom-factories.js"); 13 const PropTypes = require("resource://devtools/client/shared/vendor/react-prop-types.mjs"); 14 15 const ViewportDimension = createFactory( 16 require("resource://devtools/client/responsive/components/ViewportDimension.js") 17 ); 18 19 const { 20 getStr, 21 } = require("resource://devtools/client/responsive/utils/l10n.js"); 22 const Types = require("resource://devtools/client/responsive/types.js"); 23 24 class DeviceForm extends PureComponent { 25 static get propTypes() { 26 return { 27 formType: PropTypes.string.isRequired, 28 device: PropTypes.shape(Types.device).isRequired, 29 devices: PropTypes.shape(Types.devices).isRequired, 30 onSave: PropTypes.func.isRequired, 31 viewportTemplate: PropTypes.shape(Types.viewport).isRequired, 32 onDeviceFormHide: PropTypes.func.isRequired, 33 }; 34 } 35 36 constructor(props) { 37 super(props); 38 39 const { height, width } = this.props.viewportTemplate; 40 41 this.state = { 42 height, 43 width, 44 }; 45 46 this.nameInputRef = createRef(); 47 this.pixelRatioInputRef = createRef(); 48 this.touchInputRef = createRef(); 49 this.userAgentInputRef = createRef(); 50 51 this.onChangeSize = this.onChangeSize.bind(this); 52 this.onDeviceFormHide = this.onDeviceFormHide.bind(this); 53 this.onDeviceFormSave = this.onDeviceFormSave.bind(this); 54 this.onInputFocus = this.onInputFocus.bind(this); 55 this.validateNameField = this.validateNameField.bind(this); 56 } 57 58 onChangeSize(_, width, height) { 59 this.setState({ 60 width, 61 height, 62 }); 63 } 64 65 onDeviceFormSave(e) { 66 e.preventDefault(); 67 68 if (!this.pixelRatioInputRef.current.checkValidity()) { 69 return; 70 } 71 72 if ( 73 !this.validateNameField( 74 this.nameInputRef.current.value, 75 this.props.device 76 ) 77 ) { 78 this.nameInputRef.current.setCustomValidity( 79 getStr("responsive.deviceNameAlreadyInUse") 80 ); 81 return; 82 } 83 84 this.props.onSave({ 85 name: this.nameInputRef.current.value.trim(), 86 width: this.state.width, 87 height: this.state.height, 88 pixelRatio: parseFloat(this.pixelRatioInputRef.current.value), 89 userAgent: this.userAgentInputRef.current.value, 90 touch: this.touchInputRef.current.checked, 91 }); 92 93 this.onDeviceFormHide(); 94 } 95 96 onDeviceFormHide() { 97 // Ensure that we have onDeviceFormHide before calling it. 98 if (this.props.onDeviceFormHide) { 99 this.props.onDeviceFormHide(); 100 } 101 } 102 103 onInputFocus(e) { 104 // If the formType is "add", select all text in input field when focused. 105 if (this.props.formType === "add") { 106 e.target.select(); 107 } 108 } 109 110 /** 111 * Validates the name field's value. 112 * 113 * @param {string} value 114 * The input field value for the device name. 115 * @return {boolean} true if device name is valid, false otherwise. 116 */ 117 validateNameField(value) { 118 const nameFieldValue = value.trim(); 119 let isValidDeviceName = false; 120 121 // If the formType is "add", then we just need to check if a custom device with that 122 // same name exists. 123 if (this.props.formType === "add") { 124 isValidDeviceName = !this.props.devices.custom.find( 125 device => device.name == nameFieldValue 126 ); 127 } else { 128 // Otherwise, the formType is "edit". We'd have to find another device that 129 // already has the same name, but not itself, so: 130 // Find the index of the device being edited. Use this index value to distinguish 131 // between the device being edited from other devices in the list. 132 const deviceIndex = this.props.devices.custom.findIndex(({ name }) => { 133 return name === this.props.device.name; 134 }); 135 136 isValidDeviceName = !this.props.devices.custom.find((d, index) => { 137 return d.name === nameFieldValue && index !== deviceIndex; 138 }); 139 } 140 141 return isValidDeviceName; 142 } 143 144 render() { 145 const { device, formType } = this.props; 146 const { width, height } = this.state; 147 148 return dom.form( 149 { id: "device-form" }, 150 dom.label( 151 { id: "device-form-name" }, 152 dom.span( 153 { className: "device-form-label" }, 154 getStr("responsive.deviceAdderName") 155 ), 156 dom.input({ 157 defaultValue: device.name, 158 ref: this.nameInputRef, 159 onFocus: this.onInputFocus, 160 }) 161 ), 162 dom.label( 163 { id: "device-form-size" }, 164 dom.span( 165 { className: "device-form-label" }, 166 getStr("responsive.deviceAdderSize") 167 ), 168 ViewportDimension({ 169 viewport: { width, height }, 170 doResizeViewport: this.onChangeSize, 171 }) 172 ), 173 dom.label( 174 { id: "device-form-pixel-ratio" }, 175 dom.span( 176 { className: "device-form-label" }, 177 getStr("responsive.deviceAdderPixelRatio2") 178 ), 179 dom.input({ 180 type: "number", 181 step: "any", 182 defaultValue: device.pixelRatio, 183 ref: this.pixelRatioInputRef, 184 onFocus: this.onInputFocus, 185 }) 186 ), 187 dom.label( 188 { id: "device-form-user-agent" }, 189 dom.span( 190 { className: "device-form-label" }, 191 getStr("responsive.deviceAdderUserAgent2") 192 ), 193 dom.input({ 194 defaultValue: device.userAgent, 195 ref: this.userAgentInputRef, 196 onFocus: this.onInputFocus, 197 }) 198 ), 199 dom.label( 200 { id: "device-form-touch" }, 201 dom.input({ 202 defaultChecked: device.touch, 203 type: "checkbox", 204 ref: this.touchInputRef, 205 }), 206 dom.span( 207 { className: "device-form-label" }, 208 getStr("responsive.deviceAdderTouch2") 209 ) 210 ), 211 dom.div( 212 { className: "device-form-buttons" }, 213 dom.button( 214 { id: "device-form-save", onClick: this.onDeviceFormSave }, 215 formType === "add" 216 ? getStr("responsive.deviceAdderSave") 217 : getStr("responsive.deviceFormUpdate") 218 ), 219 dom.button( 220 { id: "device-form-cancel", onClick: this.onDeviceFormHide }, 221 getStr("responsive.deviceAdderCancel") 222 ) 223 ) 224 ); 225 } 226 } 227 228 module.exports = DeviceForm;