+2012-04-02 Alexander Pavlov <apavlov@chromium.org>
+
+ Web Inspector: Implement frontend for device metrics emulation
+ https://bugs.webkit.org/show_bug.cgi?id=82891
+
+ This change implements the backend-based device metrics emulation capability discovery,
+ UI (enablement checkbox + input controls), and a persistence setting
+ for the user-specified device metrics (screen width/height and an auxiliary font scale factor).
+
+ Reviewed by Pavel Feldman.
+
+ * English.lproj/localizedStrings.js:
+ * WebCore.gypi:
+ * WebCore.vcproj/WebCore.vcproj:
+ * inspector/compile-front-end.py:
+ * inspector/front-end/Settings.js:
+ * inspector/front-end/SettingsScreen.js:
+ (WebInspector.SettingsScreen):
+ (WebInspector.SettingsScreen.prototype._createUserAgentSelectRowElement.get const):
+ (WebInspector.SettingsScreen.prototype._showPaintRectsChanged):
+ (WebInspector.SettingsScreen.prototype.set _applyDeviceMetricsUserInput):
+ (WebInspector.SettingsScreen.prototype._setDeviceMetricsOverride):
+ (WebInspector.SettingsScreen.prototype._setDeviceMetricsOverride.set if):
+ (WebInspector.SettingsScreen.prototype._createDeviceMetricsElement.createInput):
+ (WebInspector.SettingsScreen.prototype._createDeviceMetricsElement):
+ * inspector/front-end/UserAgentSupport.js: Added.
+ (WebInspector.UserAgentSupport.DeviceMetrics):
+ (WebInspector.UserAgentSupport.DeviceMetrics.parseSetting):
+ (WebInspector.UserAgentSupport.DeviceMetrics.parseUserInput):
+ (WebInspector.UserAgentSupport.DeviceMetrics.prototype.isValid):
+ (WebInspector.UserAgentSupport.DeviceMetrics.prototype.isWidthValid):
+ (WebInspector.UserAgentSupport.DeviceMetrics.prototype.isHeightValid):
+ (WebInspector.UserAgentSupport.DeviceMetrics.prototype.isFontScaleFactorValid):
+ (WebInspector.UserAgentSupport.DeviceMetrics.prototype.toSetting):
+ (WebInspector.UserAgentSupport.DeviceMetrics.prototype.widthToInput):
+ (WebInspector.UserAgentSupport.DeviceMetrics.prototype.heightToInput):
+ (WebInspector.UserAgentSupport.DeviceMetrics.prototype.fontScaleFactorToInput):
+ * inspector/front-end/WebKit.qrc:
+ * inspector/front-end/helpScreen.css:
+ (.help-table > tr > th):
+ (.help-table > tr > td):
+ (#resolution-override-section):
+ * inspector/front-end/inspector.css:
+ (.hidden):
+ (.error-input):
+ * inspector/front-end/inspector.html:
+ * inspector/front-end/inspector.js:
+ (WebInspector.doLoadedDone):
+
2012-04-02 Alexis Menard <alexis.menard@openbossa.org>
Rename CSSPropertyLonghand class to StylePropertyShorthand.
], WebInspector.settings.textEditorIndent));
p = this._appendSection(WebInspector.UIString("User Agent"), true);
- p.appendChild(this._createUserActionControl());
+ p.appendChild(this._createUserAgentControl());
+ if (Capabilities.canOverrideDeviceMetrics)
+ p.appendChild(this._createDeviceMetricsControl());
p.appendChild(this._createCheckboxSetting(WebInspector.UIString("Emulate touch events"), WebInspector.settings.emulateTouchEvents));
p = this._appendSection(WebInspector.UIString("Scripts"), true);
for (var i = 0; i < experiments.length; ++i)
experimentsSection.appendChild(this._createExperimentCheckbox(experiments[i]));
}
-
+
var table = document.createElement("table");
table.className = "help-table";
var tr = document.createElement("tr");
return p;
},
- _createUserActionControl: function()
+ _createUserAgentControl: function()
{
var userAgent = WebInspector.settings.userAgent.get();
_createUserAgentSelectRowElement: function()
{
var userAgent = WebInspector.settings.userAgent.get();
+
+ // When present, the third element lists device metrics separated by 'x':
+ // - screen width,
+ // - screen height,
+ // - font scale factor.
const userAgents = [
["Internet Explorer 9", "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)"],
["Internet Explorer 8", "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0)"],
["Firefox 4 \u2014 Windows", "Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1"],
["Firefox 4 \u2014 Mac", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko/20100101 Firefox/4.0.1"],
- ["iPhone \u2014 iOS 5", "Mozilla/5.0 (iPhone; CPU iPhone OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3"],
- ["iPhone \u2014 iOS 4", "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_3_2 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8H7 Safari/6533.18.5"],
- ["iPad \u2014 iOS 5", "Mozilla/5.0 (iPad; CPU OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3"],
- ["iPad \u2014 iOS 4", "Mozilla/5.0 (iPad; CPU OS 4_3_2 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8H7 Safari/6533.18.5"],
+ ["iPhone \u2014 iOS 5", "Mozilla/5.0 (iPhone; CPU iPhone OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3", "640x960x1"],
+ ["iPhone \u2014 iOS 4", "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_3_2 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8H7 Safari/6533.18.5", "640x960x1"],
+ ["iPad \u2014 iOS 5", "Mozilla/5.0 (iPad; CPU OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3", "1024x768x1"],
+ ["iPad \u2014 iOS 4", "Mozilla/5.0 (iPad; CPU OS 4_3_2 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8H7 Safari/6533.18.5", "1024x768x1"],
- ["Android 2.3 \u2014 Nexus S", "Mozilla/5.0 (Linux; U; Android 2.3.6; en-us; Nexus S Build/GRK39F) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1"],
+ ["Android 2.3 \u2014 Nexus S", "Mozilla/5.0 (Linux; U; Android 2.3.6; en-us; Nexus S Build/GRK39F) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1", "480x800x1.1"],
- ["BlackBerry \u2014 PlayBook 1.0","Mozilla/5.0 (PlayBook; U; RIM Tablet OS 1.0.0; en-US) AppleWebKit/534.11+ (KHTML, like Gecko) Version/7.1.0.7 Safari/534.11+"],
- ["BlackBerry \u2014 PlayBook 2.0", "Mozilla/5.0 (PlayBook; U; RIM Tablet OS 2.0.0; en-US) AppleWebKit/535.8+ (KHTML, like Gecko) Version/7.2.0.0 Safari/535.8+"],
- ["BlackBerry \u2014 9900", "Mozilla/5.0 (BlackBerry; U; BlackBerry 9900; en-US) AppleWebKit/534.11+ (KHTML, like Gecko) Version/7.0.0.187 Mobile Safari/534.11+"],
+ ["BlackBerry \u2014 PlayBook 1.0","Mozilla/5.0 (PlayBook; U; RIM Tablet OS 1.0.0; en-US) AppleWebKit/534.11+ (KHTML, like Gecko) Version/7.1.0.7 Safari/534.11+", "1024x600x1"],
+ ["BlackBerry \u2014 PlayBook 2.0", "Mozilla/5.0 (PlayBook; U; RIM Tablet OS 2.0.0; en-US) AppleWebKit/535.8+ (KHTML, like Gecko) Version/7.2.0.0 Safari/535.8+", "1024x600x1"],
+ ["BlackBerry \u2014 9900", "Mozilla/5.0 (BlackBerry; U; BlackBerry 9900; en-US) AppleWebKit/534.11+ (KHTML, like Gecko) Version/7.0.0.187 Mobile Safari/534.11+", "640x480x1"],
- ["MeeGo \u2014 Nokia N9", "Mozilla/5.0 (MeeGo; NokiaN9) AppleWebKit/534.13 (KHTML, like Gecko) NokiaBrowser/8.5.0 Mobile Safari/534.13"],
+ ["MeeGo \u2014 Nokia N9", "Mozilla/5.0 (MeeGo; NokiaN9) AppleWebKit/534.13 (KHTML, like Gecko) NokiaBrowser/8.5.0 Mobile Safari/534.13", "480x854x1"],
[WebInspector.UIString("Other..."), "Other"]
];
var selectionRestored = false;
for (var i = 0; i < userAgents.length; ++i) {
var agent = userAgents[i];
- selectElement.add(new Option(agent[0], agent[1]));
+ var option = new Option(agent[0], agent[1]);
+ option._metrics = agent[2] ? agent[2] : "";
+ selectElement.add(option);
if (userAgent === agent[1]) {
selectElement.selectedIndex = i;
selectionRestored = true;
selectElement.selectedIndex = userAgents.length - 1;
}
- selectElement.addEventListener("change", selectionChanged.bind(this), false);
+ selectElement.addEventListener("change", selectionChanged.bind(this, true), false);
- function selectionChanged()
+ /**
+ * @param {boolean=} isUserGesture
+ */
+ function selectionChanged(isUserGesture)
{
var value = selectElement.options[selectElement.selectedIndex].value;
if (value !== "Other") {
otherUserAgentElement.disabled = false;
otherUserAgentElement.focus();
}
+
+ if (isUserGesture && Capabilities.canOverrideDeviceMetrics) {
+ var metrics = selectElement.options[selectElement.selectedIndex]._metrics;
+ this._setDeviceMetricsOverride(WebInspector.UserAgentSupport.DeviceMetrics.parseSetting(metrics), false, true);
+ }
}
fieldsetElement.addEventListener("dblclick", textDoubleClicked.bind(this), false);
_showPaintRectsChanged: function()
{
PageAgent.setShowPaintRects(WebInspector.settings.showPaintRects.get());
+ },
+
+ _createDeviceMetricsControl: function()
+ {
+ const metricsSetting = WebInspector.settings.deviceMetrics.get();
+ var metrics = WebInspector.UserAgentSupport.DeviceMetrics.parseSetting(metricsSetting);
+
+ const p = document.createElement("p");
+ const labelElement = p.createChild("label");
+ const checkboxElement = labelElement.createChild("input");
+ checkboxElement.id = "metrics-override-checkbox";
+ checkboxElement.type = "checkbox";
+ checkboxElement.checked = !metrics || (metrics.width && metrics.height && metrics.fontScaleFactor);
+ checkboxElement.addEventListener("click", this._onMetricsCheckboxClicked.bind(this), false);
+ this._metricsCheckboxElement = checkboxElement;
+ labelElement.appendChild(document.createTextNode(WebInspector.UIString("Override device metrics")));
+
+ const metricsSectionElement = this._createDeviceMetricsElement(metrics);
+ p.appendChild(metricsSectionElement);
+ this._metricsSectionElement = metricsSectionElement;
+
+ this._setDeviceMetricsOverride(metrics, false, true);
+
+ return p;
+ },
+
+ _onMetricsCheckboxClicked: function()
+ {
+ if (this._metricsCheckboxElement.checked) {
+ this._metricsSectionElement.removeStyleClass("hidden");
+ var metrics = WebInspector.UserAgentSupport.DeviceMetrics.parseUserInput(this._widthOverrideElement.value, this._heightOverrideElement.value, this._fontScaleFactorOverrideElement.value);
+ if (metrics && metrics.isValid() && metrics.width && metrics.height)
+ this._setDeviceMetricsOverride(metrics, false, false);
+ if (!this._widthOverrideElement.value)
+ this._widthOverrideElement.focus();
+ } else {
+ this._metricsSectionElement.addStyleClass("hidden");
+ if (WebInspector.settings.deviceMetrics.get())
+ WebInspector.settings.deviceMetrics.set("");
+ }
+ },
+
+ _applyDeviceMetricsUserInput: function()
+ {
+ this._setDeviceMetricsOverride(WebInspector.UserAgentSupport.DeviceMetrics.parseUserInput(this._widthOverrideElement.value.trim(), this._heightOverrideElement.value.trim(), this._fontScaleFactorOverrideElement.value.trim()), true, false);
+ },
+
+ /**
+ * @param {?WebInspector.UserAgentSupport.DeviceMetrics} metrics
+ * @param {boolean} userInputModified
+ */
+ _setDeviceMetricsOverride: function(metrics, userInputModified, updateCheckbox)
+ {
+ function setValid(condition, element)
+ {
+ if (condition)
+ element.removeStyleClass("error-input");
+ else
+ element.addStyleClass("error-input");
+ }
+
+ setValid(metrics && metrics.isWidthValid(), this._widthOverrideElement);
+ setValid(metrics && metrics.isHeightValid(), this._heightOverrideElement);
+ setValid(metrics && metrics.isFontScaleFactorValid(), this._fontScaleFactorOverrideElement);
+
+ if (!metrics)
+ return;
+
+ if (!userInputModified) {
+ this._widthOverrideElement.value = metrics.widthToInput();
+ this._heightOverrideElement.value = metrics.heightToInput();
+ this._fontScaleFactorOverrideElement.value = metrics.fontScaleFactorToInput();
+ }
+
+ if (metrics.isValid()) {
+ var value = metrics.toSetting();
+ if (value !== WebInspector.settings.deviceMetrics.get())
+ WebInspector.settings.deviceMetrics.set(value);
+ }
+
+ if (this._metricsCheckboxElement && updateCheckbox) {
+ this._metricsCheckboxElement.checked = !!metrics.toSetting();
+ this._onMetricsCheckboxClicked();
+ }
+ },
+
+ /**
+ * @param {WebInspector.UserAgentSupport.DeviceMetrics} metrics
+ */
+ _createDeviceMetricsElement: function(metrics)
+ {
+ var fieldsetElement = document.createElement("fieldset");
+ fieldsetElement.id = "metrics-override-section";
+
+ function createInput(parentElement, id, defaultText)
+ {
+ var element = parentElement.createChild("input");
+ element.id = id;
+ element.maxLength = 6;
+ element.style.width = "48px";
+ element.value = defaultText;
+ element.addEventListener("blur", this._applyDeviceMetricsUserInput.bind(this), false);
+ return element;
+ }
+
+ var tableElement = fieldsetElement.createChild("table");
+
+ var rowElement = tableElement.createChild("tr");
+ var cellElement = rowElement.createChild("td");
+ cellElement.appendChild(document.createTextNode(WebInspector.UIString("Screen resolution:")));
+ cellElement = rowElement.createChild("td");
+ this._widthOverrideElement = createInput.call(this, cellElement, "metrics-override-width", String(metrics.width || screen.width));
+ cellElement.appendChild(document.createTextNode(" \u00D7 "));
+ this._heightOverrideElement = createInput.call(this, cellElement, "metrics-override-height", String(metrics.height || screen.height));
+
+ rowElement = tableElement.createChild("tr");
+ cellElement = rowElement.createChild("td");
+ cellElement.appendChild(document.createTextNode(WebInspector.UIString("Font scale factor:")));
+ cellElement = rowElement.createChild("td");
+ this._fontScaleFactorOverrideElement = createInput.call(this, cellElement, "metrics-override-font-scale", String(metrics.fontScaleFactor || 1));
+ return fieldsetElement;
}
}
--- /dev/null
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @constructor
+ */
+WebInspector.UserAgentSupport = function()
+{
+ if (WebInspector.settings.deviceMetrics.get())
+ this._deviceMetricsSettingChanged();
+ WebInspector.settings.deviceMetrics.addChangeListener(this._deviceMetricsSettingChanged, this);
+}
+
+/**
+ * @constructor
+ * @param {number} width
+ * @param {number} height
+ * @param {number} fontScaleFactor
+ */
+WebInspector.UserAgentSupport.DeviceMetrics = function(width, height, fontScaleFactor)
+{
+ this.width = width;
+ this.height = height;
+ this.fontScaleFactor = fontScaleFactor;
+}
+
+/**
+ * @return {WebInspector.UserAgentSupport.DeviceMetrics}
+ */
+WebInspector.UserAgentSupport.DeviceMetrics.parseSetting = function(value)
+{
+ if (value) {
+ var splitMetrics = value.split("x");
+ if (splitMetrics.length === 3)
+ return new WebInspector.UserAgentSupport.DeviceMetrics(parseInt(splitMetrics[0], 10), parseInt(splitMetrics[1], 10), parseFloat(splitMetrics[2]));
+ }
+ return new WebInspector.UserAgentSupport.DeviceMetrics(0, 0, 1);
+}
+
+/**
+ * @return {?WebInspector.UserAgentSupport.DeviceMetrics}
+ */
+WebInspector.UserAgentSupport.DeviceMetrics.parseUserInput = function(widthString, heightString, fontScaleFactorString)
+{
+ function isUserInputValid(value, isInteger)
+ {
+ if (!value)
+ return true;
+ return isInteger ? /^[0]*[1-9][\d]*$/.test(value) : /^[0]*([1-9][\d]*(\.\d+)?|\.\d+)$/.test(value);
+ }
+
+ if (!widthString ^ !heightString)
+ return null;
+
+ var isWidthValid = isUserInputValid(widthString, true);
+ var isHeightValid = isUserInputValid(heightString, true);
+ var isFontScaleFactorValid = isUserInputValid(fontScaleFactorString, false);
+
+ if (!isWidthValid && !isHeightValid && !isFontScaleFactorValid)
+ return null;
+
+ var width = isWidthValid ? parseInt(widthString || "0", 10) : -1;
+ var height = isHeightValid ? parseInt(heightString || "0", 10) : -1;
+ var fontScaleFactor = isFontScaleFactorValid ? parseFloat(fontScaleFactorString) : -1;
+
+ return new WebInspector.UserAgentSupport.DeviceMetrics(width, height, fontScaleFactor);
+}
+
+WebInspector.UserAgentSupport.DeviceMetrics.prototype = {
+ /**
+ * @return {boolean}
+ */
+ isValid: function()
+ {
+ return this.isWidthValid() && this.isHeightValid() && this.isFontScaleFactorValid();
+ },
+
+ /**
+ * @return {boolean}
+ */
+ isWidthValid: function()
+ {
+ return this.width >= 0;
+ },
+
+ /**
+ * @return {boolean}
+ */
+ isHeightValid: function()
+ {
+ return this.height >= 0;
+ },
+
+ /**
+ * @return {boolean}
+ */
+ isFontScaleFactorValid: function()
+ {
+ return this.fontScaleFactor > 0;
+ },
+
+ /**
+ * @return {string}
+ */
+ toSetting: function()
+ {
+ if (!this.isValid())
+ return "";
+
+ return this.width && this.height ? this.width + "x" + this.height + "x" + this.fontScaleFactor : "";
+ },
+
+ /**
+ * @return {string}
+ */
+ widthToInput: function()
+ {
+ return this.isWidthValid() && this.width ? String(this.width) : "";
+ },
+
+ /**
+ * @return {string}
+ */
+ heightToInput: function()
+ {
+ return this.isHeightValid() && this.height ? String(this.height) : "";
+ },
+
+ /**
+ * @return {string}
+ */
+ fontScaleFactorToInput: function()
+ {
+ return this.isFontScaleFactorValid() && this.fontScaleFactor ? String(this.fontScaleFactor) : "";
+ }
+}
+
+WebInspector.UserAgentSupport.prototype = {
+ _deviceMetricsSettingChanged: function()
+ {
+ var metrics = WebInspector.UserAgentSupport.DeviceMetrics.parseSetting(WebInspector.settings.deviceMetrics.get());
+ if (metrics.isValid())
+ PageAgent.setDeviceMetricsOverride(metrics.width, metrics.height, metrics.fontScaleFactor);
+ }
+}
\ No newline at end of file