Upstream version 10.39.225.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("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     var footnoteLink = footnote.createChild("a");
204     footnoteLink.href = "https://developers.google.com/chrome-developer-tools/docs/mobile-emulation";
205     footnoteLink.target = "_blank";
206     footnoteLink.createTextChild(WebInspector.UIString("More information about screen emulation"));
207 }
208
209 WebInspector.OverridesView.DeviceTab.prototype = {
210     _createDeviceElement: function()
211     {
212         var fieldsetElement = document.createElement("fieldset");
213         fieldsetElement.id = "metrics-override-section";
214
215         var deviceModelElement = fieldsetElement.createChild("p", "overrides-device-model-section");
216         deviceModelElement.createChild("span").textContent = WebInspector.UIString("Model:");
217
218         var deviceSelectElement = WebInspector.OverridesUI.createDeviceSelect(document, this._showTitleDialog.bind(this));
219         var buttons = deviceSelectElement.querySelectorAll("button");
220         for (var i = 0; i < buttons.length; ++i)
221             buttons[i].classList.add("text-button");
222         deviceModelElement.appendChild(deviceSelectElement);
223
224         var emulateResolutionCheckbox = WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("Emulate screen resolution"), WebInspector.overridesSupport.settings.emulateResolution, true);
225         fieldsetElement.appendChild(emulateResolutionCheckbox);
226         var resolutionFieldset = WebInspector.SettingsUI.createSettingFieldset(WebInspector.overridesSupport.settings.emulateResolution);
227         fieldsetElement.appendChild(resolutionFieldset);
228
229         var tableElement = resolutionFieldset.createChild("table", "nowrap");
230         var rowElement = tableElement.createChild("tr");
231         var cellElement = rowElement.createChild("td");
232         cellElement.createTextChild(WebInspector.UIString("Resolution:"));
233         cellElement = rowElement.createChild("td");
234
235         var widthOverrideInput = WebInspector.SettingsUI.createSettingInputField("", WebInspector.overridesSupport.settings.deviceWidth, true, 4, "80px", WebInspector.OverridesSupport.deviceSizeValidator, true, true, WebInspector.UIString("\u2013"));
236         cellElement.appendChild(widthOverrideInput);
237         this._swapDimensionsElement = cellElement.createChild("button", "overrides-swap");
238         this._swapDimensionsElement.createTextChild(" \u21C4 "); // RIGHTWARDS ARROW OVER LEFTWARDS ARROW.
239         this._swapDimensionsElement.title = WebInspector.UIString("Swap dimensions");
240         this._swapDimensionsElement.addEventListener("click", WebInspector.overridesSupport.swapDimensions.bind(WebInspector.overridesSupport), false);
241         this._swapDimensionsElement.tabIndex = -1;
242         var heightOverrideInput = WebInspector.SettingsUI.createSettingInputField("", WebInspector.overridesSupport.settings.deviceHeight, true, 4, "80px", WebInspector.OverridesSupport.deviceSizeValidator, true, true, WebInspector.UIString("\u2013"));
243         cellElement.appendChild(heightOverrideInput);
244
245         rowElement = tableElement.createChild("tr");
246         cellElement = rowElement.createChild("td");
247         cellElement.colSpan = 4;
248
249         rowElement = tableElement.createChild("tr");
250         rowElement.title = WebInspector.UIString("Ratio between a device's physical pixels and device-independent pixels.");
251         rowElement.createChild("td").createTextChild(WebInspector.UIString("Device pixel ratio:"));
252         rowElement.createChild("td").appendChild(WebInspector.SettingsUI.createSettingInputField("", WebInspector.overridesSupport.settings.deviceScaleFactor, true, 4, "80px", WebInspector.OverridesSupport.deviceScaleFactorValidator, true, true, WebInspector.UIString("\u2013")));
253
254         var mobileCheckbox = this._createSettingCheckbox(WebInspector.UIString("Emulate mobile"), WebInspector.overridesSupport.settings.emulateMobile);
255         mobileCheckbox.title = WebInspector.UIString("Enable meta viewport, overlay scrollbars, text autosizing and default 980px body width");
256         fieldsetElement.appendChild(mobileCheckbox);
257
258         fieldsetElement.appendChild(this._createSettingCheckbox(WebInspector.UIString("Shrink to fit"), WebInspector.overridesSupport.settings.deviceFitWindow));
259
260         return fieldsetElement;
261     },
262
263     /**
264      * @param {!function(string)} callback
265      */
266     _showTitleDialog: function(callback)
267     {
268         WebInspector.Dialog.show(this.element, new WebInspector.OverridesView.DeviceTab.CustomDeviceTitleDialog(callback));
269     },
270
271     __proto__: WebInspector.OverridesView.Tab.prototype
272 }
273
274 /**
275  * @constructor
276  * @extends {WebInspector.DialogDelegate}
277  * @param {!function(string)} callback
278  */
279 WebInspector.OverridesView.DeviceTab.CustomDeviceTitleDialog = function(callback)
280 {
281     WebInspector.DialogDelegate.call(this);
282
283     this.element = document.createElementWithClass("div", "custom-device-title-dialog");
284     this.element.createChild("label").textContent = WebInspector.UIString("Save as: ");
285
286     this._input = this.element.createChild("input");
287     this._input.setAttribute("type", "text");
288     this._input.placeholder = WebInspector.UIString("device model name");
289     this._input.addEventListener("input", this._onInput.bind(this), false);
290
291     this._saveButton = this.element.createChild("button");
292     this._saveButton.textContent = WebInspector.UIString("Save");
293     this._saveButton.addEventListener("click", this._onSaveClick.bind(this), false);
294
295     this._callback = callback;
296     this._result = "";
297     this._onInput();
298 }
299
300 WebInspector.OverridesView.DeviceTab.CustomDeviceTitleDialog.prototype = {
301     focus: function()
302     {
303         WebInspector.setCurrentFocusElement(this._input);
304         this._input.select();
305     },
306
307     _onSaveClick: function()
308     {
309         this._result = this._input.value.trim();
310         WebInspector.Dialog.hide();
311     },
312
313     _onInput: function()
314     {
315         this._saveButton.disabled = !this._input.value.trim();
316     },
317
318     /**
319      * @param {!Event} event
320      */
321     onEnter: function(event)
322     {
323         if (this._input.value.trim()) {
324             this._result = this._input.value.trim();
325         } else {
326             event.consume();
327         }
328     },
329
330     willHide: function()
331     {
332         this._callback(this._result);
333     },
334
335     __proto__: WebInspector.DialogDelegate.prototype
336 }
337
338 /**
339  * @constructor
340  * @extends {WebInspector.OverridesView.Tab}
341  */
342 WebInspector.OverridesView.MediaTab = function()
343 {
344     var settings = [WebInspector.overridesSupport.settings.overrideCSSMedia];
345     WebInspector.OverridesView.Tab.call(this, "media", WebInspector.UIString("Media"), settings);
346     this.element.classList.add("overrides-media");
347
348     this._createMediaEmulationFragment();
349 }
350
351 WebInspector.OverridesView.MediaTab.prototype = {
352     _createMediaEmulationFragment: function()
353     {
354         var checkbox = WebInspector.SettingsUI.createSettingCheckbox(WebInspector.UIString("CSS media"), WebInspector.overridesSupport.settings.overrideCSSMedia, true);
355         var fieldsetElement = WebInspector.SettingsUI.createSettingFieldset(WebInspector.overridesSupport.settings.overrideCSSMedia);
356         var mediaSelectElement = fieldsetElement.createChild("select");
357         var mediaTypes = WebInspector.CSSStyleModel.MediaTypes;
358         var defaultMedia = WebInspector.overridesSupport.settings.emulatedCSSMedia.get();
359         for (var i = 0; i < mediaTypes.length; ++i) {
360             var mediaType = mediaTypes[i];
361             if (mediaType === "all") {
362                 // "all" is not a device-specific media type.
363                 continue;
364             }
365             var option = document.createElement("option");
366             option.text = mediaType;
367             option.value = mediaType;
368             mediaSelectElement.add(option);
369             if (mediaType === defaultMedia)
370                 mediaSelectElement.selectedIndex = mediaSelectElement.options.length - 1;
371         }
372
373         mediaSelectElement.addEventListener("change", this._emulateMediaChanged.bind(this, mediaSelectElement), false);
374         var fragment = document.createDocumentFragment();
375         fragment.appendChild(checkbox);
376         fragment.appendChild(fieldsetElement);
377         this.element.appendChild(fragment);
378     },
379
380     _emulateMediaChanged: function(select)
381     {
382         var media = select.options[select.selectedIndex].value;
383         WebInspector.overridesSupport.settings.emulatedCSSMedia.set(media);
384     },
385
386     __proto__: WebInspector.OverridesView.Tab.prototype
387 }
388
389
390 /**
391  * @constructor
392  * @extends {WebInspector.OverridesView.Tab}
393  */
394 WebInspector.OverridesView.NetworkTab = function()
395 {
396     WebInspector.OverridesView.Tab.call(this, "network", WebInspector.UIString("Network"), [], [this._userAgentOverrideEnabled.bind(this), this._networkThroughputIsLimited.bind(this)]);
397     this.element.classList.add("overrides-network");
398     this._createNetworkConditionsElement();
399     this._createUserAgentSection();
400 }
401
402 WebInspector.OverridesView.NetworkTab.prototype = {
403     /**
404      * @return {boolean}
405      */
406     _networkThroughputIsLimited: function()
407     {
408         return WebInspector.overridesSupport.networkThroughputIsLimited();
409     },
410
411     _createNetworkConditionsElement: function()
412     {
413         var fieldsetElement = this.element.createChild("fieldset");
414         fieldsetElement.createChild("span").textContent = WebInspector.UIString("Limit network throughput:");
415         fieldsetElement.createChild("br");
416         fieldsetElement.appendChild(WebInspector.OverridesUI.createNetworkConditionsSelect(document));
417
418         WebInspector.overridesSupport.settings.networkConditions.addChangeListener(this.updateActiveState, this);
419     },
420
421     /**
422      * @return {boolean}
423      */
424     _userAgentOverrideEnabled: function()
425     {
426         return !!WebInspector.overridesSupport.settings.userAgent.get();
427     },
428
429     _createUserAgentSection: function()
430     {
431         var fieldsetElement = this.element.createChild("fieldset");
432         fieldsetElement.createChild("label").textContent = WebInspector.UIString("Spoof user agent:");
433         var selectAndInput = WebInspector.OverridesUI.createUserAgentSelectAndInput(document);
434         fieldsetElement.appendChild(selectAndInput.select);
435         fieldsetElement.appendChild(selectAndInput.input);
436
437         WebInspector.overridesSupport.settings.userAgent.addChangeListener(this.updateActiveState, this);
438     },
439
440     __proto__: WebInspector.OverridesView.Tab.prototype
441 }
442
443
444 /**
445  * @constructor
446  * @extends {WebInspector.OverridesView.Tab}
447  */
448 WebInspector.OverridesView.SensorsTab = function()
449 {
450     WebInspector.OverridesView.Tab.call(this, "sensors", WebInspector.UIString("Sensors"), [
451         WebInspector.overridesSupport.settings.overrideGeolocation,
452         WebInspector.overridesSupport.settings.overrideDeviceOrientation,
453         WebInspector.overridesSupport.settings.emulateTouch
454     ]);
455
456     this.element.classList.add("overrides-sensors");
457     this.registerRequiredCSS("accelerometer.css");
458     this.element.appendChild(this._createSettingCheckbox(WebInspector.UIString("Emulate touch screen"), WebInspector.overridesSupport.settings.emulateTouch, undefined));
459     this._appendGeolocationOverrideControl();
460     this._apendDeviceOrientationOverrideControl();
461 }
462
463 WebInspector.OverridesView.SensorsTab.prototype = {
464     _appendGeolocationOverrideControl: function()
465     {
466         const geolocationSetting = WebInspector.overridesSupport.settings.geolocationOverride.get();
467         var geolocation = WebInspector.OverridesSupport.GeolocationPosition.parseSetting(geolocationSetting);
468         this.element.appendChild(this._createSettingCheckbox(WebInspector.UIString("Emulate geolocation coordinates"), WebInspector.overridesSupport.settings.overrideGeolocation, this._geolocationOverrideCheckboxClicked.bind(this)));
469         this.element.appendChild(this._createGeolocationOverrideElement(geolocation));
470         this._geolocationOverrideCheckboxClicked(WebInspector.overridesSupport.settings.overrideGeolocation.get());
471     },
472
473     /**
474      * @param {boolean} enabled
475      */
476     _geolocationOverrideCheckboxClicked: function(enabled)
477     {
478         if (enabled && !this._latitudeElement.value)
479             this._latitudeElement.focus();
480     },
481
482     _applyGeolocationUserInput: function()
483     {
484         this._setGeolocationPosition(WebInspector.OverridesSupport.GeolocationPosition.parseUserInput(this._latitudeElement.value.trim(), this._longitudeElement.value.trim(), this._geolocationErrorElement.checked), true);
485     },
486
487     /**
488      * @param {?WebInspector.OverridesSupport.GeolocationPosition} geolocation
489      * @param {boolean} userInputModified
490      */
491     _setGeolocationPosition: function(geolocation, userInputModified)
492     {
493         if (!geolocation)
494             return;
495
496         if (!userInputModified) {
497             this._latitudeElement.value = geolocation.latitude;
498             this._longitudeElement.value = geolocation.longitude;
499         }
500
501         var value = geolocation.toSetting();
502         WebInspector.overridesSupport.settings.geolocationOverride.set(value);
503     },
504
505     /**
506      * @param {!WebInspector.OverridesSupport.GeolocationPosition} geolocation
507      * @return {!Element}
508      */
509     _createGeolocationOverrideElement: function(geolocation)
510     {
511         var fieldsetElement = WebInspector.SettingsUI.createSettingFieldset(WebInspector.overridesSupport.settings.overrideGeolocation);
512         fieldsetElement.id = "geolocation-override-section";
513
514         var tableElement = fieldsetElement.createChild("table");
515         var rowElement = tableElement.createChild("tr");
516         var cellElement = rowElement.createChild("td");
517         cellElement = rowElement.createChild("td");
518         cellElement.createTextChild(WebInspector.UIString("Lat = "));
519         this._latitudeElement = WebInspector.SettingsUI.createInput(cellElement, "geolocation-override-latitude", String(geolocation.latitude), this._applyGeolocationUserInput.bind(this), true);
520         cellElement.createTextChild(" , ");
521         cellElement.createTextChild(WebInspector.UIString("Lon = "));
522         this._longitudeElement = WebInspector.SettingsUI.createInput(cellElement, "geolocation-override-longitude", String(geolocation.longitude), this._applyGeolocationUserInput.bind(this), true);
523         rowElement = tableElement.createChild("tr");
524         cellElement = rowElement.createChild("td");
525         cellElement.colSpan = 2;
526         var geolocationErrorLabelElement = document.createElement("label");
527         var geolocationErrorCheckboxElement = geolocationErrorLabelElement.createChild("input");
528         geolocationErrorCheckboxElement.id = "geolocation-error";
529         geolocationErrorCheckboxElement.type = "checkbox";
530         geolocationErrorCheckboxElement.checked = !geolocation || geolocation.error;
531         geolocationErrorCheckboxElement.addEventListener("click", this._applyGeolocationUserInput.bind(this), false);
532         geolocationErrorLabelElement.createTextChild(WebInspector.UIString("Emulate position unavailable"));
533         this._geolocationErrorElement = geolocationErrorCheckboxElement;
534         cellElement.appendChild(geolocationErrorLabelElement);
535
536         return fieldsetElement;
537     },
538
539     _apendDeviceOrientationOverrideControl: function()
540     {
541         const deviceOrientationSetting = WebInspector.overridesSupport.settings.deviceOrientationOverride.get();
542         var deviceOrientation = WebInspector.OverridesSupport.DeviceOrientation.parseSetting(deviceOrientationSetting);
543         this.element.appendChild(this._createSettingCheckbox(WebInspector.UIString("Accelerometer"), WebInspector.overridesSupport.settings.overrideDeviceOrientation, this._deviceOrientationOverrideCheckboxClicked.bind(this)));
544         this.element.appendChild(this._createDeviceOrientationOverrideElement(deviceOrientation));
545         this._deviceOrientationOverrideCheckboxClicked(WebInspector.overridesSupport.settings.overrideDeviceOrientation.get());
546     },
547
548     /**
549      * @param {boolean} enabled
550      */
551     _deviceOrientationOverrideCheckboxClicked: function(enabled)
552     {
553         if (enabled && !this._alphaElement.value)
554             this._alphaElement.focus();
555     },
556
557     _applyDeviceOrientationUserInput: function()
558     {
559         this._setDeviceOrientation(WebInspector.OverridesSupport.DeviceOrientation.parseUserInput(this._alphaElement.value.trim(), this._betaElement.value.trim(), this._gammaElement.value.trim()), WebInspector.OverridesView.SensorsTab.DeviceOrientationModificationSource.UserInput);
560     },
561
562     _resetDeviceOrientation: function()
563     {
564         this._setDeviceOrientation(new WebInspector.OverridesSupport.DeviceOrientation(0, 0, 0), WebInspector.OverridesView.SensorsTab.DeviceOrientationModificationSource.ResetButton);
565     },
566
567     /**
568      * @param {?WebInspector.OverridesSupport.DeviceOrientation} deviceOrientation
569      * @param {!WebInspector.OverridesView.SensorsTab.DeviceOrientationModificationSource} modificationSource
570      */
571     _setDeviceOrientation: function(deviceOrientation, modificationSource)
572     {
573         if (!deviceOrientation)
574             return;
575
576         if (modificationSource != WebInspector.OverridesView.SensorsTab.DeviceOrientationModificationSource.UserInput) {
577             this._alphaElement.value = deviceOrientation.alpha;
578             this._betaElement.value = deviceOrientation.beta;
579             this._gammaElement.value = deviceOrientation.gamma;
580         }
581
582         if (modificationSource != WebInspector.OverridesView.SensorsTab.DeviceOrientationModificationSource.UserDrag)
583             this._setBoxOrientation(deviceOrientation);
584
585         var value = deviceOrientation.toSetting();
586         WebInspector.overridesSupport.settings.deviceOrientationOverride.set(value);
587     },
588
589     /**
590      * @param {!Element} parentElement
591      * @param {string} id
592      * @param {string} label
593      * @param {string} defaultText
594      * @return {!Element}
595      */
596     _createAxisInput: function(parentElement, id, label, defaultText)
597     {
598         var div = parentElement.createChild("div", "accelerometer-axis-input-container");
599         div.createTextChild(label);
600         return WebInspector.SettingsUI.createInput(div, id, defaultText, this._applyDeviceOrientationUserInput.bind(this), true);
601     },
602
603     /**
604      * @param {!WebInspector.OverridesSupport.DeviceOrientation} deviceOrientation
605      */
606     _createDeviceOrientationOverrideElement: function(deviceOrientation)
607     {
608         var fieldsetElement = WebInspector.SettingsUI.createSettingFieldset(WebInspector.overridesSupport.settings.overrideDeviceOrientation);
609         fieldsetElement.id = "device-orientation-override-section";
610         var tableElement = fieldsetElement.createChild("table");
611         var rowElement = tableElement.createChild("tr");
612         var cellElement = rowElement.createChild("td", "accelerometer-inputs-cell");
613
614         this._alphaElement = this._createAxisInput(cellElement, "device-orientation-override-alpha", "\u03B1: ", String(deviceOrientation.alpha));
615         this._betaElement = this._createAxisInput(cellElement, "device-orientation-override-beta", "\u03B2: ", String(deviceOrientation.beta));
616         this._gammaElement = this._createAxisInput(cellElement, "device-orientation-override-gamma", "\u03B3: ", String(deviceOrientation.gamma));
617
618         var resetButton = cellElement.createChild("button", "text-button accelerometer-reset-button");
619         resetButton.textContent = WebInspector.UIString("Reset");
620         resetButton.addEventListener("click", this._resetDeviceOrientation.bind(this), false);
621
622         this._stageElement = rowElement.createChild("td","accelerometer-stage");
623         this._boxElement = this._stageElement.createChild("section", "accelerometer-box");
624
625         this._boxElement.createChild("section", "front");
626         this._boxElement.createChild("section", "top");
627         this._boxElement.createChild("section", "back");
628         this._boxElement.createChild("section", "left");
629         this._boxElement.createChild("section", "right");
630         this._boxElement.createChild("section", "bottom");
631
632         WebInspector.installDragHandle(this._stageElement, this._onBoxDragStart.bind(this), this._onBoxDrag.bind(this), this._onBoxDragEnd.bind(this), "move");
633         this._setBoxOrientation(deviceOrientation);
634         return fieldsetElement;
635     },
636
637     /**
638      * @param {!WebInspector.OverridesSupport.DeviceOrientation} deviceOrientation
639      */
640     _setBoxOrientation: function(deviceOrientation)
641     {
642         var matrix = new WebKitCSSMatrix();
643         this._boxMatrix = matrix.rotate(-deviceOrientation.beta, deviceOrientation.gamma, -deviceOrientation.alpha);
644         this._boxElement.style.webkitTransform = this._boxMatrix.toString();
645     },
646
647     /**
648      * @param {!MouseEvent} event
649      * @return {boolean}
650      */
651     _onBoxDrag: function(event)
652     {
653         var mouseMoveVector = this._calculateRadiusVector(event.x, event.y);
654         if (!mouseMoveVector)
655             return true;
656
657         event.consume(true);
658         var axis = WebInspector.Geometry.crossProduct(this._mouseDownVector, mouseMoveVector);
659         axis.normalize();
660         var angle = WebInspector.Geometry.calculateAngle(this._mouseDownVector, mouseMoveVector);
661         var matrix = new WebKitCSSMatrix();
662         var rotationMatrix = matrix.rotateAxisAngle(axis.x, axis.y, axis.z, angle);
663         this._currentMatrix = rotationMatrix.multiply(this._boxMatrix)
664         this._boxElement.style.webkitTransform = this._currentMatrix;
665         var eulerAngles = WebInspector.Geometry.EulerAngles.fromRotationMatrix(this._currentMatrix);
666         var newOrientation = new WebInspector.OverridesSupport.DeviceOrientation(-eulerAngles.alpha, -eulerAngles.beta, eulerAngles.gamma);
667         this._setDeviceOrientation(newOrientation, WebInspector.OverridesView.SensorsTab.DeviceOrientationModificationSource.UserDrag);
668         return false;
669     },
670
671     /**
672      * @param {!MouseEvent} event
673      * @return {boolean}
674      */
675     _onBoxDragStart: function(event)
676     {
677         if (!WebInspector.overridesSupport.settings.overrideDeviceOrientation.get())
678             return false;
679
680         this._mouseDownVector = this._calculateRadiusVector(event.x, event.y);
681
682         if (!this._mouseDownVector)
683             return false;
684
685         event.consume(true);
686         return true;
687     },
688
689     _onBoxDragEnd: function()
690     {
691         this._boxMatrix = this._currentMatrix;
692     },
693
694     /**
695      * @param {number} x
696      * @param {number} y
697      * @return {?WebInspector.Geometry.Vector}
698      */
699     _calculateRadiusVector: function(x, y)
700     {
701         var rect = this._stageElement.getBoundingClientRect();
702         var radius = Math.max(rect.width, rect.height) / 2;
703         var sphereX = (x - rect.left - rect.width / 2) / radius;
704         var sphereY = (y - rect.top - rect.height / 2) / radius;
705         var sqrSum = sphereX * sphereX + sphereY * sphereY;
706         if (sqrSum > 0.5)
707             return new WebInspector.Geometry.Vector(sphereX, sphereY, 0.5 / Math.sqrt(sqrSum));
708
709         return new WebInspector.Geometry.Vector(sphereX, sphereY, Math.sqrt(1 - sqrSum));
710     },
711
712     __proto__ : WebInspector.OverridesView.Tab.prototype
713 }
714
715 /** @enum {string} */
716 WebInspector.OverridesView.SensorsTab.DeviceOrientationModificationSource = {
717     UserInput: "userInput",
718     UserDrag: "userDrag",
719     ResetButton: "resetButton"
720 }
721
722 /**
723  * @constructor
724  * @implements {WebInspector.Revealer}
725  */
726 WebInspector.OverridesView.Revealer = function()
727 {
728 }
729
730 WebInspector.OverridesView.Revealer.prototype = {
731     /**
732      * @param {!Object} overridesSupport
733      */
734     reveal: function(overridesSupport)
735     {
736         WebInspector.inspectorView.showViewInDrawer("emulation");
737     }
738 }