2 * Copyright (C) 2014 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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
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.
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.
33 * @extends {WebInspector.VBox}
35 WebInspector.OverridesView = function()
37 WebInspector.VBox.call(this);
38 this.registerRequiredCSS("main/overrides.css");
39 this.element.classList.add("overrides-view");
41 this._tabbedPane = new WebInspector.TabbedPane();
42 this._tabbedPane.shrinkableTabs = false;
43 this._tabbedPane.verticalTabLayout = true;
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);
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);
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);
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);
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."));
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."));
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);
83 this._warningFooter = this.element.createChild("div", "overrides-footer");
84 this._overridesWarningUpdated();
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();
91 WebInspector.OverridesView.prototype = {
93 * @param {!WebInspector.Event} event
95 _tabSelected: function(event)
97 this._lastSelectedTabSetting.set(this._tabbedPane.selectedTabId);
100 _overridesWarningUpdated: function()
102 var message = WebInspector.overridesSupport.warningMessage();
103 this._warningFooter.classList.toggle("hidden", !message);
104 this._warningFooter.textContent = message;
107 _toggleEmulationEnabled: function()
109 WebInspector.overridesSupport.setEmulationEnabled(!WebInspector.overridesSupport.emulationEnabled());
112 _emulationStateChanged: function()
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());
119 __proto__: WebInspector.VBox.prototype
124 * @extends {WebInspector.VBox}
126 * @param {string} name
127 * @param {!Array.<!WebInspector.Setting>} settings
128 * @param {!Array.<function():boolean>=} predicates
130 WebInspector.OverridesView.Tab = function(id, name, settings, predicates)
132 WebInspector.VBox.call(this);
135 this._settings = settings;
136 this._predicates = predicates || [];
137 for (var i = 0; i < settings.length; ++i)
138 settings[i].addChangeListener(this.updateActiveState, this);
141 WebInspector.OverridesView.Tab.prototype = {
143 * @param {!WebInspector.TabbedPane} tabbedPane
145 appendAsTab: function(tabbedPane)
147 this._tabbedPane = tabbedPane;
148 tabbedPane.appendTab(this._id, this._name, this);
149 this.updateActiveState();
152 updateActiveState: function()
154 if (!this._tabbedPane)
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);
165 * @param {string} name
166 * @param {!WebInspector.Setting} setting
167 * @param {function(boolean)=} callback
169 _createSettingCheckbox: function(name, setting, callback)
171 var checkbox = WebInspector.SettingsUI.createSettingCheckbox(name, setting, true);
173 function changeListener(value)
175 callback(setting.get());
179 setting.addChangeListener(changeListener);
184 __proto__: WebInspector.VBox.prototype
189 * @extends {WebInspector.OverridesView.Tab}
191 WebInspector.OverridesView.DeviceTab = function()
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
198 this.element.classList.add("overrides-device");
200 this.element.appendChild(this._createDeviceElement());
202 var footnote = this.element.createChild("p", "help-footnote");
203 footnote.appendChild(WebInspector.createDocumentationAnchor("device-mode", WebInspector.UIString("More information about screen emulation")));
206 WebInspector.OverridesView.DeviceTab.prototype = {
207 _createDeviceElement: function()
209 var fieldsetElement = createElement("fieldset");
210 fieldsetElement.id = "metrics-override-section";
212 var deviceModelElement = fieldsetElement.createChild("p", "overrides-device-model-section");
213 deviceModelElement.createChild("span").textContent = WebInspector.UIString("Model:");
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);
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);
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");
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);
242 rowElement = tableElement.createChild("tr");
243 cellElement = rowElement.createChild("td");
244 cellElement.colSpan = 4;
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")));
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);
255 fieldsetElement.appendChild(this._createSettingCheckbox(WebInspector.UIString("Shrink to fit"), WebInspector.overridesSupport.settings.deviceFitWindow));
257 return fieldsetElement;
261 * @param {!function(string)} callback
263 _showTitleDialog: function(callback)
265 WebInspector.Dialog.show(this.element, new WebInspector.OverridesView.DeviceTab.CustomDeviceTitleDialog(callback));
268 __proto__: WebInspector.OverridesView.Tab.prototype
273 * @extends {WebInspector.DialogDelegate}
274 * @param {!function(string)} callback
276 WebInspector.OverridesView.DeviceTab.CustomDeviceTitleDialog = function(callback)
278 WebInspector.DialogDelegate.call(this);
280 this.element = createElementWithClass("div", "custom-device-title-dialog");
281 this.element.createChild("label").textContent = WebInspector.UIString("Save as: ");
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);
288 this._saveButton = this.element.createChild("button");
289 this._saveButton.textContent = WebInspector.UIString("Save");
290 this._saveButton.addEventListener("click", this._onSaveClick.bind(this), false);
292 this._callback = callback;
297 WebInspector.OverridesView.DeviceTab.CustomDeviceTitleDialog.prototype = {
300 WebInspector.setCurrentFocusElement(this._input);
301 this._input.select();
304 _onSaveClick: function()
306 this._result = this._input.value.trim();
307 WebInspector.Dialog.hide();
312 this._saveButton.disabled = !this._input.value.trim();
316 * @param {!Event} event
318 onEnter: function(event)
320 if (this._input.value.trim()) {
321 this._result = this._input.value.trim();
329 this._callback(this._result);
332 __proto__: WebInspector.DialogDelegate.prototype
337 * @extends {WebInspector.OverridesView.Tab}
339 WebInspector.OverridesView.MediaTab = function()
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");
345 this._createMediaEmulationFragment();
348 WebInspector.OverridesView.MediaTab.prototype = {
349 _createMediaEmulationFragment: function()
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.
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;
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);
377 _emulateMediaChanged: function(select)
379 var media = select.options[select.selectedIndex].value;
380 WebInspector.overridesSupport.settings.emulatedCSSMedia.set(media);
383 __proto__: WebInspector.OverridesView.Tab.prototype
389 * @extends {WebInspector.OverridesView.Tab}
391 WebInspector.OverridesView.NetworkTab = function()
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();
399 WebInspector.OverridesView.NetworkTab.prototype = {
403 _networkThroughputIsLimited: function()
405 return WebInspector.overridesSupport.networkThroughputIsLimited();
408 _createNetworkConditionsElement: function()
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());
415 WebInspector.overridesSupport.settings.networkConditions.addChangeListener(this.updateActiveState, this);
421 _userAgentOverrideEnabled: function()
423 return !!WebInspector.overridesSupport.settings.userAgent.get();
426 _createUserAgentSection: function()
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);
434 WebInspector.overridesSupport.settings.userAgent.addChangeListener(this.updateActiveState, this);
437 __proto__: WebInspector.OverridesView.Tab.prototype
443 * @extends {WebInspector.OverridesView.Tab}
445 WebInspector.OverridesView.SensorsTab = function()
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
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();
460 WebInspector.OverridesView.SensorsTab.prototype = {
461 _appendGeolocationOverrideControl: function()
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());
471 * @param {boolean} enabled
473 _geolocationOverrideCheckboxClicked: function(enabled)
475 if (enabled && !this._latitudeElement.value)
476 this._latitudeElement.focus();
479 _applyGeolocationUserInput: function()
481 this._setGeolocationPosition(WebInspector.OverridesSupport.GeolocationPosition.parseUserInput(this._latitudeElement.value.trim(), this._longitudeElement.value.trim(), this._geolocationErrorElement.checked), true);
485 * @param {?WebInspector.OverridesSupport.GeolocationPosition} geolocation
486 * @param {boolean} userInputModified
488 _setGeolocationPosition: function(geolocation, userInputModified)
493 if (!userInputModified) {
494 this._latitudeElement.value = geolocation.latitude;
495 this._longitudeElement.value = geolocation.longitude;
498 var value = geolocation.toSetting();
499 WebInspector.overridesSupport.settings.geolocationOverride.set(value);
503 * @param {!WebInspector.OverridesSupport.GeolocationPosition} geolocation
506 _createGeolocationOverrideElement: function(geolocation)
508 var fieldsetElement = WebInspector.SettingsUI.createSettingFieldset(WebInspector.overridesSupport.settings.overrideGeolocation);
509 fieldsetElement.id = "geolocation-override-section";
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);
533 return fieldsetElement;
536 _apendDeviceOrientationOverrideControl: function()
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());
546 * @param {boolean} enabled
548 _deviceOrientationOverrideCheckboxClicked: function(enabled)
550 if (enabled && !this._alphaElement.value)
551 this._alphaElement.focus();
554 _applyDeviceOrientationUserInput: function()
556 this._setDeviceOrientation(WebInspector.OverridesSupport.DeviceOrientation.parseUserInput(this._alphaElement.value.trim(), this._betaElement.value.trim(), this._gammaElement.value.trim()), WebInspector.OverridesView.SensorsTab.DeviceOrientationModificationSource.UserInput);
559 _resetDeviceOrientation: function()
561 this._setDeviceOrientation(new WebInspector.OverridesSupport.DeviceOrientation(0, 0, 0), WebInspector.OverridesView.SensorsTab.DeviceOrientationModificationSource.ResetButton);
565 * @param {?WebInspector.OverridesSupport.DeviceOrientation} deviceOrientation
566 * @param {!WebInspector.OverridesView.SensorsTab.DeviceOrientationModificationSource} modificationSource
568 _setDeviceOrientation: function(deviceOrientation, modificationSource)
570 if (!deviceOrientation)
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;
579 if (modificationSource != WebInspector.OverridesView.SensorsTab.DeviceOrientationModificationSource.UserDrag)
580 this._setBoxOrientation(deviceOrientation);
582 var value = deviceOrientation.toSetting();
583 WebInspector.overridesSupport.settings.deviceOrientationOverride.set(value);
587 * @param {!Element} parentElement
589 * @param {string} label
590 * @param {string} defaultText
593 _createAxisInput: function(parentElement, id, label, defaultText)
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);
601 * @param {!WebInspector.OverridesSupport.DeviceOrientation} deviceOrientation
603 _createDeviceOrientationOverrideElement: function(deviceOrientation)
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");
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));
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);
619 this._stageElement = rowElement.createChild("td","accelerometer-stage");
620 this._boxElement = this._stageElement.createChild("section", "accelerometer-box");
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");
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;
635 * @param {!WebInspector.OverridesSupport.DeviceOrientation} deviceOrientation
637 _setBoxOrientation: function(deviceOrientation)
639 var matrix = new WebKitCSSMatrix();
640 this._boxMatrix = matrix.rotate(-deviceOrientation.beta, deviceOrientation.gamma, -deviceOrientation.alpha);
641 this._boxElement.style.webkitTransform = this._boxMatrix.toString();
645 * @param {!MouseEvent} event
648 _onBoxDrag: function(event)
650 var mouseMoveVector = this._calculateRadiusVector(event.x, event.y);
651 if (!mouseMoveVector)
655 var axis = WebInspector.Geometry.crossProduct(this._mouseDownVector, mouseMoveVector);
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);
669 * @param {!MouseEvent} event
672 _onBoxDragStart: function(event)
674 if (!WebInspector.overridesSupport.settings.overrideDeviceOrientation.get())
677 this._mouseDownVector = this._calculateRadiusVector(event.x, event.y);
679 if (!this._mouseDownVector)
686 _onBoxDragEnd: function()
688 this._boxMatrix = this._currentMatrix;
694 * @return {?WebInspector.Geometry.Vector}
696 _calculateRadiusVector: function(x, y)
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;
704 return new WebInspector.Geometry.Vector(sphereX, sphereY, 0.5 / Math.sqrt(sqrSum));
706 return new WebInspector.Geometry.Vector(sphereX, sphereY, Math.sqrt(1 - sqrSum));
709 __proto__ : WebInspector.OverridesView.Tab.prototype
712 /** @enum {string} */
713 WebInspector.OverridesView.SensorsTab.DeviceOrientationModificationSource = {
714 UserInput: "userInput",
715 UserDrag: "userDrag",
716 ResetButton: "resetButton"
721 * @implements {WebInspector.Revealer}
723 WebInspector.OverridesView.Revealer = function()
727 WebInspector.OverridesView.Revealer.prototype = {
729 * @param {!Object} overridesSupport
732 reveal: function(overridesSupport)
734 WebInspector.inspectorView.showViewInDrawer("emulation");
735 return Promise.resolve();