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("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 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"));
209 WebInspector.OverridesView.DeviceTab.prototype = {
210 _createDeviceElement: function()
212 var fieldsetElement = document.createElement("fieldset");
213 fieldsetElement.id = "metrics-override-section";
215 var deviceModelElement = fieldsetElement.createChild("p", "overrides-device-model-section");
216 deviceModelElement.createChild("span").textContent = WebInspector.UIString("Model:");
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);
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);
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");
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);
245 rowElement = tableElement.createChild("tr");
246 cellElement = rowElement.createChild("td");
247 cellElement.colSpan = 4;
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")));
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);
258 fieldsetElement.appendChild(this._createSettingCheckbox(WebInspector.UIString("Shrink to fit"), WebInspector.overridesSupport.settings.deviceFitWindow));
260 return fieldsetElement;
264 * @param {!function(string)} callback
266 _showTitleDialog: function(callback)
268 WebInspector.Dialog.show(this.element, new WebInspector.OverridesView.DeviceTab.CustomDeviceTitleDialog(callback));
271 __proto__: WebInspector.OverridesView.Tab.prototype
276 * @extends {WebInspector.DialogDelegate}
277 * @param {!function(string)} callback
279 WebInspector.OverridesView.DeviceTab.CustomDeviceTitleDialog = function(callback)
281 WebInspector.DialogDelegate.call(this);
283 this.element = document.createElementWithClass("div", "custom-device-title-dialog");
284 this.element.createChild("label").textContent = WebInspector.UIString("Save as: ");
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);
291 this._saveButton = this.element.createChild("button");
292 this._saveButton.textContent = WebInspector.UIString("Save");
293 this._saveButton.addEventListener("click", this._onSaveClick.bind(this), false);
295 this._callback = callback;
300 WebInspector.OverridesView.DeviceTab.CustomDeviceTitleDialog.prototype = {
303 WebInspector.setCurrentFocusElement(this._input);
304 this._input.select();
307 _onSaveClick: function()
309 this._result = this._input.value.trim();
310 WebInspector.Dialog.hide();
315 this._saveButton.disabled = !this._input.value.trim();
319 * @param {!Event} event
321 onEnter: function(event)
323 if (this._input.value.trim()) {
324 this._result = this._input.value.trim();
332 this._callback(this._result);
335 __proto__: WebInspector.DialogDelegate.prototype
340 * @extends {WebInspector.OverridesView.Tab}
342 WebInspector.OverridesView.MediaTab = function()
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");
348 this._createMediaEmulationFragment();
351 WebInspector.OverridesView.MediaTab.prototype = {
352 _createMediaEmulationFragment: function()
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.
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;
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);
380 _emulateMediaChanged: function(select)
382 var media = select.options[select.selectedIndex].value;
383 WebInspector.overridesSupport.settings.emulatedCSSMedia.set(media);
386 __proto__: WebInspector.OverridesView.Tab.prototype
392 * @extends {WebInspector.OverridesView.Tab}
394 WebInspector.OverridesView.NetworkTab = function()
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();
402 WebInspector.OverridesView.NetworkTab.prototype = {
406 _networkThroughputIsLimited: function()
408 return WebInspector.overridesSupport.networkThroughputIsLimited();
411 _createNetworkConditionsElement: function()
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));
418 WebInspector.overridesSupport.settings.networkConditions.addChangeListener(this.updateActiveState, this);
424 _userAgentOverrideEnabled: function()
426 return !!WebInspector.overridesSupport.settings.userAgent.get();
429 _createUserAgentSection: function()
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);
437 WebInspector.overridesSupport.settings.userAgent.addChangeListener(this.updateActiveState, this);
440 __proto__: WebInspector.OverridesView.Tab.prototype
446 * @extends {WebInspector.OverridesView.Tab}
448 WebInspector.OverridesView.SensorsTab = function()
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
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();
463 WebInspector.OverridesView.SensorsTab.prototype = {
464 _appendGeolocationOverrideControl: function()
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());
474 * @param {boolean} enabled
476 _geolocationOverrideCheckboxClicked: function(enabled)
478 if (enabled && !this._latitudeElement.value)
479 this._latitudeElement.focus();
482 _applyGeolocationUserInput: function()
484 this._setGeolocationPosition(WebInspector.OverridesSupport.GeolocationPosition.parseUserInput(this._latitudeElement.value.trim(), this._longitudeElement.value.trim(), this._geolocationErrorElement.checked), true);
488 * @param {?WebInspector.OverridesSupport.GeolocationPosition} geolocation
489 * @param {boolean} userInputModified
491 _setGeolocationPosition: function(geolocation, userInputModified)
496 if (!userInputModified) {
497 this._latitudeElement.value = geolocation.latitude;
498 this._longitudeElement.value = geolocation.longitude;
501 var value = geolocation.toSetting();
502 WebInspector.overridesSupport.settings.geolocationOverride.set(value);
506 * @param {!WebInspector.OverridesSupport.GeolocationPosition} geolocation
509 _createGeolocationOverrideElement: function(geolocation)
511 var fieldsetElement = WebInspector.SettingsUI.createSettingFieldset(WebInspector.overridesSupport.settings.overrideGeolocation);
512 fieldsetElement.id = "geolocation-override-section";
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);
536 return fieldsetElement;
539 _apendDeviceOrientationOverrideControl: function()
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());
549 * @param {boolean} enabled
551 _deviceOrientationOverrideCheckboxClicked: function(enabled)
553 if (enabled && !this._alphaElement.value)
554 this._alphaElement.focus();
557 _applyDeviceOrientationUserInput: function()
559 this._setDeviceOrientation(WebInspector.OverridesSupport.DeviceOrientation.parseUserInput(this._alphaElement.value.trim(), this._betaElement.value.trim(), this._gammaElement.value.trim()), WebInspector.OverridesView.SensorsTab.DeviceOrientationModificationSource.UserInput);
562 _resetDeviceOrientation: function()
564 this._setDeviceOrientation(new WebInspector.OverridesSupport.DeviceOrientation(0, 0, 0), WebInspector.OverridesView.SensorsTab.DeviceOrientationModificationSource.ResetButton);
568 * @param {?WebInspector.OverridesSupport.DeviceOrientation} deviceOrientation
569 * @param {!WebInspector.OverridesView.SensorsTab.DeviceOrientationModificationSource} modificationSource
571 _setDeviceOrientation: function(deviceOrientation, modificationSource)
573 if (!deviceOrientation)
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;
582 if (modificationSource != WebInspector.OverridesView.SensorsTab.DeviceOrientationModificationSource.UserDrag)
583 this._setBoxOrientation(deviceOrientation);
585 var value = deviceOrientation.toSetting();
586 WebInspector.overridesSupport.settings.deviceOrientationOverride.set(value);
590 * @param {!Element} parentElement
592 * @param {string} label
593 * @param {string} defaultText
596 _createAxisInput: function(parentElement, id, label, defaultText)
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);
604 * @param {!WebInspector.OverridesSupport.DeviceOrientation} deviceOrientation
606 _createDeviceOrientationOverrideElement: function(deviceOrientation)
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");
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));
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);
622 this._stageElement = rowElement.createChild("td","accelerometer-stage");
623 this._boxElement = this._stageElement.createChild("section", "accelerometer-box");
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");
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;
638 * @param {!WebInspector.OverridesSupport.DeviceOrientation} deviceOrientation
640 _setBoxOrientation: function(deviceOrientation)
642 var matrix = new WebKitCSSMatrix();
643 this._boxMatrix = matrix.rotate(-deviceOrientation.beta, deviceOrientation.gamma, -deviceOrientation.alpha);
644 this._boxElement.style.webkitTransform = this._boxMatrix.toString();
648 * @param {!MouseEvent} event
651 _onBoxDrag: function(event)
653 var mouseMoveVector = this._calculateRadiusVector(event.x, event.y);
654 if (!mouseMoveVector)
658 var axis = WebInspector.Geometry.crossProduct(this._mouseDownVector, mouseMoveVector);
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);
672 * @param {!MouseEvent} event
675 _onBoxDragStart: function(event)
677 if (!WebInspector.overridesSupport.settings.overrideDeviceOrientation.get())
680 this._mouseDownVector = this._calculateRadiusVector(event.x, event.y);
682 if (!this._mouseDownVector)
689 _onBoxDragEnd: function()
691 this._boxMatrix = this._currentMatrix;
697 * @return {?WebInspector.Geometry.Vector}
699 _calculateRadiusVector: function(x, y)
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;
707 return new WebInspector.Geometry.Vector(sphereX, sphereY, 0.5 / Math.sqrt(sqrSum));
709 return new WebInspector.Geometry.Vector(sphereX, sphereY, Math.sqrt(1 - sqrSum));
712 __proto__ : WebInspector.OverridesView.Tab.prototype
715 /** @enum {string} */
716 WebInspector.OverridesView.SensorsTab.DeviceOrientationModificationSource = {
717 UserInput: "userInput",
718 UserDrag: "userDrag",
719 ResetButton: "resetButton"
724 * @implements {WebInspector.Revealer}
726 WebInspector.OverridesView.Revealer = function()
730 WebInspector.OverridesView.Revealer.prototype = {
732 * @param {!Object} overridesSupport
734 reveal: function(overridesSupport)
736 WebInspector.inspectorView.showViewInDrawer("emulation");