Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / devtools / front_end / main / OverridesView.js
1 /*
2  * Copyright (C) 2014 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 /**
32  * @constructor
33  * @extends {WebInspector.VBox}
34  */
35 WebInspector.OverridesView = function()
36 {
37     WebInspector.VBox.call(this);
38     this.registerRequiredCSS("main/overrides.css");
39     this.element.classList.add("overrides-view");
40
41     this._tabbedPane = new WebInspector.TabbedPane();
42     this._tabbedPane.shrinkableTabs = false;
43     this._tabbedPane.verticalTabLayout = true;
44
45     new WebInspector.OverridesView.DeviceTab().appendAsTab(this._tabbedPane);
46     new WebInspector.OverridesView.MediaTab().appendAsTab(this._tabbedPane);
47     new WebInspector.OverridesView.NetworkTab().appendAsTab(this._tabbedPane);
48     new WebInspector.OverridesView.SensorsTab().appendAsTab(this._tabbedPane);
49
50     this._lastSelectedTabSetting = WebInspector.settings.createSetting("lastSelectedEmulateTab", "device");
51     this._tabbedPane.selectTab(this._lastSelectedTabSetting.get());
52     this._tabbedPane.addEventListener(WebInspector.TabbedPane.EventTypes.TabSelected, this._tabSelected, this);
53     this._tabbedPane.show(this.element);
54
55     var resetButtonElement = this._tabbedPane.headerElement().createChild("button", "text-button");
56     resetButtonElement.id = "overrides-reset-button";
57     resetButtonElement.textContent = WebInspector.UIString("Reset");
58     resetButtonElement.addEventListener("click", WebInspector.overridesSupport.reset.bind(WebInspector.overridesSupport), false);
59
60     if (!WebInspector.overridesSupport.responsiveDesignAvailable()) {
61         var disableButtonElement = this._tabbedPane.headerElement().createChild("button", "text-button overrides-disable-button");
62         disableButtonElement.id = "overrides-disable-button";
63         disableButtonElement.textContent = WebInspector.UIString("Disable");
64         disableButtonElement.addEventListener("click", this._toggleEmulationEnabled.bind(this), false);
65     }
66
67     this._splashScreenElement = this.element.createChild("div", "overrides-splash-screen");
68     this._unavailableSplashScreenElement = this.element.createChild("div", "overrides-splash-screen");
69     this._unavailableSplashScreenElement.createTextChild(WebInspector.UIString("Emulation is not available."));
70
71     if (WebInspector.overridesSupport.responsiveDesignAvailable()) {
72         this._splashScreenElement.createTextChild(WebInspector.UIString("Emulation is currently disabled. Toggle "));
73         var toggleEmulationButton = new WebInspector.StatusBarButton("", "emulation-status-bar-item");
74         toggleEmulationButton.addEventListener("click", this._toggleEmulationEnabled, this);
75         this._splashScreenElement.appendChild(toggleEmulationButton.element);
76         this._splashScreenElement.createTextChild(WebInspector.UIString("in the main toolbar to enable it."));
77     } else {
78         var toggleEmulationButton = this._splashScreenElement.createChild("button", "text-button overrides-enable-button");
79         toggleEmulationButton.textContent = WebInspector.UIString("Enable emulation");
80         toggleEmulationButton.addEventListener("click", this._toggleEmulationEnabled.bind(this), false);
81     }
82
83     this._warningFooter = this.element.createChild("div", "overrides-footer");
84     this._overridesWarningUpdated();
85
86     WebInspector.overridesSupport.addEventListener(WebInspector.OverridesSupport.Events.OverridesWarningUpdated, this._overridesWarningUpdated, this);
87     WebInspector.overridesSupport.addEventListener(WebInspector.OverridesSupport.Events.EmulationStateChanged, this._emulationStateChanged, this);
88     this._emulationStateChanged();
89 }
90
91 WebInspector.OverridesView.prototype = {
92     /**
93      * @param {!WebInspector.Event} event
94      */
95     _tabSelected: function(event)
96     {
97         this._lastSelectedTabSetting.set(this._tabbedPane.selectedTabId);
98     },
99
100     _overridesWarningUpdated: function()
101     {
102         var message = WebInspector.overridesSupport.warningMessage();
103         this._warningFooter.classList.toggle("hidden", !message);
104         this._warningFooter.textContent = message;
105     },
106
107     _toggleEmulationEnabled: function()
108     {
109         WebInspector.overridesSupport.setEmulationEnabled(!WebInspector.overridesSupport.emulationEnabled());
110     },
111
112     _emulationStateChanged: function()
113     {
114         this._unavailableSplashScreenElement.classList.toggle("hidden", WebInspector.overridesSupport.canEmulate());
115         this._tabbedPane.element.classList.toggle("hidden", !WebInspector.overridesSupport.emulationEnabled());
116         this._splashScreenElement.classList.toggle("hidden", WebInspector.overridesSupport.emulationEnabled() || !WebInspector.overridesSupport.canEmulate());
117     },
118
119     __proto__: WebInspector.VBox.prototype
120 }
121
122 /**
123  * @constructor
124  * @extends {WebInspector.VBox}
125  * @param {string} id
126  * @param {string} name
127  * @param {!Array.<!WebInspector.Setting>} settings
128  * @param {!Array.<function():boolean>=} predicates
129  */
130 WebInspector.OverridesView.Tab = function(id, name, settings, predicates)
131 {
132     WebInspector.VBox.call(this);
133     this._id = id;
134     this._name = name;
135     this._settings = settings;
136     this._predicates = predicates || [];
137     for (var i = 0; i < settings.length; ++i)
138         settings[i].addChangeListener(this.updateActiveState, this);
139 }
140
141 WebInspector.OverridesView.Tab.prototype = {
142     /**
143      * @param {!WebInspector.TabbedPane} tabbedPane
144      */
145     appendAsTab: function(tabbedPane)
146     {
147         this._tabbedPane = tabbedPane;
148         tabbedPane.appendTab(this._id, this._name, this);
149         this.updateActiveState();
150     },
151
152     updateActiveState: function()
153     {
154         if (!this._tabbedPane)
155             return;
156         var active = false;
157         for (var i = 0; !active && i < this._settings.length; ++i)
158             active = this._settings[i].get();
159         for (var i = 0; !active && i < this._predicates.length; ++i)
160             active = this._predicates[i]();
161         this._tabbedPane.toggleTabClass(this._id, "overrides-activate", active);
162     },
163
164     /**
165      * @param {string} name
166      * @param {!WebInspector.Setting} setting
167      * @param {function(boolean)=} callback
168      */
169     _createSettingCheckbox: function(name, setting, callback)
170     {
171         var checkbox = WebInspector.SettingsUI.createSettingCheckbox(name, setting, true);
172
173         function changeListener(value)
174         {
175             callback(setting.get());
176         }
177
178         if (callback)
179             setting.addChangeListener(changeListener);
180
181         return checkbox;
182     },
183
184     __proto__: WebInspector.VBox.prototype
185 }
186
187 /**
188  * @constructor
189  * @extends {WebInspector.OverridesView.Tab}
190  */
191 WebInspector.OverridesView.DeviceTab = function()
192 {
193     WebInspector.OverridesView.Tab.call(this, "device", WebInspector.UIString("Device"),  [
194         WebInspector.overridesSupport.settings.emulateResolution,
195         WebInspector.overridesSupport.settings.deviceScaleFactor,
196         WebInspector.overridesSupport.settings.emulateMobile
197     ]);
198     this.element.classList.add("overrides-device");
199
200     this.element.appendChild(this._createDeviceElement());
201
202     var footnote = this.element.createChild("p", "help-footnote");
203     footnote.appendChild(WebInspector.createDocumentationAnchor("device-mode", WebInspector.UIString("More information about screen emulation")));
204 }
205
206 WebInspector.OverridesView.DeviceTab.prototype = {
207     _createDeviceElement: function()
208     {
209         var fieldsetElement = createElement("fieldset");
210         fieldsetElement.id = "metrics-override-section";
211
212         var deviceModelElement = fieldsetElement.createChild("p", "overrides-device-model-section");
213         deviceModelElement.createChild("span").textContent = WebInspector.UIString("Model:");
214
215         var deviceSelectElement = WebInspector.OverridesUI.createDeviceSelect(this._showTitleDialog.bind(this));
216         var buttons = deviceSelectElement.querySelectorAll("button");
217         for (var i = 0; i < buttons.length; ++i)
218             buttons[i].classList.add("text-button");
219         deviceModelElement.appendChild(deviceSelectElement);
220
221         var emulateResolutionCheckbox = WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Emulate screen resolution"), WebInspector.overridesSupport.settings.emulateResolution, true);
222         fieldsetElement.appendChild(emulateResolutionCheckbox);
223         var resolutionFieldset = WebInspector.SettingsUI.createSettingFieldset(WebInspector.overridesSupport.settings.emulateResolution);
224         fieldsetElement.appendChild(resolutionFieldset);
225
226         var tableElement = resolutionFieldset.createChild("table", "nowrap");
227         var rowElement = tableElement.createChild("tr");
228         var cellElement = rowElement.createChild("td");
229         cellElement.createTextChild(WebInspector.UIString("Resolution:"));
230         cellElement = rowElement.createChild("td");
231
232         var widthOverrideInput = WebInspector.SettingsUI.createSettingInputField("", WebInspector.overridesSupport.settings.deviceWidth, true, 4, "80px", WebInspector.OverridesSupport.deviceSizeValidator, true, true, WebInspector.UIString("\u2013"));
233         cellElement.appendChild(widthOverrideInput);
234         this._swapDimensionsElement = cellElement.createChild("button", "overrides-swap");
235         this._swapDimensionsElement.createTextChild(" \u21C4 "); // RIGHTWARDS ARROW OVER LEFTWARDS ARROW.
236         this._swapDimensionsElement.title = WebInspector.UIString("Swap dimensions");
237         this._swapDimensionsElement.addEventListener("click", WebInspector.overridesSupport.swapDimensions.bind(WebInspector.overridesSupport), false);
238         this._swapDimensionsElement.tabIndex = -1;
239         var heightOverrideInput = WebInspector.SettingsUI.createSettingInputField("", WebInspector.overridesSupport.settings.deviceHeight, true, 4, "80px", WebInspector.OverridesSupport.deviceSizeValidator, true, true, WebInspector.UIString("\u2013"));
240         cellElement.appendChild(heightOverrideInput);
241
242         rowElement = tableElement.createChild("tr");
243         cellElement = rowElement.createChild("td");
244         cellElement.colSpan = 4;
245
246         rowElement = tableElement.createChild("tr");
247         rowElement.title = WebInspector.UIString("Ratio between a device's physical pixels and device-independent pixels.");
248         rowElement.createChild("td").createTextChild(WebInspector.UIString("Device pixel ratio:"));
249         rowElement.createChild("td").appendChild(WebInspector.SettingsUI.createSettingInputField("", WebInspector.overridesSupport.settings.deviceScaleFactor, true, 4, "80px", WebInspector.OverridesSupport.deviceScaleFactorValidator, true, true, WebInspector.UIString("\u2013")));
250
251         var mobileCheckbox = this._createSettingCheckbox(WebInspector.UIString("Emulate mobile"), WebInspector.overridesSupport.settings.emulateMobile);
252         mobileCheckbox.title = WebInspector.UIString("Enable meta viewport, overlay scrollbars, text autosizing and default 980px body width");
253         fieldsetElement.appendChild(mobileCheckbox);
254
255         fieldsetElement.appendChild(this._createSettingCheckbox(WebInspector.UIString("Shrink to fit"), WebInspector.overridesSupport.settings.deviceFitWindow));
256
257         return fieldsetElement;
258     },
259
260     /**
261      * @param {!function(string)} callback
262      */
263     _showTitleDialog: function(callback)
264     {
265         WebInspector.Dialog.show(this.element, new WebInspector.OverridesView.DeviceTab.CustomDeviceTitleDialog(callback));
266     },
267
268     __proto__: WebInspector.OverridesView.Tab.prototype
269 }
270
271 /**
272  * @constructor
273  * @extends {WebInspector.DialogDelegate}
274  * @param {!function(string)} callback
275  */
276 WebInspector.OverridesView.DeviceTab.CustomDeviceTitleDialog = function(callback)
277 {
278     WebInspector.DialogDelegate.call(this);
279
280     this.element = createElementWithClass("div", "custom-device-title-dialog");
281     this.element.createChild("label").textContent = WebInspector.UIString("Save as: ");
282
283     this._input = this.element.createChild("input");
284     this._input.setAttribute("type", "text");
285     this._input.placeholder = WebInspector.UIString("device model name");
286     this._input.addEventListener("input", this._onInput.bind(this), false);
287
288     this._saveButton = this.element.createChild("button");
289     this._saveButton.textContent = WebInspector.UIString("Save");
290     this._saveButton.addEventListener("click", this._onSaveClick.bind(this), false);
291
292     this._callback = callback;
293     this._result = "";
294     this._onInput();
295 }
296
297 WebInspector.OverridesView.DeviceTab.CustomDeviceTitleDialog.prototype = {
298     focus: function()
299     {
300         WebInspector.setCurrentFocusElement(this._input);
301         this._input.select();
302     },
303
304     _onSaveClick: function()
305     {
306         this._result = this._input.value.trim();
307         WebInspector.Dialog.hide();
308     },
309
310     _onInput: function()
311     {
312         this._saveButton.disabled = !this._input.value.trim();
313     },
314
315     /**
316      * @param {!Event} event
317      */
318     onEnter: function(event)
319     {
320         if (this._input.value.trim()) {
321             this._result = this._input.value.trim();
322         } else {
323             event.consume();
324         }
325     },
326
327     willHide: function()
328     {
329         this._callback(this._result);
330     },
331
332     __proto__: WebInspector.DialogDelegate.prototype
333 }
334
335 /**
336  * @constructor
337  * @extends {WebInspector.OverridesView.Tab}
338  */
339 WebInspector.OverridesView.MediaTab = function()
340 {
341     var settings = [WebInspector.overridesSupport.settings.overrideCSSMedia];
342     WebInspector.OverridesView.Tab.call(this, "media", WebInspector.UIString("Media"), settings);
343     this.element.classList.add("overrides-media");
344
345     this._createMediaEmulationFragment();
346 }
347
348 WebInspector.OverridesView.MediaTab.prototype = {
349     _createMediaEmulationFragment: function()
350     {
351         var checkbox = WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("CSS media"), WebInspector.overridesSupport.settings.overrideCSSMedia, true);
352         var fieldsetElement = WebInspector.SettingsUI.createSettingFieldset(WebInspector.overridesSupport.settings.overrideCSSMedia);
353         var mediaSelectElement = fieldsetElement.createChild("select");
354         var mediaTypes = WebInspector.CSSStyleModel.MediaTypes;
355         var defaultMedia = WebInspector.overridesSupport.settings.emulatedCSSMedia.get();
356         for (var i = 0; i < mediaTypes.length; ++i) {
357             var mediaType = mediaTypes[i];
358             if (mediaType === "all") {
359                 // "all" is not a device-specific media type.
360                 continue;
361             }
362             var option = createElement("option");
363             option.text = mediaType;
364             option.value = mediaType;
365             mediaSelectElement.add(option);
366             if (mediaType === defaultMedia)
367                 mediaSelectElement.selectedIndex = mediaSelectElement.options.length - 1;
368         }
369
370         mediaSelectElement.addEventListener("change", this._emulateMediaChanged.bind(this, mediaSelectElement), false);
371         var fragment = createDocumentFragment();
372         fragment.appendChild(checkbox);
373         fragment.appendChild(fieldsetElement);
374         this.element.appendChild(fragment);
375     },
376
377     _emulateMediaChanged: function(select)
378     {
379         var media = select.options[select.selectedIndex].value;
380         WebInspector.overridesSupport.settings.emulatedCSSMedia.set(media);
381     },
382
383     __proto__: WebInspector.OverridesView.Tab.prototype
384 }
385
386
387 /**
388  * @constructor
389  * @extends {WebInspector.OverridesView.Tab}
390  */
391 WebInspector.OverridesView.NetworkTab = function()
392 {
393     WebInspector.OverridesView.Tab.call(this, "network", WebInspector.UIString("Network"), [], [this._userAgentOverrideEnabled.bind(this), this._networkThroughputIsLimited.bind(this)]);
394     this.element.classList.add("overrides-network");
395     this._createNetworkConditionsElement();
396     this._createUserAgentSection();
397 }
398
399 WebInspector.OverridesView.NetworkTab.prototype = {
400     /**
401      * @return {boolean}
402      */
403     _networkThroughputIsLimited: function()
404     {
405         return WebInspector.overridesSupport.networkThroughputIsLimited();
406     },
407
408     _createNetworkConditionsElement: function()
409     {
410         var fieldsetElement = this.element.createChild("fieldset");
411         fieldsetElement.createChild("span").textContent = WebInspector.UIString("Limit network throughput:");
412         fieldsetElement.createChild("br");
413         fieldsetElement.appendChild(WebInspector.OverridesUI.createNetworkConditionsSelect());
414
415         WebInspector.overridesSupport.settings.networkConditions.addChangeListener(this.updateActiveState, this);
416     },
417
418     /**
419      * @return {boolean}
420      */
421     _userAgentOverrideEnabled: function()
422     {
423         return !!WebInspector.overridesSupport.settings.userAgent.get();
424     },
425
426     _createUserAgentSection: function()
427     {
428         var fieldsetElement = this.element.createChild("fieldset");
429         fieldsetElement.createChild("label").textContent = WebInspector.UIString("Spoof user agent:");
430         var selectAndInput = WebInspector.OverridesUI.createUserAgentSelectAndInput();
431         fieldsetElement.appendChild(selectAndInput.select);
432         fieldsetElement.appendChild(selectAndInput.input);
433
434         WebInspector.overridesSupport.settings.userAgent.addChangeListener(this.updateActiveState, this);
435     },
436
437     __proto__: WebInspector.OverridesView.Tab.prototype
438 }
439
440
441 /**
442  * @constructor
443  * @extends {WebInspector.OverridesView.Tab}
444  */
445 WebInspector.OverridesView.SensorsTab = function()
446 {
447     WebInspector.OverridesView.Tab.call(this, "sensors", WebInspector.UIString("Sensors"), [
448         WebInspector.overridesSupport.settings.overrideGeolocation,
449         WebInspector.overridesSupport.settings.overrideDeviceOrientation,
450         WebInspector.overridesSupport.settings.emulateTouch
451     ]);
452
453     this.element.classList.add("overrides-sensors");
454     this.registerRequiredCSS("main/accelerometer.css");
455     this.element.appendChild(this._createSettingCheckbox(WebInspector.UIString("Emulate touch screen"), WebInspector.overridesSupport.settings.emulateTouch, undefined));
456     this._appendGeolocationOverrideControl();
457     this._apendDeviceOrientationOverrideControl();
458 }
459
460 WebInspector.OverridesView.SensorsTab.prototype = {
461     _appendGeolocationOverrideControl: function()
462     {
463         const geolocationSetting = WebInspector.overridesSupport.settings.geolocationOverride.get();
464         var geolocation = WebInspector.OverridesSupport.GeolocationPosition.parseSetting(geolocationSetting);
465         this.element.appendChild(this._createSettingCheckbox(WebInspector.UIString("Emulate geolocation coordinates"), WebInspector.overridesSupport.settings.overrideGeolocation, this._geolocationOverrideCheckboxClicked.bind(this)));
466         this.element.appendChild(this._createGeolocationOverrideElement(geolocation));
467         this._geolocationOverrideCheckboxClicked(WebInspector.overridesSupport.settings.overrideGeolocation.get());
468     },
469
470     /**
471      * @param {boolean} enabled
472      */
473     _geolocationOverrideCheckboxClicked: function(enabled)
474     {
475         if (enabled && !this._latitudeElement.value)
476             this._latitudeElement.focus();
477     },
478
479     _applyGeolocationUserInput: function()
480     {
481         this._setGeolocationPosition(WebInspector.OverridesSupport.GeolocationPosition.parseUserInput(this._latitudeElement.value.trim(), this._longitudeElement.value.trim(), this._geolocationErrorElement.checked), true);
482     },
483
484     /**
485      * @param {?WebInspector.OverridesSupport.GeolocationPosition} geolocation
486      * @param {boolean} userInputModified
487      */
488     _setGeolocationPosition: function(geolocation, userInputModified)
489     {
490         if (!geolocation)
491             return;
492
493         if (!userInputModified) {
494             this._latitudeElement.value = geolocation.latitude;
495             this._longitudeElement.value = geolocation.longitude;
496         }
497
498         var value = geolocation.toSetting();
499         WebInspector.overridesSupport.settings.geolocationOverride.set(value);
500     },
501
502     /**
503      * @param {!WebInspector.OverridesSupport.GeolocationPosition} geolocation
504      * @return {!Element}
505      */
506     _createGeolocationOverrideElement: function(geolocation)
507     {
508         var fieldsetElement = WebInspector.SettingsUI.createSettingFieldset(WebInspector.overridesSupport.settings.overrideGeolocation);
509         fieldsetElement.id = "geolocation-override-section";
510
511         var tableElement = fieldsetElement.createChild("table");
512         var rowElement = tableElement.createChild("tr");
513         var cellElement = rowElement.createChild("td");
514         cellElement = rowElement.createChild("td");
515         cellElement.createTextChild(WebInspector.UIString("Lat = "));
516         this._latitudeElement = WebInspector.SettingsUI.createInput(cellElement, "geolocation-override-latitude", String(geolocation.latitude), this._applyGeolocationUserInput.bind(this), true);
517         cellElement.createTextChild(" , ");
518         cellElement.createTextChild(WebInspector.UIString("Lon = "));
519         this._longitudeElement = WebInspector.SettingsUI.createInput(cellElement, "geolocation-override-longitude", String(geolocation.longitude), this._applyGeolocationUserInput.bind(this), true);
520         rowElement = tableElement.createChild("tr");
521         cellElement = rowElement.createChild("td");
522         cellElement.colSpan = 2;
523         var geolocationErrorLabelElement = createElement("label");
524         var geolocationErrorCheckboxElement = geolocationErrorLabelElement.createChild("input");
525         geolocationErrorCheckboxElement.id = "geolocation-error";
526         geolocationErrorCheckboxElement.type = "checkbox";
527         geolocationErrorCheckboxElement.checked = !geolocation || geolocation.error;
528         geolocationErrorCheckboxElement.addEventListener("click", this._applyGeolocationUserInput.bind(this), false);
529         geolocationErrorLabelElement.createTextChild(WebInspector.UIString("Emulate position unavailable"));
530         this._geolocationErrorElement = geolocationErrorCheckboxElement;
531         cellElement.appendChild(geolocationErrorLabelElement);
532
533         return fieldsetElement;
534     },
535
536     _apendDeviceOrientationOverrideControl: function()
537     {
538         const deviceOrientationSetting = WebInspector.overridesSupport.settings.deviceOrientationOverride.get();
539         var deviceOrientation = WebInspector.OverridesSupport.DeviceOrientation.parseSetting(deviceOrientationSetting);
540         this.element.appendChild(this._createSettingCheckbox(WebInspector.UIString("Accelerometer"), WebInspector.overridesSupport.settings.overrideDeviceOrientation, this._deviceOrientationOverrideCheckboxClicked.bind(this)));
541         this.element.appendChild(this._createDeviceOrientationOverrideElement(deviceOrientation));
542         this._deviceOrientationOverrideCheckboxClicked(WebInspector.overridesSupport.settings.overrideDeviceOrientation.get());
543     },
544
545     /**
546      * @param {boolean} enabled
547      */
548     _deviceOrientationOverrideCheckboxClicked: function(enabled)
549     {
550         if (enabled && !this._alphaElement.value)
551             this._alphaElement.focus();
552     },
553
554     _applyDeviceOrientationUserInput: function()
555     {
556         this._setDeviceOrientation(WebInspector.OverridesSupport.DeviceOrientation.parseUserInput(this._alphaElement.value.trim(), this._betaElement.value.trim(), this._gammaElement.value.trim()), WebInspector.OverridesView.SensorsTab.DeviceOrientationModificationSource.UserInput);
557     },
558
559     _resetDeviceOrientation: function()
560     {
561         this._setDeviceOrientation(new WebInspector.OverridesSupport.DeviceOrientation(0, 0, 0), WebInspector.OverridesView.SensorsTab.DeviceOrientationModificationSource.ResetButton);
562     },
563
564     /**
565      * @param {?WebInspector.OverridesSupport.DeviceOrientation} deviceOrientation
566      * @param {!WebInspector.OverridesView.SensorsTab.DeviceOrientationModificationSource} modificationSource
567      */
568     _setDeviceOrientation: function(deviceOrientation, modificationSource)
569     {
570         if (!deviceOrientation)
571             return;
572
573         if (modificationSource != WebInspector.OverridesView.SensorsTab.DeviceOrientationModificationSource.UserInput) {
574             this._alphaElement.value = deviceOrientation.alpha;
575             this._betaElement.value = deviceOrientation.beta;
576             this._gammaElement.value = deviceOrientation.gamma;
577         }
578
579         if (modificationSource != WebInspector.OverridesView.SensorsTab.DeviceOrientationModificationSource.UserDrag)
580             this._setBoxOrientation(deviceOrientation);
581
582         var value = deviceOrientation.toSetting();
583         WebInspector.overridesSupport.settings.deviceOrientationOverride.set(value);
584     },
585
586     /**
587      * @param {!Element} parentElement
588      * @param {string} id
589      * @param {string} label
590      * @param {string} defaultText
591      * @return {!Element}
592      */
593     _createAxisInput: function(parentElement, id, label, defaultText)
594     {
595         var div = parentElement.createChild("div", "accelerometer-axis-input-container");
596         div.createTextChild(label);
597         return WebInspector.SettingsUI.createInput(div, id, defaultText, this._applyDeviceOrientationUserInput.bind(this), true);
598     },
599
600     /**
601      * @param {!WebInspector.OverridesSupport.DeviceOrientation} deviceOrientation
602      */
603     _createDeviceOrientationOverrideElement: function(deviceOrientation)
604     {
605         var fieldsetElement = WebInspector.SettingsUI.createSettingFieldset(WebInspector.overridesSupport.settings.overrideDeviceOrientation);
606         fieldsetElement.id = "device-orientation-override-section";
607         var tableElement = fieldsetElement.createChild("table");
608         var rowElement = tableElement.createChild("tr");
609         var cellElement = rowElement.createChild("td", "accelerometer-inputs-cell");
610
611         this._alphaElement = this._createAxisInput(cellElement, "device-orientation-override-alpha", "\u03B1: ", String(deviceOrientation.alpha));
612         this._betaElement = this._createAxisInput(cellElement, "device-orientation-override-beta", "\u03B2: ", String(deviceOrientation.beta));
613         this._gammaElement = this._createAxisInput(cellElement, "device-orientation-override-gamma", "\u03B3: ", String(deviceOrientation.gamma));
614
615         var resetButton = cellElement.createChild("button", "text-button accelerometer-reset-button");
616         resetButton.textContent = WebInspector.UIString("Reset");
617         resetButton.addEventListener("click", this._resetDeviceOrientation.bind(this), false);
618
619         this._stageElement = rowElement.createChild("td","accelerometer-stage");
620         this._boxElement = this._stageElement.createChild("section", "accelerometer-box");
621
622         this._boxElement.createChild("section", "front");
623         this._boxElement.createChild("section", "top");
624         this._boxElement.createChild("section", "back");
625         this._boxElement.createChild("section", "left");
626         this._boxElement.createChild("section", "right");
627         this._boxElement.createChild("section", "bottom");
628
629         WebInspector.installDragHandle(this._stageElement, this._onBoxDragStart.bind(this), this._onBoxDrag.bind(this), this._onBoxDragEnd.bind(this), "move");
630         this._setBoxOrientation(deviceOrientation);
631         return fieldsetElement;
632     },
633
634     /**
635      * @param {!WebInspector.OverridesSupport.DeviceOrientation} deviceOrientation
636      */
637     _setBoxOrientation: function(deviceOrientation)
638     {
639         var matrix = new WebKitCSSMatrix();
640         this._boxMatrix = matrix.rotate(-deviceOrientation.beta, deviceOrientation.gamma, -deviceOrientation.alpha);
641         this._boxElement.style.webkitTransform = this._boxMatrix.toString();
642     },
643
644     /**
645      * @param {!MouseEvent} event
646      * @return {boolean}
647      */
648     _onBoxDrag: function(event)
649     {
650         var mouseMoveVector = this._calculateRadiusVector(event.x, event.y);
651         if (!mouseMoveVector)
652             return true;
653
654         event.consume(true);
655         var axis = WebInspector.Geometry.crossProduct(this._mouseDownVector, mouseMoveVector);
656         axis.normalize();
657         var angle = WebInspector.Geometry.calculateAngle(this._mouseDownVector, mouseMoveVector);
658         var matrix = new WebKitCSSMatrix();
659         var rotationMatrix = matrix.rotateAxisAngle(axis.x, axis.y, axis.z, angle);
660         this._currentMatrix = rotationMatrix.multiply(this._boxMatrix)
661         this._boxElement.style.webkitTransform = this._currentMatrix;
662         var eulerAngles = WebInspector.Geometry.EulerAngles.fromRotationMatrix(this._currentMatrix);
663         var newOrientation = new WebInspector.OverridesSupport.DeviceOrientation(-eulerAngles.alpha, -eulerAngles.beta, eulerAngles.gamma);
664         this._setDeviceOrientation(newOrientation, WebInspector.OverridesView.SensorsTab.DeviceOrientationModificationSource.UserDrag);
665         return false;
666     },
667
668     /**
669      * @param {!MouseEvent} event
670      * @return {boolean}
671      */
672     _onBoxDragStart: function(event)
673     {
674         if (!WebInspector.overridesSupport.settings.overrideDeviceOrientation.get())
675             return false;
676
677         this._mouseDownVector = this._calculateRadiusVector(event.x, event.y);
678
679         if (!this._mouseDownVector)
680             return false;
681
682         event.consume(true);
683         return true;
684     },
685
686     _onBoxDragEnd: function()
687     {
688         this._boxMatrix = this._currentMatrix;
689     },
690
691     /**
692      * @param {number} x
693      * @param {number} y
694      * @return {?WebInspector.Geometry.Vector}
695      */
696     _calculateRadiusVector: function(x, y)
697     {
698         var rect = this._stageElement.getBoundingClientRect();
699         var radius = Math.max(rect.width, rect.height) / 2;
700         var sphereX = (x - rect.left - rect.width / 2) / radius;
701         var sphereY = (y - rect.top - rect.height / 2) / radius;
702         var sqrSum = sphereX * sphereX + sphereY * sphereY;
703         if (sqrSum > 0.5)
704             return new WebInspector.Geometry.Vector(sphereX, sphereY, 0.5 / Math.sqrt(sqrSum));
705
706         return new WebInspector.Geometry.Vector(sphereX, sphereY, Math.sqrt(1 - sqrSum));
707     },
708
709     __proto__ : WebInspector.OverridesView.Tab.prototype
710 }
711
712 /** @enum {string} */
713 WebInspector.OverridesView.SensorsTab.DeviceOrientationModificationSource = {
714     UserInput: "userInput",
715     UserDrag: "userDrag",
716     ResetButton: "resetButton"
717 }
718
719 /**
720  * @constructor
721  * @implements {WebInspector.Revealer}
722  */
723 WebInspector.OverridesView.Revealer = function()
724 {
725 }
726
727 WebInspector.OverridesView.Revealer.prototype = {
728     /**
729      * @param {!Object} overridesSupport
730      * @return {!Promise}
731      */
732     reveal: function(overridesSupport)
733     {
734         WebInspector.inspectorView.showViewInDrawer("emulation");
735         return Promise.resolve();
736     }
737 }