--- a/devtools/client/locales/en-US/responsive.properties
+++ b/devtools/client/locales/en-US/responsive.properties
@@ -64,8 +64,18 @@ responsive.remoteOnly=Responsive Design
# container tab.
responsive.noContainerTabs=Responsive Design Mode is currently unavailable in container tabs.
# LOCALIZATION NOTE (responsive.noThrottling): UI option in a menu to configure
# network throttling. This option is the default and disables throttling so you
# just have normal network conditions. There is not very much room in the UI
# so a short string would be best if possible.
responsive.noThrottling=No throttling
+
+# LOCALIZATION NOTE (responsive.devicePixelRatio): tooltip for the
+# DevicePixelRatio (DPR) dropdown when is enabled.
+responsive.devicePixelRatio=Device Pixel Ratio
+
+# LOCALIZATION NOTE (responsive.autoDPR): tooltip for the DevicePixelRatio
+# (DPR) dropdown when is disabled because a device is selected.
+# The argument (%1$S) is the selected device (e.g. iPhone 6) that set
+# automatically the DPR value.
+responsive.autoDPR=DPR automatically set by %1$S
new file mode 100644
--- /dev/null
+++ b/devtools/client/responsive.html/actions/display-pixel-ratio.js
@@ -0,0 +1,23 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+"use strict";
+
+const { CHANGE_DISPLAY_PIXEL_RATIO } = require("./index");
+
+module.exports = {
+
+ /**
+ * The pixel ratio of the display has changed. This may be triggered by the user
+ * when changing the monitor resolution, or when the window is dragged to a different
+ * display with a different pixel ratio.
+ */
+ changeDisplayPixelRatio(displayPixelRatio) {
+ return {
+ type: CHANGE_DISPLAY_PIXEL_RATIO,
+ displayPixelRatio,
+ };
+ },
+
+};
--- a/devtools/client/responsive.html/actions/index.js
+++ b/devtools/client/responsive.html/actions/index.js
@@ -23,19 +23,29 @@ createEnum([
// Change the device displayed in the viewport.
"CHANGE_DEVICE",
// Change the location of the page. This may be triggered by the user
// directly entering a new URL, navigating with links, etc.
"CHANGE_LOCATION",
+ // The pixel ratio of the display has changed. This may be triggered by the user
+ // when changing the monitor resolution, or when the window is dragged to a different
+ // display with a different pixel ratio.
+ "CHANGE_DISPLAY_PIXEL_RATIO",
+
// Change the network throttling profile.
"CHANGE_NETWORK_THROTTLING",
+ // The pixel ratio of the viewport has changed. This may be triggered by the user
+ // when changing the device displayed in the viewport, or when a pixel ratio is
+ // selected from the DPR dropdown.
+ "CHANGE_VIEWPORT_PIXEL_RATIO",
+
// Indicates that the device list is being loaded
"LOAD_DEVICE_LIST_START",
// Indicates that the device list loading action threw an error
"LOAD_DEVICE_LIST_ERROR",
// Indicates that the device list has been loaded successfully
"LOAD_DEVICE_LIST_END",
--- a/devtools/client/responsive.html/actions/moz.build
+++ b/devtools/client/responsive.html/actions/moz.build
@@ -1,15 +1,16 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DevToolsModules(
'devices.js',
+ 'display-pixel-ratio.js',
'index.js',
'location.js',
'network-throttling.js',
'screenshot.js',
'touch-simulation.js',
'viewports.js',
)
--- a/devtools/client/responsive.html/actions/viewports.js
+++ b/devtools/client/responsive.html/actions/viewports.js
@@ -2,16 +2,17 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const {
ADD_VIEWPORT,
CHANGE_DEVICE,
+ CHANGE_VIEWPORT_PIXEL_RATIO,
RESIZE_VIEWPORT,
ROTATE_VIEWPORT
} = require("./index");
module.exports = {
/**
* Add an additional viewport to display the document.
@@ -29,16 +30,27 @@ module.exports = {
return {
type: CHANGE_DEVICE,
id,
device,
};
},
/**
+ * Change the viewport pixel ratio.
+ */
+ changeViewportPixelRatio(id, pixelRatio = 0) {
+ return {
+ type: CHANGE_VIEWPORT_PIXEL_RATIO,
+ id,
+ pixelRatio,
+ };
+ },
+
+ /**
* Resize the viewport.
*/
resizeViewport(id, width, height) {
return {
type: RESIZE_VIEWPORT,
id,
width,
height,
--- a/devtools/client/responsive.html/app.js
+++ b/devtools/client/responsive.html/app.js
@@ -15,29 +15,31 @@ const {
updateDeviceModalOpen,
updatePreferredDevices,
} = require("./actions/devices");
const { changeNetworkThrottling } = require("./actions/network-throttling");
const { takeScreenshot } = require("./actions/screenshot");
const { updateTouchSimulationEnabled } = require("./actions/touch-simulation");
const {
changeDevice,
+ changeViewportPixelRatio,
resizeViewport,
rotateViewport
} = require("./actions/viewports");
const DeviceModal = createFactory(require("./components/device-modal"));
const GlobalToolbar = createFactory(require("./components/global-toolbar"));
const Viewports = createFactory(require("./components/viewports"));
const Types = require("./types");
let App = createClass({
displayName: "App",
propTypes: {
devices: PropTypes.shape(Types.devices).isRequired,
+ displayPixelRatio: PropTypes.number.isRequired,
location: Types.location.isRequired,
networkThrottling: PropTypes.shape(Types.networkThrottling).isRequired,
screenshot: PropTypes.shape(Types.screenshot).isRequired,
touchSimulation: PropTypes.shape(Types.touchSimulation).isRequired,
viewports: PropTypes.arrayOf(PropTypes.shape(Types.viewport)).isRequired,
},
onBrowserMounted() {
@@ -55,16 +57,26 @@ let App = createClass({
onChangeViewportDevice(id, device) {
window.postMessage({
type: "change-viewport-device",
device,
}, "*");
this.props.dispatch(changeDevice(id, device.name));
this.props.dispatch(updateTouchSimulationEnabled(device.touch));
+ this.props.dispatch(changeViewportPixelRatio(id, device.pixelRatio));
+ },
+
+ onChangeViewportPixelRatio(pixelRatio) {
+ window.postMessage({
+ type: "change-viewport-pixel-ratio",
+ pixelRatio,
+ }, "*");
+
+ this.props.dispatch(changeViewportPixelRatio(0, pixelRatio));
},
onContentResize({ width, height }) {
window.postMessage({
type: "content-resize",
width,
height,
}, "*");
@@ -105,47 +117,62 @@ let App = createClass({
}, "*");
this.props.dispatch(updateTouchSimulationEnabled(isEnabled));
},
render() {
let {
devices,
+ displayPixelRatio,
location,
networkThrottling,
screenshot,
touchSimulation,
viewports,
} = this.props;
let {
onBrowserMounted,
onChangeNetworkThrottling,
onChangeViewportDevice,
+ onChangeViewportPixelRatio,
onContentResize,
onDeviceListUpdate,
onExit,
onResizeViewport,
onRotateViewport,
onScreenshot,
onUpdateDeviceDisplayed,
onUpdateDeviceModalOpen,
onUpdateTouchSimulation,
} = this;
+ let selectedDevice = "";
+ let selectedPixelRatio = 0;
+
+ if (viewports.length) {
+ selectedDevice = viewports[0].device;
+ selectedPixelRatio = viewports[0].pixelRatio;
+ }
+
return dom.div(
{
id: "app",
},
GlobalToolbar({
+ devices,
+ displayPixelRatio,
networkThrottling,
screenshot,
+ selectedDevice,
+ selectedPixelRatio,
touchSimulation,
onChangeNetworkThrottling,
+ onChangeViewportPixelRatio,
onExit,
onScreenshot,
onUpdateTouchSimulation,
}),
Viewports({
devices,
location,
screenshot,
new file mode 100644
--- /dev/null
+++ b/devtools/client/responsive.html/components/dpr-selector.js
@@ -0,0 +1,131 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* eslint-env browser */
+
+"use strict";
+
+const { DOM: dom, createClass, PropTypes, addons } =
+ require("devtools/client/shared/vendor/react");
+
+const Types = require("../types");
+const { getStr, getFormatStr } = require("../utils/l10n");
+
+const PIXEL_RATIO_PRESET = [1, 2, 3];
+
+const createVisibleOption = value =>
+ dom.option({
+ value,
+ title: value,
+ key: value,
+ }, value);
+
+const createHiddenOption = value =>
+ dom.option({
+ value,
+ title: value,
+ hidden: true,
+ disabled: true,
+ }, value);
+
+module.exports = createClass({
+ displayName: "DPRSelector",
+
+ propTypes: {
+ devices: PropTypes.shape(Types.devices).isRequired,
+ displayPixelRatio: PropTypes.number.isRequired,
+ selectedDevice: PropTypes.string.isRequired,
+ selectedPixelRatio: PropTypes.number.isRequired,
+ onChangeViewportPixelRatio: PropTypes.func.isRequired,
+ },
+
+ mixins: [ addons.PureRenderMixin ],
+
+ getInitialState() {
+ return {
+ isFocused: false
+ };
+ },
+
+ onFocusChange({type}) {
+ this.setState({
+ isFocused: type === "focus"
+ });
+ },
+
+ onSelectChange({ target }) {
+ this.props.onChangeViewportPixelRatio(+target.value);
+ },
+
+ render() {
+ let {
+ devices,
+ displayPixelRatio,
+ selectedDevice,
+ selectedPixelRatio,
+ } = this.props;
+
+ let hiddenOptions = [];
+
+ for (let type of devices.types) {
+ for (let device of devices[type]) {
+ if (device.displayed &&
+ !hiddenOptions.includes(device.pixelRatio) &&
+ !PIXEL_RATIO_PRESET.includes(device.pixelRatio)) {
+ hiddenOptions.push(device.pixelRatio);
+ }
+ }
+ }
+
+ if (!PIXEL_RATIO_PRESET.includes(displayPixelRatio)) {
+ hiddenOptions.push(displayPixelRatio);
+ }
+
+ let state = devices.listState;
+ let isDisabled = (state !== Types.deviceListState.LOADED) || (selectedDevice !== "");
+ let selectorClass = "";
+ let title;
+
+ if (isDisabled) {
+ selectorClass += " disabled";
+ title = getFormatStr("responsive.autoDPR", selectedDevice);
+ } else {
+ title = getStr("responsive.devicePixelRatio");
+
+ if (selectedPixelRatio) {
+ selectorClass += " selected";
+ }
+ }
+
+ if (this.state.isFocused) {
+ selectorClass += " focused";
+ }
+
+ let listContent = PIXEL_RATIO_PRESET.map(createVisibleOption);
+
+ if (state == Types.deviceListState.LOADED) {
+ listContent = listContent.concat(hiddenOptions.map(createHiddenOption));
+ }
+
+ return dom.label(
+ {
+ id: "global-dpr-selector",
+ className: selectorClass,
+ title,
+ },
+ "DPR",
+ dom.select(
+ {
+ value: selectedPixelRatio || displayPixelRatio,
+ disabled: isDisabled,
+ onChange: this.onSelectChange,
+ onFocus: this.onFocusChange,
+ onBlur: this.onFocusChange,
+ },
+ ...listContent
+ )
+ );
+ },
+
+});
--- a/devtools/client/responsive.html/components/global-toolbar.js
+++ b/devtools/client/responsive.html/components/global-toolbar.js
@@ -4,39 +4,50 @@
"use strict";
const { DOM: dom, createClass, createFactory, PropTypes, addons } =
require("devtools/client/shared/vendor/react");
const { getStr } = require("../utils/l10n");
const Types = require("../types");
+const DPRSelector = createFactory(require("./dpr-selector"));
const NetworkThrottlingSelector = createFactory(require("./network-throttling-selector"));
module.exports = createClass({
displayName: "GlobalToolbar",
propTypes: {
+ devices: PropTypes.shape(Types.devices).isRequired,
+ displayPixelRatio: PropTypes.number.isRequired,
networkThrottling: PropTypes.shape(Types.networkThrottling).isRequired,
screenshot: PropTypes.shape(Types.screenshot).isRequired,
+ selectedDevice: PropTypes.string.isRequired,
+ selectedPixelRatio: PropTypes.number.isRequired,
touchSimulation: PropTypes.shape(Types.touchSimulation).isRequired,
onChangeNetworkThrottling: PropTypes.func.isRequired,
+ onChangeViewportPixelRatio: PropTypes.func.isRequired,
onExit: PropTypes.func.isRequired,
onScreenshot: PropTypes.func.isRequired,
onUpdateTouchSimulation: PropTypes.func.isRequired,
},
mixins: [ addons.PureRenderMixin ],
render() {
let {
+ devices,
+ displayPixelRatio,
networkThrottling,
screenshot,
+ selectedDevice,
+ selectedPixelRatio,
touchSimulation,
onChangeNetworkThrottling,
+ onChangeViewportPixelRatio,
onExit,
onScreenshot,
onUpdateTouchSimulation
} = this.props;
let touchButtonClass = "toolbar-button devtools-button";
if (touchSimulation.enabled) {
touchButtonClass += " active";
@@ -52,16 +63,23 @@ module.exports = createClass({
className: "title",
},
getStr("responsive.title")
),
NetworkThrottlingSelector({
networkThrottling,
onChangeNetworkThrottling,
}),
+ DPRSelector({
+ devices,
+ displayPixelRatio,
+ selectedDevice,
+ selectedPixelRatio,
+ onChangeViewportPixelRatio,
+ }),
dom.button({
id: "global-touch-simulation-button",
className: touchButtonClass,
title: (touchSimulation.enabled ?
getStr("responsive.disableTouch") : getStr("responsive.enableTouch")),
onClick: () => onUpdateTouchSimulation(!touchSimulation.enabled),
}),
dom.button({
--- a/devtools/client/responsive.html/components/moz.build
+++ b/devtools/client/responsive.html/components/moz.build
@@ -3,16 +3,17 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DevToolsModules(
'browser.js',
'device-modal.js',
'device-selector.js',
+ 'dpr-selector.js',
'global-toolbar.js',
'network-throttling-selector.js',
'resizable-viewport.js',
'viewport-dimension.js',
'viewport-toolbar.js',
'viewport.js',
'viewports.js',
)
--- a/devtools/client/responsive.html/index.css
+++ b/devtools/client/responsive.html/index.css
@@ -81,28 +81,29 @@ select {
-moz-appearance: none;
background-color: var(--theme-toolbar-background);
background-image: var(--viewport-selection-arrow);
background-position: 100% 50%;
background-repeat: no-repeat;
background-size: 7px;
border: none;
color: var(--viewport-color);
+ height: 100%;
padding: 0 8px;
text-align: center;
text-overflow: ellipsis;
font-size: 11px;
}
select.selected {
background-image: var(--viewport-selection-arrow-selected);
color: var(--viewport-active-color);
}
-select:hover {
+select:not(:disabled):hover {
background-image: var(--viewport-selection-arrow-hovered);
color: var(--viewport-hover-color);
}
/* This is (believed to be?) separate from the identical select.selected rule
set so that it overrides select:hover because of file ordering once the
select is focused. It's unclear whether the visual effect that results here
is intentional and desired. */
@@ -183,16 +184,53 @@ select > option.divider {
}
#global-network-throttling-selector {
height: 15px;
padding-left: 0;
width: 103px;
}
+#global-dpr-selector > select {
+ padding: 0 8px 0 0;
+ margin-left: 2px;
+}
+
+#global-dpr-selector {
+ margin: 0 8px;
+ -moz-user-select: none;
+ color: var(--viewport-color);
+ font-size: 11px;
+ height: 15px;
+}
+
+#global-dpr-selector.focused,
+#global-dpr-selector:not(.disabled):hover {
+ color: var(--viewport-hover-color);
+}
+
+#global-dpr-selector:not(.disabled):hover > select {
+ background-image: var(--viewport-selection-arrow-hovered);
+ color: var(--viewport-hover-color);
+}
+
+#global-dpr-selector:focus > select {
+ background-image: var(--viewport-selection-arrow-selected);
+ color: var(--viewport-active-color);
+}
+
+#global-dpr-selector.selected,
+#global-dpr-selector.selected > select {
+ color: var(--viewport-active-color);
+}
+
+#global-dpr-selector > select > option {
+ padding: 5px;
+}
+
#viewports {
/* Make sure left-most viewport is visible when there's horizontal overflow.
That is, when the horizontal space become smaller than the viewports and a
scrollbar appears, then the first viewport will still be visible */
position: sticky;
left: 0;
/* Individual viewports are inline elements, make sure they stay on a single
line */
--- a/devtools/client/responsive.html/index.js
+++ b/devtools/client/responsive.html/index.js
@@ -21,16 +21,17 @@ const { createFactory, createElement } =
require("devtools/client/shared/vendor/react");
const ReactDOM = require("devtools/client/shared/vendor/react-dom");
const { Provider } = require("devtools/client/shared/vendor/react-redux");
const message = require("./utils/message");
const App = createFactory(require("./app"));
const Store = require("./store");
const { changeLocation } = require("./actions/location");
+const { changeDisplayPixelRatio } = require("./actions/display-pixel-ratio");
const { addViewport, resizeViewport } = require("./actions/viewports");
const { loadDevices } = require("./actions/devices");
let bootstrap = {
telemetry: new Telemetry(),
store: null,
@@ -84,22 +85,40 @@ window.addEventListener("unload", functi
window.dispatch = action => bootstrap.dispatch(action);
// Expose the store on window for testing
Object.defineProperty(window, "store", {
get: () => bootstrap.store,
enumerable: true,
});
+// Dispatch a `changeDisplayPixelRatio` action when the browser's pixel ratio is changing.
+// This is usually triggered when the user changes the monitor resolution, or when the
+// browser's window is dragged to a different display with a different pixel ratio.
+function onDPRChange() {
+ let dpr = window.devicePixelRatio;
+ let mql = window.matchMedia(`(resolution: ${dpr}dppx)`);
+
+ function listener() {
+ bootstrap.dispatch(changeDisplayPixelRatio(window.devicePixelRatio));
+ mql.removeListener(listener);
+ onDPRChange();
+ }
+
+ mql.addListener(listener);
+}
+
/**
* Called by manager.js to add the initial viewport based on the original page.
*/
window.addInitialViewport = contentURI => {
try {
+ onDPRChange();
bootstrap.dispatch(changeLocation(contentURI));
+ bootstrap.dispatch(changeDisplayPixelRatio(window.devicePixelRatio));
bootstrap.dispatch(addViewport());
} catch (e) {
console.error(e);
}
};
/**
* Called by manager.js when tests want to check the viewport size.
--- a/devtools/client/responsive.html/manager.js
+++ b/devtools/client/responsive.html/manager.js
@@ -447,16 +447,19 @@ ResponsiveUI.prototype = {
switch (event.data.type) {
case "change-network-throtting":
this.onChangeNetworkThrottling(event);
break;
case "change-viewport-device":
this.onChangeViewportDevice(event);
break;
+ case "change-viewport-pixel-ratio":
+ this.updateDPPX(event.data.pixelRatio);
+ break;
case "content-resize":
this.onContentResize(event);
break;
case "exit":
this.onExit();
break;
case "update-touch-simulation":
this.onUpdateTouchSimulation(event);
--- a/devtools/client/responsive.html/reducers.js
+++ b/devtools/client/responsive.html/reducers.js
@@ -1,12 +1,13 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
exports.devices = require("./reducers/devices");
+exports.displayPixelRatio = require("./reducers/display-pixel-ratio");
exports.location = require("./reducers/location");
exports.networkThrottling = require("./reducers/network-throttling");
exports.screenshot = require("./reducers/screenshot");
exports.touchSimulation = require("./reducers/touch-simulation");
exports.viewports = require("./reducers/viewports");
new file mode 100644
--- /dev/null
+++ b/devtools/client/responsive.html/reducers/display-pixel-ratio.js
@@ -0,0 +1,26 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/* eslint-env browser */
+
+"use strict";
+
+const { CHANGE_DISPLAY_PIXEL_RATIO } = require("../actions/index");
+const INITIAL_DISPLAY_PIXEL_RATIO = 0;
+
+let reducers = {
+
+ [CHANGE_DISPLAY_PIXEL_RATIO](_, action) {
+ return action.displayPixelRatio;
+ },
+
+};
+
+module.exports = function (displayPixelRatio = INITIAL_DISPLAY_PIXEL_RATIO, action) {
+ let reducer = reducers[action.type];
+ if (!reducer) {
+ return displayPixelRatio;
+ }
+ return reducer(displayPixelRatio, action);
+};
--- a/devtools/client/responsive.html/reducers/moz.build
+++ b/devtools/client/responsive.html/reducers/moz.build
@@ -1,14 +1,15 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DevToolsModules(
'devices.js',
+ 'display-pixel-ratio.js',
'location.js',
'network-throttling.js',
'screenshot.js',
'touch-simulation.js',
'viewports.js',
)
--- a/devtools/client/responsive.html/reducers/viewports.js
+++ b/devtools/client/responsive.html/reducers/viewports.js
@@ -2,28 +2,30 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const {
ADD_VIEWPORT,
CHANGE_DEVICE,
+ CHANGE_VIEWPORT_PIXEL_RATIO,
RESIZE_VIEWPORT,
ROTATE_VIEWPORT,
} = require("../actions/index");
let nextViewportId = 0;
const INITIAL_VIEWPORTS = [];
const INITIAL_VIEWPORT = {
id: nextViewportId++,
device: "",
width: 320,
height: 480,
+ pixelRatio: 0,
};
let reducers = {
[ADD_VIEWPORT](viewports) {
// For the moment, there can be at most one viewport.
if (viewports.length === 1) {
return viewports;
@@ -38,16 +40,28 @@ let reducers = {
}
return Object.assign({}, viewport, {
device,
});
});
},
+ [CHANGE_VIEWPORT_PIXEL_RATIO](viewports, {id, pixelRatio }) {
+ return viewports.map(viewport => {
+ if (viewport.id !== id) {
+ return viewport;
+ }
+
+ return Object.assign({}, viewport, {
+ pixelRatio,
+ });
+ });
+ },
+
[RESIZE_VIEWPORT](viewports, { id, width, height }) {
return viewports.map(viewport => {
if (viewport.id !== id) {
return viewport;
}
if (!width) {
width = viewport.width;
--- a/devtools/client/responsive.html/test/browser/browser.ini
+++ b/devtools/client/responsive.html/test/browser/browser.ini
@@ -16,16 +16,17 @@ support-files =
!/devtools/client/shared/test/test-actor.js
!/devtools/client/shared/test/test-actor-registry.js
[browser_device_change.js]
[browser_device_modal_error.js]
[browser_device_modal_exit.js]
[browser_device_modal_submit.js]
[browser_device_width.js]
+[browser_dpr_change.js]
[browser_exit_button.js]
[browser_frame_script_active.js]
[browser_menu_item_01.js]
[browser_menu_item_02.js]
[browser_mouse_resize.js]
[browser_navigation.js]
[browser_network_throttling.js]
[browser_page_state.js]
--- a/devtools/client/responsive.html/test/browser/browser_device_change.js
+++ b/devtools/client/responsive.html/test/browser/browser_device_change.js
@@ -38,34 +38,34 @@ addRDMTask(TEST_URL, function* ({ ui, ma
// Test defaults
testViewportDimensions(ui, 320, 480);
yield testUserAgent(ui, DEFAULT_UA);
yield testDevicePixelRatio(ui, DEFAULT_DPPX);
yield testTouchEventsOverride(ui, false);
testViewportSelectLabel(ui, "no device selected");
// Test device with custom properties
- yield switchDevice(ui, "Fake Phone RDM Test");
+ yield selectDevice(ui, "Fake Phone RDM Test");
yield waitForViewportResizeTo(ui, testDevice.width, testDevice.height);
yield testUserAgent(ui, testDevice.userAgent);
yield testDevicePixelRatio(ui, testDevice.pixelRatio);
yield testTouchEventsOverride(ui, true);
// Test resetting device when resizing viewport
let deviceChanged = once(ui, "viewport-device-changed");
yield testViewportResize(ui, ".viewport-vertical-resize-handle",
[-10, -10], [testDevice.width, testDevice.height - 10], [0, -10], ui);
yield deviceChanged;
yield testUserAgent(ui, DEFAULT_UA);
yield testDevicePixelRatio(ui, DEFAULT_DPPX);
yield testTouchEventsOverride(ui, false);
testViewportSelectLabel(ui, "no device selected");
// Test device with generic properties
- yield switchDevice(ui, "Laptop (1366 x 768)");
+ yield selectDevice(ui, "Laptop (1366 x 768)");
yield waitForViewportResizeTo(ui, 1366, 768);
yield testUserAgent(ui, DEFAULT_UA);
yield testDevicePixelRatio(ui, 1);
yield testTouchEventsOverride(ui, false);
});
function testViewportDimensions(ui, w, h) {
let viewport = ui.toolWindow.document.querySelector(".viewport-content");
new file mode 100644
--- /dev/null
+++ b/devtools/client/responsive.html/test/browser/browser_dpr_change.js
@@ -0,0 +1,146 @@
+/* Any copyright is dedicated to the Public Domain.
+http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Tests changing viewport device
+const TEST_URL = "data:text/html;charset=utf-8,DPR list test";
+const DEFAULT_DPPX = window.devicePixelRatio;
+const VIEWPORT_DPPX = DEFAULT_DPPX + 2;
+const Types = require("devtools/client/responsive.html/types");
+
+const testDevice = {
+ "name": "Fake Phone RDM Test",
+ "width": 320,
+ "height": 470,
+ "pixelRatio": 5.5,
+ "userAgent": "Mozilla/5.0 (Mobile; rv:39.0) Gecko/39.0 Firefox/39.0",
+ "touch": true,
+ "firefoxOS": true,
+ "os": "custom",
+ "featured": true,
+};
+
+// Add the new device to the list
+addDeviceForTest(testDevice);
+
+addRDMTask(TEST_URL, function* ({ ui, manager }) {
+ yield waitStartup(ui);
+
+ yield testDefaults(ui);
+ yield testChangingDevice(ui);
+ yield testResetWhenResizingViewport(ui);
+ yield testChangingDPR(ui);
+});
+
+function* waitStartup(ui) {
+ let { store } = ui.toolWindow;
+
+ // Wait until the viewport has been added and the device list has been loaded
+ yield waitUntilState(store, state => state.viewports.length == 1
+ && state.devices.listState == Types.deviceListState.LOADED);
+}
+
+function* testDefaults(ui) {
+ info("Test Defaults");
+
+ yield testDevicePixelRatio(ui, window.devicePixelRatio);
+ testViewportDPRSelect(ui, {value: window.devicePixelRatio, disabled: false});
+ testViewportDeviceSelectLabel(ui, "no device selected");
+}
+
+function* testChangingDevice(ui) {
+ info("Test Changing Device");
+
+ let waitPixelRatioChange = onceDevicePixelRatioChange(ui);
+
+ yield selectDevice(ui, testDevice.name);
+ yield waitForViewportResizeTo(ui, testDevice.width, testDevice.height);
+ yield waitPixelRatioChange;
+ yield testDevicePixelRatio(ui, testDevice.pixelRatio);
+ testViewportDPRSelect(ui, {value: testDevice.pixelRatio, disabled: true});
+ testViewportDeviceSelectLabel(ui, testDevice.name);
+}
+
+function* testResetWhenResizingViewport(ui) {
+ info("Test reset when resizing the viewport");
+
+ let waitPixelRatioChange = onceDevicePixelRatioChange(ui);
+
+ yield testViewportResize(ui, ".viewport-vertical-resize-handle",
+ [-10, -10], [testDevice.width, testDevice.height - 10], [0, -10], ui);
+
+ yield waitPixelRatioChange;
+ yield testDevicePixelRatio(ui, window.devicePixelRatio);
+
+ testViewportDPRSelect(ui, {value: window.devicePixelRatio, disabled: false});
+ testViewportDeviceSelectLabel(ui, "no device selected");
+}
+
+function* testChangingDPR(ui) {
+ info("Test changing device pixel ratio");
+
+ let waitPixelRatioChange = onceDevicePixelRatioChange(ui);
+
+ yield selectDPR(ui, VIEWPORT_DPPX);
+ yield waitPixelRatioChange;
+ yield testDevicePixelRatio(ui, VIEWPORT_DPPX);
+ testViewportDPRSelect(ui, {value: VIEWPORT_DPPX, disabled: false});
+ testViewportDeviceSelectLabel(ui, "no device selected");
+}
+
+function testViewportDPRSelect(ui, expected) {
+ info("Test viewport's DPR Select");
+
+ let select = ui.toolWindow.document.querySelector("#global-dpr-selector > select");
+ is(select.value, expected.value,
+ `DPR Select value should be: ${expected.value}`);
+ is(select.disabled, expected.disabled,
+ `DPR Select should be ${expected.disabled ? "disabled" : "enabled"}.`);
+}
+
+function testViewportDeviceSelectLabel(ui, expected) {
+ info("Test viewport's device select label");
+
+ let select = ui.toolWindow.document.querySelector(".viewport-device-selector");
+ is(select.selectedOptions[0].textContent, expected,
+ `Device Select value should be: ${expected}`);
+}
+
+function* testDevicePixelRatio(ui, expected) {
+ info("Test device pixel ratio");
+
+ let dppx = yield getViewportDevicePixelRatio(ui);
+ is(dppx, expected, `devicePixelRatio should be: ${expected}`);
+}
+
+function* getViewportDevicePixelRatio(ui) {
+ return yield ContentTask.spawn(ui.getViewportBrowser(), {}, function* () {
+ return content.devicePixelRatio;
+ });
+}
+
+function onceDevicePixelRatioChange(ui) {
+ return ContentTask.spawn(ui.getViewportBrowser(), {}, function* () {
+ info(`Listening for a pixel ratio change (current: ${content.devicePixelRatio}dppx)`);
+
+ let pixelRatio = content.devicePixelRatio;
+ let mql = content.matchMedia(`(resolution: ${pixelRatio}dppx)`);
+
+ return new Promise(resolve => {
+ const onWindowCreated = () => {
+ if (pixelRatio !== content.devicePixelRatio) {
+ resolve();
+ }
+ };
+
+ addEventListener("DOMWindowCreated", onWindowCreated, {once: true});
+
+ mql.addListener(function listener() {
+ mql.removeListener(listener);
+ removeEventListener("DOMWindowCreated", onWindowCreated, {once: true});
+ resolve();
+ });
+ });
+ });
+}
--- a/devtools/client/responsive.html/test/browser/browser_network_throttling.js
+++ b/devtools/client/responsive.html/test/browser/browser_network_throttling.js
@@ -20,17 +20,17 @@ addRDMTask(TEST_URL, function* ({ ui, ma
// Test a fast profile
yield testThrottlingProfile(ui, "Wi-Fi");
// Test a slower profile
yield testThrottlingProfile(ui, "Regular 3G");
// Test switching back to no throttling
- yield switchNetworkThrottling(ui, "No throttling");
+ yield selectNetworkThrottling(ui, "No throttling");
testNetworkThrottlingSelectorLabel(ui, "No throttling");
yield testNetworkThrottlingState(ui, null);
});
function testNetworkThrottlingSelectorLabel(ui, expected) {
let selector = "#global-network-throttling-selector";
let select = ui.toolWindow.document.querySelector(selector);
is(select.selectedOptions[0].textContent, expected,
@@ -39,17 +39,17 @@ function testNetworkThrottlingSelectorLa
var testNetworkThrottlingState = Task.async(function* (ui, expected) {
let state = yield ui.emulationFront.getNetworkThrottling();
Assert.deepEqual(state, expected, "Network throttling state should be " +
JSON.stringify(expected, null, 2));
});
var testThrottlingProfile = Task.async(function* (ui, profile) {
- yield switchNetworkThrottling(ui, profile);
+ yield selectNetworkThrottling(ui, profile);
testNetworkThrottlingSelectorLabel(ui, profile);
let data = throttlingProfiles.find(({ id }) => id == profile);
let { download, upload, latency } = data;
yield testNetworkThrottlingState(ui, {
downloadThroughput: download,
uploadThroughput: upload,
latency,
});
--- a/devtools/client/responsive.html/test/browser/head.js
+++ b/devtools/client/responsive.html/test/browser/head.js
@@ -206,39 +206,43 @@ function* testViewportResize(ui, selecto
let endRect = getElRect(selector, win);
is(endRect.left - startRect.left, expectedHandleMove[0],
`The x move of ${selector} is as expected`);
is(endRect.top - startRect.top, expectedHandleMove[1],
`The y move of ${selector} is as expected`);
}
-function openDeviceModal(ui) {
- let { document } = ui.toolWindow;
+function openDeviceModal({toolWindow}) {
+ let { document } = toolWindow;
let select = document.querySelector(".viewport-device-selector");
let modal = document.querySelector("#device-modal-wrapper");
- let editDeviceOption = [...select.options].filter(o => {
- return o.value === OPEN_DEVICE_MODAL_VALUE;
- })[0];
info("Checking initial device modal state");
ok(modal.classList.contains("closed") && !modal.classList.contains("opened"),
"The device modal is closed by default.");
info("Opening device modal through device selector.");
- EventUtils.synthesizeMouseAtCenter(select, {type: "mousedown"},
- ui.toolWindow);
- EventUtils.synthesizeMouseAtCenter(editDeviceOption, {type: "mouseup"},
- ui.toolWindow);
+
+ let event = new toolWindow.UIEvent("change", {
+ view: toolWindow,
+ bubbles: true,
+ cancelable: true
+ });
+
+ select.value = OPEN_DEVICE_MODAL_VALUE;
+ select.dispatchEvent(event);
ok(modal.classList.contains("opened") && !modal.classList.contains("closed"),
"The device modal is displayed.");
}
-function switchSelector({ toolWindow }, selector, value) {
+function changeSelectValue({ toolWindow }, selector, value) {
+ info(`Selecting ${value} in ${selector}.`);
+
return new Promise(resolve => {
let select = toolWindow.document.querySelector(selector);
isnot(select, null, `selector "${selector}" should match an existing element.`);
let option = [...select.options].find(o => o.value === String(value));
isnot(option, undefined, `value "${value}" should match an existing option.`);
let event = new toolWindow.UIEvent("change", {
@@ -253,27 +257,28 @@ function switchSelector({ toolWindow },
resolve();
}, { once: true });
select.value = value;
select.dispatchEvent(event);
});
}
-let switchDevice = Task.async(function* (ui, value) {
- let changed = once(ui, "viewport-device-changed");
- yield switchSelector(ui, ".viewport-device-selector", value);
- yield changed;
-});
+const selectDevice = (ui, value) => Promise.all([
+ once(ui, "viewport-device-changed"),
+ changeSelectValue(ui, ".viewport-device-selector", value)
+]);
-let switchNetworkThrottling = Task.async(function* (ui, value) {
- let changed = once(ui, "network-throttling-changed");
- yield switchSelector(ui, "#global-network-throttling-selector", value);
- yield changed;
-});
+const selectDPR = (ui, value) =>
+ changeSelectValue(ui, "#global-dpr-selector > select", value);
+
+const selectNetworkThrottling = (ui, value) => Promise.all([
+ once(ui, "network-throttling-changed"),
+ changeSelectValue(ui, "#global-network-throttling-selector", value)
+]);
function getSessionHistory(browser) {
return ContentTask.spawn(browser, {}, function* () {
/* eslint-disable no-undef */
let { interfaces: Ci } = Components;
let webNav = docShell.QueryInterface(Ci.nsIWebNavigation);
let sessionHistory = webNav.sessionHistory;
let result = {
new file mode 100644
--- /dev/null
+++ b/devtools/client/responsive.html/test/unit/test_change_display_pixel_ratio.js
@@ -0,0 +1,22 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test changing the display pixel ratio.
+
+const { changeDisplayPixelRatio } =
+ require("devtools/client/responsive.html/actions/display-pixel-ratio");
+const NEW_PIXEL_RATIO = 5.5;
+
+add_task(function* () {
+ let store = Store();
+ const { getState, dispatch } = store;
+
+ equal(getState().displayPixelRatio, 0,
+ "Defaults to 0 at startup");
+
+ dispatch(changeDisplayPixelRatio(NEW_PIXEL_RATIO));
+ equal(getState().displayPixelRatio, NEW_PIXEL_RATIO,
+ `Display Pixel Ratio changed to ${NEW_PIXEL_RATIO}`);
+});
new file mode 100644
--- /dev/null
+++ b/devtools/client/responsive.html/test/unit/test_change_viewport_pixel_ratio.js
@@ -0,0 +1,22 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test changing the viewport pixel ratio.
+
+const { addViewport, changeViewportPixelRatio } =
+ require("devtools/client/responsive.html/actions/viewports");
+const NEW_PIXEL_RATIO = 5.5;
+
+add_task(function* () {
+ let store = Store();
+ const { getState, dispatch } = store;
+
+ dispatch(addViewport());
+ dispatch(changeViewportPixelRatio(0, NEW_PIXEL_RATIO));
+
+ let viewport = getState().viewports[0];
+ equal(viewport.pixelRatio, NEW_PIXEL_RATIO,
+ `Viewport's pixel ratio changed to ${NEW_PIXEL_RATIO}`);
+});
--- a/devtools/client/responsive.html/test/unit/xpcshell.ini
+++ b/devtools/client/responsive.html/test/unit/xpcshell.ini
@@ -2,15 +2,17 @@
tags = devtools
head = head.js ../../../framework/test/shared-redux-head.js
tail =
firefox-appdir = browser
[test_add_device.js]
[test_add_device_type.js]
[test_add_viewport.js]
+[test_change_display_pixel_ratio.js]
[test_change_location.js]
[test_change_network_throttling.js]
[test_change_viewport_device.js]
+[test_change_viewport_pixel_ratio.js]
[test_resize_viewport.js]
[test_rotate_viewport.js]
[test_update_device_displayed.js]
[test_update_touch_simulation_enabled.js]