OLD | NEW |
1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * @constructor | 6 * @constructor |
7 * @extends {WebInspector.VBox} | 7 * @extends {WebInspector.VBox} |
| 8 * @implements {WebInspector.ListWidget.Delegate} |
8 */ | 9 */ |
9 WebInspector.DevicesSettingsTab = function() | 10 WebInspector.DevicesSettingsTab = function() |
10 { | 11 { |
11 WebInspector.VBox.call(this); | 12 WebInspector.VBox.call(this); |
12 this.element.classList.add("settings-tab-container"); | 13 this.element.classList.add("settings-tab-container"); |
13 this.element.classList.add("devices-settings-tab"); | 14 this.element.classList.add("devices-settings-tab"); |
14 this.registerRequiredCSS("emulation/devicesSettingsTab.css"); | 15 this.registerRequiredCSS("emulation/devicesSettingsTab.css"); |
15 | 16 |
16 var header = this.element.createChild("header"); | 17 var header = this.element.createChild("header"); |
17 header.createChild("h3").createTextChild(WebInspector.UIString("Emulated Dev
ices")); | 18 header.createChild("h3").createTextChild(WebInspector.UIString("Emulated Dev
ices")); |
18 this.containerElement = this.element.createChild("div", "help-container-wrap
per").createChild("div", "settings-tab help-content help-container"); | 19 this.containerElement = this.element.createChild("div", "help-container-wrap
per").createChild("div", "settings-tab help-content help-container"); |
19 | 20 |
20 var buttonsRow = this.containerElement.createChild("div", "devices-button-ro
w"); | 21 var buttonsRow = this.containerElement.createChild("div", "devices-button-ro
w"); |
21 this._addCustomButton = createTextButton(WebInspector.UIString("Add custom d
evice..."), this._addCustomDevice.bind(this)); | 22 var addCustomButton = createTextButton(WebInspector.UIString("Add custom dev
ice..."), this._addCustomDevice.bind(this)); |
22 buttonsRow.appendChild(this._addCustomButton); | 23 buttonsRow.appendChild(addCustomButton); |
23 | 24 |
24 this._devicesList = this.containerElement.createChild("div", "devices-list")
; | 25 this._list = new WebInspector.ListWidget(this); |
25 this._customListSearator = createElementWithClass("div", "devices-custom-sep
arator"); | 26 this._list.registerRequiredCSS("emulation/devicesSettingsTab.css"); |
26 | 27 this._list.element.classList.add("devices-list"); |
27 this._editDevice = null; | 28 this._list.show(this.containerElement); |
28 this._editDeviceListItem = null; | |
29 this._createEditDeviceElement(); | |
30 | 29 |
31 this._muteUpdate = false; | 30 this._muteUpdate = false; |
32 WebInspector.emulatedDevicesList.addEventListener(WebInspector.EmulatedDevic
esList.Events.CustomDevicesUpdated, this._devicesUpdated, this); | 31 WebInspector.emulatedDevicesList.addEventListener(WebInspector.EmulatedDevic
esList.Events.CustomDevicesUpdated, this._devicesUpdated, this); |
33 WebInspector.emulatedDevicesList.addEventListener(WebInspector.EmulatedDevic
esList.Events.StandardDevicesUpdated, this._devicesUpdated, this); | 32 WebInspector.emulatedDevicesList.addEventListener(WebInspector.EmulatedDevic
esList.Events.StandardDevicesUpdated, this._devicesUpdated, this); |
| 33 |
| 34 this.setDefaultFocusedElement(addCustomButton); |
34 } | 35 } |
35 | 36 |
36 WebInspector.DevicesSettingsTab.prototype = { | 37 WebInspector.DevicesSettingsTab.prototype = { |
37 wasShown: function() | 38 wasShown: function() |
38 { | 39 { |
39 WebInspector.VBox.prototype.wasShown.call(this); | 40 WebInspector.VBox.prototype.wasShown.call(this); |
40 this._devicesUpdated(); | 41 this._devicesUpdated(); |
41 this._stopEditing(); | |
42 }, | 42 }, |
43 | 43 |
44 _devicesUpdated: function() | 44 _devicesUpdated: function() |
45 { | 45 { |
46 if (this._muteUpdate) | 46 if (this._muteUpdate) |
47 return; | 47 return; |
48 | 48 |
49 this._devicesList.removeChildren(); | 49 this._list.clear(); |
50 | 50 |
51 var devices = WebInspector.emulatedDevicesList.custom().slice(); | 51 var devices = WebInspector.emulatedDevicesList.custom().slice(); |
52 devices.sort(WebInspector.EmulatedDevice.compareByTitle); | |
53 for (var i = 0; i < devices.length; ++i) | 52 for (var i = 0; i < devices.length; ++i) |
54 this._devicesList.appendChild(this._createDeviceListItem(devices[i],
true)); | 53 this._list.appendItem(devices[i], true); |
55 | 54 |
56 this._devicesList.appendChild(this._customListSearator); | 55 this._list.appendSeparator(); |
57 this._updateSeparatorVisibility(); | |
58 | 56 |
59 devices = WebInspector.emulatedDevicesList.standard().slice(); | 57 devices = WebInspector.emulatedDevicesList.standard().slice(); |
60 devices.sort(WebInspector.EmulatedDevice.compareByTitle); | 58 devices.sort(WebInspector.EmulatedDevice.compareByTitle); |
61 for (var i = 0; i < devices.length; ++i) | 59 for (var i = 0; i < devices.length; ++i) |
62 this._devicesList.appendChild(this._createDeviceListItem(devices[i],
false)); | 60 this._list.appendItem(devices[i], false); |
63 }, | |
64 | |
65 _updateSeparatorVisibility: function() | |
66 { | |
67 this._customListSearator.classList.toggle("hidden", this._devicesList.fi
rstChild === this._customListSearator); | |
68 }, | 61 }, |
69 | 62 |
70 /** | 63 /** |
71 * @param {boolean} custom | 64 * @param {boolean} custom |
72 */ | 65 */ |
73 _muteAndSaveDeviceList: function(custom) | 66 _muteAndSaveDeviceList: function(custom) |
74 { | 67 { |
75 this._muteUpdate = true; | 68 this._muteUpdate = true; |
76 if (custom) | 69 if (custom) |
77 WebInspector.emulatedDevicesList.saveCustomDevices(); | 70 WebInspector.emulatedDevicesList.saveCustomDevices(); |
78 else | 71 else |
79 WebInspector.emulatedDevicesList.saveStandardDevices(); | 72 WebInspector.emulatedDevicesList.saveStandardDevices(); |
80 this._muteUpdate = false; | 73 this._muteUpdate = false; |
81 }, | 74 }, |
82 | 75 |
| 76 _addCustomDevice: function() |
| 77 { |
| 78 var device = new WebInspector.EmulatedDevice(); |
| 79 device.deviceScaleFactor = 0; |
| 80 this._list.addNewItem(WebInspector.emulatedDevicesList.custom().length,
device); |
| 81 }, |
| 82 |
83 /** | 83 /** |
84 * @param {!WebInspector.EmulatedDevice} device | 84 * @param {number} value |
85 * @param {boolean} custom | 85 * @return {string} |
| 86 */ |
| 87 _toNumericInputValue: function(value) |
| 88 { |
| 89 return value ? String(value) : ""; |
| 90 }, |
| 91 |
| 92 /** |
| 93 * @override |
| 94 * @param {*} item |
| 95 * @param {boolean} editable |
86 * @return {!Element} | 96 * @return {!Element} |
87 */ | 97 */ |
88 _createDeviceListItem: function(device, custom) | 98 renderItem: function(item, editable) |
89 { | 99 { |
90 var item = createElementWithClass("div", "devices-list-item"); | 100 var device = /** @type {!WebInspector.EmulatedDevice} */ (item); |
91 var checkbox = item.createChild("input", "devices-list-checkbox"); | 101 var element = createElementWithClass("div", "devices-list-item"); |
| 102 var checkbox = element.createChild("input", "devices-list-checkbox"); |
92 checkbox.type = "checkbox"; | 103 checkbox.type = "checkbox"; |
93 checkbox.checked = device.show(); | 104 checkbox.checked = device.show(); |
94 item.createChild("div", "devices-list-title").textContent = device.title
; | 105 element.createChild("div", "devices-list-title").textContent = device.ti
tle; |
95 item.addEventListener("click", onItemClicked.bind(this), false); | 106 element.addEventListener("click", onItemClicked.bind(this), false); |
96 item.classList.toggle("device-list-item-show", device.show()); | 107 element.classList.toggle("device-list-item-show", device.show()); |
97 if (custom) { | 108 return element; |
98 var editButton = item.createChild("div", "devices-list-edit"); | |
99 editButton.title = WebInspector.UIString("Edit"); | |
100 editButton.addEventListener("click", onEditClicked.bind(this), false
); | |
101 | |
102 var removeButton = item.createChild("div", "devices-list-remove"); | |
103 removeButton.title = WebInspector.UIString("Remove"); | |
104 removeButton.addEventListener("click", onRemoveClicked, false); | |
105 } | |
106 | 109 |
107 /** | 110 /** |
108 * @param {!Event} event | 111 * @param {!Event} event |
109 * @this {WebInspector.DevicesSettingsTab} | 112 * @this {WebInspector.DevicesSettingsTab} |
110 */ | 113 */ |
111 function onItemClicked(event) | 114 function onItemClicked(event) |
112 { | 115 { |
113 var show = !checkbox.checked; | 116 var show = !checkbox.checked; |
114 device.setShow(show); | 117 device.setShow(show); |
115 this._muteAndSaveDeviceList(custom); | 118 this._muteAndSaveDeviceList(editable); |
116 checkbox.checked = show; | 119 checkbox.checked = show; |
117 item.classList.toggle("device-list-item-show", show); | 120 element.classList.toggle("device-list-item-show", show); |
118 event.consume(); | 121 event.consume(); |
119 } | 122 } |
120 | |
121 /** | |
122 * @param {!Event} event | |
123 * @this {WebInspector.DevicesSettingsTab} | |
124 */ | |
125 function onEditClicked(event) | |
126 { | |
127 event.consume(); | |
128 this._startEditing(device, item); | |
129 } | |
130 | |
131 /** | |
132 * @param {!Event} event | |
133 */ | |
134 function onRemoveClicked(event) | |
135 { | |
136 WebInspector.emulatedDevicesList.removeCustomDevice(device); | |
137 event.consume(); | |
138 } | |
139 | |
140 return item; | |
141 }, | |
142 | |
143 _addCustomDevice: function() | |
144 { | |
145 this._startEditing(new WebInspector.EmulatedDevice(), null); | |
146 }, | |
147 | |
148 _createEditDeviceElement: function() | |
149 { | |
150 this._editDeviceElement = createElementWithClass("div", "devices-edit-co
ntainer"); | |
151 this._editDeviceElement.addEventListener("keydown", onKeyDown.bind(null,
isEscKey, this._stopEditing.bind(this)), false); | |
152 this._editDeviceElement.addEventListener("keydown", onKeyDown.bind(null,
isEnterKey, this._editDeviceCommitClicked.bind(this)), false); | |
153 this._editDeviceCheckbox = this._editDeviceElement.createChild("input",
"devices-edit-checkbox"); | |
154 this._editDeviceCheckbox.type = "checkbox"; | |
155 var fields = this._editDeviceElement.createChild("div", "devices-edit-fi
elds"); | |
156 | |
157 this._editDeviceTitle = this._createInput(WebInspector.UIString("Device
name")); | |
158 fields.appendChild(this._editDeviceTitle); | |
159 | |
160 var screen = fields.createChild("div", "hbox"); | |
161 this._editDeviceWidth = this._createInput(WebInspector.UIString("Width")
, "80px"); | |
162 screen.appendChild(this._editDeviceWidth); | |
163 this._editDeviceHeight = this._createInput(WebInspector.UIString("Height
"), "80px"); | |
164 screen.appendChild(this._editDeviceHeight); | |
165 this._editDeviceScale = this._createInput(WebInspector.UIString("Device
pixel ratio")); | |
166 screen.appendChild(this._editDeviceScale); | |
167 | |
168 this._editDeviceUserAgent = this._createInput(WebInspector.UIString("Use
r agent string")); | |
169 fields.appendChild(this._editDeviceUserAgent); | |
170 | |
171 var buttonsRow = fields.createChild("div", "devices-edit-buttons"); | |
172 this._editDeviceCommitButton = createTextButton("", this._editDeviceComm
itClicked.bind(this)); | |
173 buttonsRow.appendChild(this._editDeviceCommitButton); | |
174 this._editDeviceCancelButton = createTextButton(WebInspector.UIString("C
ancel"), this._stopEditing.bind(this)); | |
175 this._editDeviceCancelButton.addEventListener("keydown", onKeyDown.bind(
null, isEnterKey, this._stopEditing.bind(this)), false); | |
176 buttonsRow.appendChild(this._editDeviceCancelButton); | |
177 | |
178 /** | |
179 * @param {function(!Event):boolean} predicate | |
180 * @param {function()} callback | |
181 * @param {!Event} event | |
182 */ | |
183 function onKeyDown(predicate, callback, event) | |
184 { | |
185 if (predicate(event)) { | |
186 event.consume(true); | |
187 callback(); | |
188 } | |
189 } | |
190 }, | 123 }, |
191 | 124 |
192 /** | 125 /** |
193 * @param {string} title | 126 * @override |
194 * @param {string=} width | 127 * @param {*} item |
195 * @return {!Element} | 128 * @param {number} index |
196 */ | 129 */ |
197 _createInput: function(title, width) | 130 removeItemRequested: function(item, index) |
198 { | 131 { |
199 var input = createElement("input"); | 132 WebInspector.emulatedDevicesList.removeCustomDevice(/** @type {!WebInspe
ctor.EmulatedDevice} */ (item)); |
200 input.type = "text"; | |
201 if (width) | |
202 input.style.width = width; | |
203 input.placeholder = title; | |
204 input.addEventListener("input", this._validateInputs.bind(this, false),
false); | |
205 input.addEventListener("blur", this._validateInputs.bind(this, false), f
alse); | |
206 return input; | |
207 }, | 133 }, |
208 | 134 |
209 /** | 135 /** |
210 * @param {boolean} forceValid | 136 * @override |
| 137 * @param {*} item |
| 138 * @param {!WebInspector.ListWidget.Editor} editor |
| 139 * @param {boolean} isNew |
211 */ | 140 */ |
212 _validateInputs: function(forceValid) | 141 commitEdit: function(item, editor, isNew) |
213 { | 142 { |
214 var trimmedTitle = this._editDeviceTitle.value.trim(); | 143 var device = /** @type {!WebInspector.EmulatedDevice} */ (item); |
215 var titleValid = trimmedTitle.length > 0 && trimmedTitle.length < 50; | 144 device.title = editor.control("title").value.trim(); |
216 this._editDeviceTitle.classList.toggle("error-input", !titleValid && !fo
rceValid); | 145 device.vertical.width = editor.control("width").value ? parseInt(editor.
control("width").value, 10) : 0; |
| 146 device.vertical.height = editor.control("height").value ? parseInt(edito
r.control("height").value, 10) : 0; |
| 147 device.horizontal.width = device.vertical.height; |
| 148 device.horizontal.height = device.vertical.width; |
| 149 device.deviceScaleFactor = editor.control("scale").value ? parseFloat(ed
itor.control("scale").value) : 0; |
| 150 device.userAgent = editor.control("user-agent").value; |
| 151 device.modes = []; |
| 152 device.modes.push({title: "", orientation: WebInspector.EmulatedDevice.H
orizontal, insets: new Insets(0, 0, 0, 0), images: null}); |
| 153 device.modes.push({title: "", orientation: WebInspector.EmulatedDevice.V
ertical, insets: new Insets(0, 0, 0, 0), images: null}); |
217 | 154 |
218 var widthValid = !WebInspector.OverridesSupport.deviceSizeValidator(this
._editDeviceWidth.value); | 155 if (isNew) |
219 this._editDeviceWidth.classList.toggle("error-input", !widthValid && !fo
rceValid); | 156 WebInspector.emulatedDevicesList.addCustomDevice(device); |
220 | 157 else |
221 var heightValid = !WebInspector.OverridesSupport.deviceSizeValidator(thi
s._editDeviceHeight.value); | 158 WebInspector.emulatedDevicesList.saveCustomDevices(); |
222 this._editDeviceHeight.classList.toggle("error-input", !heightValid && !
forceValid); | |
223 | |
224 var scaleValid = !WebInspector.OverridesSupport.deviceScaleFactorValidat
or(this._editDeviceScale.value); | |
225 this._editDeviceScale.classList.toggle("error-input", !scaleValid && !fo
rceValid); | |
226 | |
227 var allValid = titleValid && widthValid && heightValid && scaleValid; | |
228 this._editDeviceCommitButton.disabled = !allValid; | |
229 }, | 159 }, |
230 | 160 |
231 /** | 161 /** |
232 * @param {number} value | 162 * @override |
233 * @return {string} | 163 * @param {*} item |
| 164 * @return {!WebInspector.ListWidget.Editor} |
234 */ | 165 */ |
235 _toNumericInputValue: function(value) | 166 beginEdit: function(item) |
236 { | 167 { |
237 return value ? String(value) : ""; | 168 var device = /** @type {!WebInspector.EmulatedDevice} */ (item); |
| 169 var editor = this._createEditor(); |
| 170 editor.control("title").value = device.title; |
| 171 editor.control("width").value = this._toNumericInputValue(device.vertica
l.width); |
| 172 editor.control("height").value = this._toNumericInputValue(device.vertic
al.height); |
| 173 editor.control("scale").value = this._toNumericInputValue(device.deviceS
caleFactor); |
| 174 editor.control("user-agent").value = device.userAgent; |
| 175 return editor; |
238 }, | 176 }, |
239 | 177 |
240 /** | 178 /** |
241 * @param {!WebInspector.EmulatedDevice} device | 179 * @return {!WebInspector.ListWidget.Editor} |
242 * @param {?Element} listItem | |
243 */ | 180 */ |
244 _startEditing: function(device, listItem) | 181 _createEditor: function() |
245 { | 182 { |
246 this._stopEditing(); | 183 if (this._editor) |
| 184 return this._editor; |
247 | 185 |
248 this._addCustomButton.disabled = true; | 186 var editor = new WebInspector.ListWidget.Editor(); |
249 this._devicesList.classList.add("devices-list-editing"); | 187 this._editor = editor; |
250 this._editDevice = device; | 188 var content = editor.contentElement(); |
251 this._editDeviceListItem = listItem; | |
252 if (listItem) | |
253 listItem.classList.add("hidden"); | |
254 | 189 |
255 this._editDeviceCommitButton.textContent = listItem ? WebInspector.UIStr
ing("Save") : WebInspector.UIString("Add device"); | 190 var fields = content.createChild("div", "devices-edit-fields"); |
256 this._editDeviceCheckbox.checked = device.show(); | 191 fields.appendChild(editor.createInput("title", "text", WebInspector.UISt
ring("Device name"), titleValidator)); |
257 this._editDeviceTitle.value = device.title; | 192 var screen = fields.createChild("div", "hbox"); |
258 this._editDeviceWidth.value = listItem ? this._toNumericInputValue(devic
e.vertical.width) : ""; | 193 var width = editor.createInput("width", "text", WebInspector.UIString("W
idth"), sizeValidator); |
259 this._editDeviceHeight.value = listItem ? this._toNumericInputValue(devi
ce.vertical.height) : ""; | 194 width.classList.add("device-edit-small"); |
260 this._editDeviceScale.value = listItem ? this._toNumericInputValue(devic
e.deviceScaleFactor) : ""; | 195 screen.appendChild(width); |
261 this._editDeviceUserAgent.value = device.userAgent; | 196 var height = editor.createInput("height", "text", WebInspector.UIString(
"height"), sizeValidator); |
262 this._validateInputs(true); | 197 height.classList.add("device-edit-small"); |
| 198 screen.appendChild(height); |
| 199 screen.appendChild(editor.createInput("scale", "text", WebInspector.UISt
ring("Device pixel ratio"), scaleValidator)); |
| 200 fields.appendChild(editor.createInput("user-agent", "text", WebInspector
.UIString("User agent string"), userAgentValidator)); |
263 | 201 |
264 if (listItem && listItem.nextElementSibling) | 202 return editor; |
265 this._devicesList.insertBefore(this._editDeviceElement, listItem.nex
tElementSibling); | |
266 else | |
267 this._devicesList.insertBefore(this._editDeviceElement, this._custom
ListSearator); | |
268 this._editDeviceCommitButton.scrollIntoView(); | |
269 this._editDeviceTitle.focus(); | |
270 }, | |
271 | 203 |
272 _editDeviceCommitClicked: function() | 204 /** |
273 { | 205 * @param {!HTMLInputElement|!HTMLSelectElement} input |
274 if (this._editDeviceCommitButton.disabled) | 206 * @return {boolean} |
275 return; | 207 */ |
| 208 function titleValidator(input) |
| 209 { |
| 210 var value = input.value.trim(); |
| 211 return value.length > 0 && value.length < 50; |
| 212 } |
276 | 213 |
277 this._editDevice.setShow(this._editDeviceCheckbox.checked); | 214 /** |
278 this._editDevice.title = this._editDeviceTitle.value; | 215 * @param {!HTMLInputElement|!HTMLSelectElement} input |
279 this._editDevice.vertical.width = this._editDeviceWidth.value ? parseInt
(this._editDeviceWidth.value, 10) : 0; | 216 * @return {boolean} |
280 this._editDevice.vertical.height = this._editDeviceHeight.value ? parseI
nt(this._editDeviceHeight.value, 10) : 0; | 217 */ |
281 this._editDevice.horizontal.width = this._editDevice.vertical.height; | 218 function sizeValidator(input) |
282 this._editDevice.horizontal.height = this._editDevice.vertical.width; | 219 { |
283 this._editDevice.deviceScaleFactor = this._editDeviceScale.value ? parse
Float(this._editDeviceScale.value) : 0; | 220 return !WebInspector.OverridesSupport.deviceSizeValidator(input.valu
e); |
284 this._editDevice.userAgent = this._editDeviceUserAgent.value; | 221 } |
285 this._editDevice.modes.push({title: "", orientation: WebInspector.Emulat
edDevice.Horizontal, insets: new Insets(0, 0, 0, 0), images: null}); | |
286 this._editDevice.modes.push({title: "", orientation: WebInspector.Emulat
edDevice.Vertical, insets: new Insets(0, 0, 0, 0), images: null}); | |
287 | 222 |
288 this._stopEditing(); | 223 /** |
289 if (this._editDeviceListItem) | 224 * @param {!HTMLInputElement|!HTMLSelectElement} input |
290 WebInspector.emulatedDevicesList.saveCustomDevices(); | 225 * @return {boolean} |
291 else | 226 */ |
292 WebInspector.emulatedDevicesList.addCustomDevice(this._editDevice); | 227 function scaleValidator(input) |
293 this._editDevice = null; | 228 { |
294 this._editDeviceListItem = null; | 229 return !WebInspector.OverridesSupport.deviceScaleFactorValidator(inp
ut.value); |
295 }, | 230 } |
296 | 231 |
297 _stopEditing: function() | 232 /** |
298 { | 233 * @param {!HTMLInputElement|!HTMLSelectElement} input |
299 this._devicesList.classList.remove("devices-list-editing"); | 234 * @return {boolean} |
300 if (this._editDeviceListItem) | 235 */ |
301 this._editDeviceListItem.classList.remove("hidden"); | 236 function userAgentValidator(input) |
302 if (this._editDeviceElement.parentElement) | 237 { |
303 this._devicesList.removeChild(this._editDeviceElement); | 238 return true; |
304 this._addCustomButton.disabled = false; | 239 } |
305 this._addCustomButton.focus(); | |
306 }, | 240 }, |
307 | 241 |
308 __proto__: WebInspector.VBox.prototype | 242 __proto__: WebInspector.VBox.prototype |
309 } | 243 } |
OLD | NEW |