1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 WebInspector.OverridesUI = {}
9 * @param {!Element} rotateButton
10 * @param {?function(!WebInspector.EmulatedDevice, !WebInspector.EmulatedDevice.Mode)} callback
12 WebInspector.DeviceSelect = function(rotateButton, callback)
14 this._callback = callback;
15 this._rotateButton = rotateButton;
16 this.element = createElement("p");
18 this._deviceSelectElement = this.element.createChild("select", "device-select");
19 this._deviceSelectElement.addEventListener("change", this._deviceSelected.bind(this), false);
21 var container = this.element.createChild("div", "mode-container");
22 container.appendChild(this._rotateButton);
23 this._rotateButton.addEventListener("click", this._rotateButtonClicked.bind(this), false);
24 this._rotateButton.title = WebInspector.UIString("Change orientation");
26 var modeSelectContainer = container.createChild("span", "mode-select");
27 this._modeSelectElement = modeSelectContainer.createChild("select");
28 this._modeSelectElement.addEventListener("change", this._modeSelected.bind(this), false);
29 this._modeLabelElement = modeSelectContainer.createChild("label");
30 this._modeLabelElement.addEventListener("click", this._rotateButtonClicked.bind(this), false);
31 this._modeLabelElement.title = WebInspector.UIString("Change orientation");
33 this._emulatedSettingChangedMuted = false;
34 this._lastOrientation = null;
36 WebInspector.overridesSupport.settings.emulateResolution.addChangeListener(this._emulatedSettingChanged, this);
37 WebInspector.overridesSupport.settings.deviceWidth.addChangeListener(this._emulatedSettingChanged, this);
38 WebInspector.overridesSupport.settings.deviceHeight.addChangeListener(this._emulatedSettingChanged, this);
39 WebInspector.overridesSupport.settings.deviceScaleFactor.addChangeListener(this._emulatedSettingChanged, this);
40 WebInspector.overridesSupport.settings.emulateMobile.addChangeListener(this._emulatedSettingChanged, this);
41 WebInspector.overridesSupport.settings.emulateTouch.addChangeListener(this._emulatedSettingChanged, this);
42 WebInspector.overridesSupport.settings.userAgent.addChangeListener(this._emulatedSettingChanged, this);
44 WebInspector.emulatedDevicesList.addEventListener(WebInspector.EmulatedDevicesList.Events.CustomDevicesUpdated, this._deviceListChanged, this);
45 WebInspector.emulatedDevicesList.addEventListener(WebInspector.EmulatedDevicesList.Events.StandardDevicesUpdated, this._deviceListChanged, this);
46 this._deviceListChanged();
49 WebInspector.DeviceSelect.prototype = {
50 _deviceListChanged: function()
52 this._deviceSelectElement.removeChildren();
54 var selectDeviceOption = new Option(WebInspector.UIString("<Select model>"), WebInspector.UIString("<Select model>"));
55 selectDeviceOption.device = null;
56 selectDeviceOption.lastSelectedIndex = 0;
57 selectDeviceOption.disabled = true;
58 this._deviceSelectElement.appendChild(selectDeviceOption);
60 this._addDeviceGroup(WebInspector.UIString("Custom"), WebInspector.emulatedDevicesList.custom());
61 this._addDeviceGroup(WebInspector.UIString("Devices"), WebInspector.emulatedDevicesList.standard());
62 this._emulatedSettingChanged();
66 * @param {string} name
67 * @param {!Array.<!WebInspector.EmulatedDevice>} devices
69 _addDeviceGroup: function(name, devices)
71 devices = devices.filter(function (d) { return d.show(); });
74 devices.sort(WebInspector.EmulatedDevice.compareByTitle);
75 var groupElement = this._deviceSelectElement.createChild("optgroup");
76 groupElement.label = name;
77 for (var i = 0; i < devices.length; ++i) {
78 var option = new Option(devices[i].title, devices[i].title);
79 option.device = devices[i];
80 option.lastSelectedIndex = 0;
81 groupElement.appendChild(option);
85 _emulatedSettingChanged: function()
87 if (this._emulatedSettingChangedMuted)
90 for (var i = 1; i < this._deviceSelectElement.options.length; ++i) {
91 var option = this._deviceSelectElement.options[i];
92 var device = /** @type {!WebInspector.EmulatedDevice} */ (option.device);
93 for (var j = 0; j < device.modes.length; j++) {
94 if (WebInspector.overridesSupport.isEmulatingDevice(device.modeToOverridesDevice(device.modes[j]))) {
95 this._select(device, device.modes[j]);
101 this._select(null, null);
105 * @param {?WebInspector.EmulatedDevice} device
106 * @param {?WebInspector.EmulatedDevice.Mode} mode
108 _select: function(device, mode)
110 for (var i = 0; i < this._deviceSelectElement.options.length; i++) {
111 if (this._deviceSelectElement.options[i].device === device)
112 this._deviceSelectElement.selectedIndex = i;
114 this._updateModeSelect();
115 for (var i = 0; i < this._modeSelectElement.options.length; i++) {
116 if (this._modeSelectElement.options[i].mode === mode)
117 this._modeSelectElement.selectedIndex = i;
119 this._updateModeControls();
120 this._saveLastSelectedIndex();
121 if (this._callback) {
122 var option = this._modeSelectElement.options[this._modeSelectElement.selectedIndex];
123 this._callback(option.device, option.mode);
127 _deviceSelected: function()
129 this._updateModeSelect();
130 this._modeSelected();
133 _updateModeSelect: function()
135 this._modeSelectElement.removeChildren();
136 var option = this._deviceSelectElement.options[this._deviceSelectElement.selectedIndex];
137 var device = /** @type {!WebInspector.EmulatedDevice} */ (option.device);
139 if (this._deviceSelectElement.selectedIndex === 0) {
140 this._addMode(device, null, "");
141 } else if (device.modes.length === 1) {
142 this._addMode(device, device.modes[0], WebInspector.UIString("Default"));
144 this._addOrientation(device, WebInspector.EmulatedDevice.Vertical, WebInspector.UIString("Portrait"));
145 this._addOrientation(device, WebInspector.EmulatedDevice.Horizontal, WebInspector.UIString("Landscape"));
147 this._updateRotateModes();
149 var index = option.lastSelectedIndex;
150 var modeOption = this._modeSelectElement.options[index];
151 if (modeOption.rotateIndex != -1) {
152 var rotateOption = this._modeSelectElement.options[modeOption.rotateIndex];
153 if (rotateOption.mode && rotateOption.mode.orientation === this._lastOrientation)
154 index = modeOption.rotateIndex;
156 this._modeSelectElement.selectedIndex = index;
157 this._updateModeControls();
161 * @param {!WebInspector.EmulatedDevice} device
162 * @param {string} orientation
163 * @param {string} title
165 _addOrientation: function(device, orientation, title)
167 var modes = device.modesForOrientation(orientation);
170 if (modes.length === 1) {
171 this._addMode(device, modes[0], title);
173 for (var index = 0; index < modes.length; index++)
174 this._addMode(device, modes[index], title + " \u2013 " + modes[index].title);
179 * @param {!WebInspector.EmulatedDevice} device
180 * @param {?WebInspector.EmulatedDevice.Mode} mode
181 * @param {string} title
183 _addMode: function(device, mode, title)
185 var option = new Option(title, title);
187 option.device = device;
188 this._modeSelectElement.appendChild(option);
191 _updateRotateModes: function()
193 for (var i = 0; i < this._modeSelectElement.options.length; i++) {
194 var modeI = this._modeSelectElement.options[i].mode;
195 this._modeSelectElement.options[i].rotateIndex = -1;
196 for (var j = 0; j < this._modeSelectElement.options.length; j++) {
197 var modeJ = this._modeSelectElement.options[j].mode;
198 if (modeI && modeJ && modeI.orientation !== modeJ.orientation && modeI.title === modeJ.title)
199 this._modeSelectElement.options[i].rotateIndex = j;
204 _updateModeControls: function()
206 this._modeLabelElement.textContent = this._modeSelectElement.options[this._modeSelectElement.selectedIndex].label;
208 if (this._modeSelectElement.options.length <= 1) {
209 this._modeSelectElement.classList.toggle("hidden", true);
210 this._modeLabelElement.classList.toggle("hidden", true);
212 var showLabel = this._modeSelectElement.options.length === 2 && this._modeSelectElement.options[0].rotateIndex === 1;
213 this._modeSelectElement.classList.toggle("hidden", showLabel);
214 this._modeLabelElement.classList.toggle("hidden", !showLabel);
217 this._rotateButton.classList.toggle("hidden", this._modeSelectElement.options[this._modeSelectElement.selectedIndex].rotateIndex === -1);
220 _modeSelected: function()
222 this._saveLastSelectedIndex();
223 this._updateModeControls();
224 var option = this._modeSelectElement.options[this._modeSelectElement.selectedIndex];
226 this._callback(option.device, option.mode);
227 this._emulatedSettingChangedMuted = true;
228 WebInspector.overridesSupport.emulateDevice(option.device.modeToOverridesDevice(option.mode));
229 this._emulatedSettingChangedMuted = false;
232 _saveLastSelectedIndex: function()
234 this._deviceSelectElement.options[this._deviceSelectElement.selectedIndex].lastSelectedIndex = this._modeSelectElement.selectedIndex;
236 var option = this._modeSelectElement.options[this._modeSelectElement.selectedIndex];
237 if (option.mode && option.rotateIndex != -1)
238 this._lastOrientation = option.mode.orientation;
241 _rotateButtonClicked: function()
243 this._modeSelectElement.selectedIndex = this._modeSelectElement.options[this._modeSelectElement.selectedIndex].rotateIndex;
244 this._modeSelected();
250 * @return {{select: !Element, input: !Element}}
252 WebInspector.OverridesUI.createUserAgentSelectAndInput = function()
254 var userAgentSetting = WebInspector.overridesSupport.settings.userAgent;
255 const noOverride = {title: WebInspector.UIString("No override"), value: ""};
256 const customOverride = {title: WebInspector.UIString("Other"), value: "Other"};
257 var userAgents = [noOverride].concat(WebInspector.OverridesUI._userAgents).concat([customOverride]);
259 var userAgentSelectElement = createElement("select");
260 for (var i = 0; i < userAgents.length; ++i)
261 userAgentSelectElement.add(new Option(userAgents[i].title, userAgents[i].value));
262 userAgentSelectElement.selectedIndex = 0;
264 var otherUserAgentElement = createElement("input");
265 otherUserAgentElement.type = "text";
266 otherUserAgentElement.value = userAgentSetting.get();
267 otherUserAgentElement.title = userAgentSetting.get();
270 userAgentSetting.addChangeListener(settingChanged);
271 userAgentSelectElement.addEventListener("change", userAgentSelected, false);
273 otherUserAgentElement.addEventListener("dblclick", textDoubleClicked, true);
274 otherUserAgentElement.addEventListener("blur", textChanged, false);
275 otherUserAgentElement.addEventListener("keydown", textKeyDown, false);
277 function userAgentSelected()
279 var value = userAgentSelectElement.options[userAgentSelectElement.selectedIndex].value;
280 if (value !== customOverride.value) {
281 userAgentSetting.removeChangeListener(settingChanged);
282 userAgentSetting.set(value);
283 userAgentSetting.addChangeListener(settingChanged);
284 otherUserAgentElement.value = value;
285 otherUserAgentElement.title = value;
286 otherUserAgentElement.readOnly = true;
288 otherUserAgentElement.readOnly = false;
289 otherUserAgentElement.focus();
293 function settingChanged()
295 var value = userAgentSetting.get();
296 var options = userAgentSelectElement.options;
297 var selectionRestored = false;
298 for (var i = 0; i < options.length; ++i) {
299 if (options[i].value === value) {
300 userAgentSelectElement.selectedIndex = i;
301 selectionRestored = true;
306 otherUserAgentElement.readOnly = selectionRestored;
307 if (!selectionRestored)
308 userAgentSelectElement.selectedIndex = options.length - 1;
310 if (otherUserAgentElement.value !== value) {
311 otherUserAgentElement.value = value;
312 otherUserAgentElement.title = value;
316 function textKeyDown(event)
318 if (isEnterKey(event))
322 function textDoubleClicked()
324 userAgentSelectElement.selectedIndex = userAgents.length - 1;
328 function textChanged()
330 if (userAgentSetting.get() !== otherUserAgentElement.value)
331 userAgentSetting.set(otherUserAgentElement.value);
334 return { select: userAgentSelectElement, input: otherUserAgentElement };
337 /** @type {!Array.<{title: string, value: string}>} */
338 WebInspector.OverridesUI._userAgents = [
339 {title: "Android 4.0.2 \u2014 Galaxy Nexus", value: "Mozilla/5.0 (Linux; U; Android 4.0.2; en-us; Galaxy Nexus Build/ICL53F) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30"},
340 {title: "Android 2.3 \u2014 Nexus S", value: "Mozilla/5.0 (Linux; U; Android 2.3.6; en-us; Nexus S Build/GRK39F) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1"},
341 {title: "BlackBerry \u2014 BB10", value: "Mozilla/5.0 (BB10; Touch) AppleWebKit/537.1+ (KHTML, like Gecko) Version/10.0.0.1337 Mobile Safari/537.1+"},
342 {title: "BlackBerry \u2014 PlayBook 2.1", value: "Mozilla/5.0 (PlayBook; U; RIM Tablet OS 2.1.0; en-US) AppleWebKit/536.2+ (KHTML, like Gecko) Version/7.2.1.0 Safari/536.2+"},
343 {title: "BlackBerry \u2014 9900", value: "Mozilla/5.0 (BlackBerry; U; BlackBerry 9900; en-US) AppleWebKit/534.11+ (KHTML, like Gecko) Version/7.0.0.187 Mobile Safari/534.11+"},
344 {title: "Chrome 31 \u2014 Mac", value: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36"},
345 {title: "Chrome 31 \u2014 Windows", value: "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.16 Safari/537.36"},
346 {title: "Chrome \u2014 Android Tablet", value: "Mozilla/5.0 (Linux; Android 4.1.2; Nexus 7 Build/JZ054K) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19"},
347 {title: "Chrome \u2014 Android Mobile", value: "Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19"},
348 {title: "Chrome \u2014 iPad", value: "Mozilla/5.0 (iPad; CPU OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) CriOS/30.0.1599.12 Mobile/11A465 Safari/8536.25"},
349 {title: "Chrome \u2014 iPhone", value: "Mozilla/5.0 (iPhone; CPU iPhone OS 7_0_2 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) CriOS/30.0.1599.12 Mobile/11A501 Safari/8536.25"},
350 {title: "Firefox 14 \u2014 Android Mobile", value: "Mozilla/5.0 (Android; Mobile; rv:14.0) Gecko/14.0 Firefox/14.0"},
351 {title: "Firefox 14 \u2014 Android Tablet", value: "Mozilla/5.0 (Android; Tablet; rv:14.0) Gecko/14.0 Firefox/14.0"},
352 {title: "Firefox 4 \u2014 Mac", value: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko/20100101 Firefox/4.0.1"},
353 {title: "Firefox 4 \u2014 Windows", value: "Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1"},
354 {title: "Firefox 7 \u2014 Mac", value: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1"},
355 {title: "Firefox 7 \u2014 Windows", value: "Mozilla/5.0 (Windows NT 6.1; Intel Mac OS X 10.6; rv:7.0.1) Gecko/20100101 Firefox/7.0.1"},
356 {title: "Googlebot", value: "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"},
357 {title: "Googlebot Smartphone", value: "Mozilla/5.0 (iPhone; CPU iPhone OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A5376e Safari/8536.25 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"},
358 {title: "Internet Explorer 10", value: "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0)"},
359 {title: "Internet Explorer 7", value: "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)"},
360 {title: "Internet Explorer 8", value: "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0)"},
361 {title: "Internet Explorer 9", value: "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)"},
362 {title: "iPad \u2014 iOS 8", value: "Mozilla/5.0 (iPad; CPU OS 8_0 like Mac OS X) AppleWebKit/600.1.3 (KHTML, like Gecko) Version/8.0 Mobile/12A4345d Safari/600.1.4"},
363 {title: "iPad \u2014 iOS 7", value: "Mozilla/5.0 (iPad; CPU OS 7_0_2 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A501 Safari/9537.53"},
364 {title: "iPad \u2014 iOS 6", value: "Mozilla/5.0 (iPad; CPU OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A5376e Safari/8536.25"},
365 {title: "iPhone \u2014 iOS 8", value: "Mozilla/5.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/600.1.3 (KHTML, like Gecko) Version/8.0 Mobile/12A4345d Safari/600.1.4"},
366 {title: "iPhone \u2014 iOS 7", value: "Mozilla/5.0 (iPhone; CPU iPhone OS 7_0_2 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A4449d Safari/9537.53"},
367 {title: "iPhone \u2014 iOS 6", value: "Mozilla/5.0 (iPhone; CPU iPhone OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A5376e Safari/8536.25"},
368 {title: "MeeGo \u2014 Nokia N9", value: "Mozilla/5.0 (MeeGo; NokiaN9) AppleWebKit/534.13 (KHTML, like Gecko) NokiaBrowser/8.5.0 Mobile Safari/534.13"},
369 {title: "Opera 18 \u2014 Mac", value: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36 OPR/18.0.1284.68"},
370 {title: "Opera 18 \u2014 Windows", value: "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36 OPR/18.0.1284.68"},
371 {title: "Opera 12 \u2014 Mac", value: "Opera/9.80 (Macintosh; Intel Mac OS X 10.9.1) Presto/2.12.388 Version/12.16"},
372 {title: "Opera 12 \u2014 Windows", value: "Opera/9.80 (Windows NT 6.1) Presto/2.12.388 Version/12.16"},
373 {title: "Silk \u2014 Kindle Fire (Desktop view)", value: "Mozilla/5.0 (Linux; U; en-us; KFTHWI Build/JDQ39) AppleWebKit/535.19 (KHTML, like Gecko) Silk/3.13 Safari/535.19 Silk-Accelerated=true"},
374 {title: "Silk \u2014 Kindle Fire (Mobile view)", value: "Mozilla/5.0 (Linux; U; Android 4.2.2; en-us; KFTHWI Build/JDQ39) AppleWebKit/535.19 (KHTML, like Gecko) Silk/3.13 Mobile Safari/535.19 Silk-Accelerated=true"}