Bug 1241720 - Modal to promote devices from larger DB r=jyrans

This commit is contained in:
Gabriel Luong
2016-04-20 17:15:34 -04:00
parent 9673789d6e
commit 993bf105f2
29 changed files with 1255 additions and 52 deletions

View File

@@ -142,7 +142,7 @@
.theme-dark .tabs .tabs-menu-item:hover,
.theme-light .tabs .tabs-menu-item:hover {
background-color: rgba(170,170,170,.2);
background-color: var(--toolbar-tab-hover);
}
.theme-dark .tabs .tabs-menu-item.is-active,
@@ -161,7 +161,7 @@
.theme-dark .tabs .tabs-menu-item:active:hover,
.theme-light .tabs .tabs-menu-item:active:hover {
background-color: rgba(170,170,170,.4);
background-color: var(--toolbar-tab-hover-active);
}
.theme-dark .tabs .tabs-menu-item.is-active,
@@ -190,7 +190,7 @@
}
.theme-dark .tabs .tabs-menu-item:active:hover {
background-color: hsla(206,37%,4%,.4);
background-color: hsla(206, 37%, 4%, .4); /* --toolbar-tab-hover-active */
}
.theme-dark .tabs .tabs-menu-item.is-active {

View File

@@ -79,7 +79,7 @@
margin: 1px 2px 1px 2px;
border: none;
border-radius: 0;
background-color: rgba(170, 170, 170, .2); /* Splitter */
background-color: rgba(170, 170, 170, .2); /* --toolbar-tab-hover */
transition: background 0.05s ease-in-out;
}
@@ -90,5 +90,5 @@
.theme-dark .toolbar .btn:not([disabled]):hover:active,
.theme-light .toolbar .btn:not([disabled]):hover:active {
background: rgba(170, 170, 170, .4); /* Splitters */
background: rgba(170, 170, 170, .4); /* --toolbar-tab-hover-active */
}

View File

@@ -11,17 +11,24 @@
# A good criteria is the language in which you'd find the best
# documentation on web development on the web.
# LOCALIZATION NOTE (responsive.title): the title displayed in the global
# toolbar
responsive.title=Responsive Design Mode
# LOCALIZATION NOTE (responsive.editDeviceList): option displayed in the device
# selector
responsive.editDeviceList=Edit list…
# LOCALIZATION NOTE (responsive.exit): tooltip text of the exit button.
responsive.exit=Close Responsive Design Mode
# LOCALIZATION NOTE (responsive.done): button text in the device list modal
responsive.done=Done
# LOCALIZATION NOTE (responsive.noDeviceSelected): placeholder text for the
# device selector
responsive.noDeviceSelected=no device selected
# LOCALIZATION NOTE (responsive.title): the title displayed in the global
# toolbar
responsive.title=Responsive Design Mode
# LOCALIZATION NOTE (responsive.screenshot): tooltip of the screenshot button.
responsive.screenshot=Take a screenshot of the viewport

View File

@@ -7,6 +7,8 @@
const {
ADD_DEVICE,
ADD_DEVICE_TYPE,
UPDATE_DEVICE_DISPLAYED,
UPDATE_DEVICE_MODAL_OPEN,
} = require("./index");
module.exports = {
@@ -26,4 +28,20 @@ module.exports = {
};
},
updateDeviceDisplayed(device, deviceType, displayed) {
return {
type: UPDATE_DEVICE_DISPLAYED,
device,
deviceType,
displayed,
};
},
updateDeviceModalOpen(isOpen) {
return {
type: UPDATE_DEVICE_MODAL_OPEN,
isOpen,
};
},
};

View File

@@ -38,6 +38,12 @@ createEnum([
// Indicates when the screenshot action ends.
"TAKE_SCREENSHOT_END",
// Update the device display state in the device selector.
"UPDATE_DEVICE_DISPLAYED",
// Update the device modal open state.
"UPDATE_DEVICE_MODAL_OPEN",
], module.exports);
/**

View File

@@ -10,15 +10,21 @@ const { createClass, createFactory, PropTypes, DOM: dom } =
require("devtools/client/shared/vendor/react");
const { connect } = require("devtools/client/shared/vendor/react-redux");
const {
updateDeviceDisplayed,
updateDeviceModalOpen,
} = require("./actions/devices");
const {
changeDevice,
resizeViewport,
rotateViewport
} = require("./actions/viewports");
const { takeScreenshot } = require("./actions/screenshot");
const Types = require("./types");
const Viewports = createFactory(require("./components/viewports"));
const DeviceModal = createFactory(require("./components/device-modal"));
const GlobalToolbar = createFactory(require("./components/global-toolbar"));
const Viewports = createFactory(require("./components/viewports"));
const { updateDeviceList } = require("./devices");
const Types = require("./types");
let App = createClass({
propTypes: {
@@ -46,6 +52,10 @@ let App = createClass({
}, "*");
},
onDeviceListUpdate(devices) {
updateDeviceList(devices);
},
onExit() {
window.postMessage({ type: "exit" }, "*");
},
@@ -62,6 +72,14 @@ let App = createClass({
this.props.dispatch(takeScreenshot());
},
onUpdateDeviceDisplayed(device, deviceType, displayed) {
this.props.dispatch(updateDeviceDisplayed(device, deviceType, displayed));
},
onUpdateDeviceModalOpen(isOpen) {
this.props.dispatch(updateDeviceModalOpen(isOpen));
},
render() {
let {
devices,
@@ -74,10 +92,13 @@ let App = createClass({
onBrowserMounted,
onChangeViewportDevice,
onContentResize,
onDeviceListUpdate,
onExit,
onResizeViewport,
onRotateViewport,
onScreenshot,
onUpdateDeviceDisplayed,
onUpdateDeviceModalOpen,
} = this;
return dom.div(
@@ -99,6 +120,13 @@ let App = createClass({
onContentResize,
onRotateViewport,
onResizeViewport,
onUpdateDeviceModalOpen,
}),
DeviceModal({
devices,
onDeviceListUpdate,
onUpdateDeviceDisplayed,
onUpdateDeviceModalOpen,
})
);
},

View File

@@ -0,0 +1,139 @@
/* 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 { DOM: dom, createClass, PropTypes, addons } =
require("devtools/client/shared/vendor/react");
const { getStr } = require("../utils/l10n");
const Types = require("../types");
module.exports = createClass({
propTypes: {
devices: PropTypes.shape(Types.devices).isRequired,
onDeviceListUpdate: PropTypes.func.isRequired,
onUpdateDeviceDisplayed: PropTypes.func.isRequired,
onUpdateDeviceModalOpen: PropTypes.func.isRequired,
},
displayName: "DeviceModal",
mixins: [ addons.PureRenderMixin ],
getInitialState() {
return {};
},
componentWillReceiveProps(nextProps) {
let {
devices,
} = nextProps;
for (let type of devices.types) {
for (let device of devices[type]) {
this.setState({
[device.name]: device.displayed,
});
}
}
},
onDeviceCheckboxClick({ target }) {
this.setState({
[target.value]: !this.state[target.value]
});
},
onDeviceModalSubmit() {
let {
devices,
onDeviceListUpdate,
onUpdateDeviceDisplayed,
onUpdateDeviceModalOpen,
} = this.props;
let displayedDeviceList = [];
for (let type of devices.types) {
for (let device of devices[type]) {
if (this.state[device.name] != device.displayed) {
onUpdateDeviceDisplayed(device, type, this.state[device.name]);
}
if (this.state[device.name]) {
displayedDeviceList.push(device.name);
}
}
}
onDeviceListUpdate(displayedDeviceList);
onUpdateDeviceModalOpen(false);
},
render() {
let {
devices,
onUpdateDeviceModalOpen,
} = this.props;
let modalClass = "device-modal container";
if (!devices.isModalOpen) {
modalClass += " hidden";
}
return dom.div(
{
className: modalClass,
},
dom.button({
id: "device-close-button",
className: "toolbar-button devtools-button",
onClick: () => onUpdateDeviceModalOpen(false),
}),
dom.div(
{
className: "device-modal-content",
},
devices.types.map(type => {
return dom.div(
{
className: "device-type",
key: type,
},
dom.header(
{
className: "device-header",
},
type
),
devices[type].map(device => {
return dom.label(
{
className: "device-label",
key: device.name,
},
dom.input({
className: "device-input-checkbox",
type: "checkbox",
value: device.name,
checked: this.state[device.name],
onChange: this.onDeviceCheckboxClick,
}),
device.name
);
})
);
})
),
dom.button(
{
id: "device-submit-button",
onClick: this.onDeviceModalSubmit,
},
getStr("responsive.done")
)
);
},
});

View File

@@ -9,6 +9,7 @@ const { DOM: dom, createClass, PropTypes, addons } =
require("devtools/client/shared/vendor/react");
const Types = require("../types");
const OPEN_DEVICE_MODAL_VALUE = "OPEN_DEVICE_MODAL";
module.exports = createClass({
propTypes: {
@@ -16,6 +17,7 @@ module.exports = createClass({
selectedDevice: PropTypes.string.isRequired,
onChangeViewportDevice: PropTypes.func.isRequired,
onResizeViewport: PropTypes.func.isRequired,
onUpdateDeviceModalOpen: PropTypes.func.isRequired,
},
displayName: "DeviceSelector",
@@ -27,8 +29,14 @@ module.exports = createClass({
devices,
onChangeViewportDevice,
onResizeViewport,
onUpdateDeviceModalOpen,
} = this.props;
if (target.value === OPEN_DEVICE_MODAL_VALUE) {
onUpdateDeviceModalOpen(true);
return;
}
for (let type of devices.types) {
for (let device of devices[type]) {
if (device.name === target.value) {
@@ -50,7 +58,9 @@ module.exports = createClass({
let options = [];
for (let type of devices.types) {
for (let device of devices[type]) {
options.push(device);
if (device.displayed) {
options.push(device);
}
}
}
@@ -75,7 +85,10 @@ module.exports = createClass({
key: device.name,
value: device.name,
}, device.name);
})
}),
dom.option({
value: OPEN_DEVICE_MODAL_VALUE,
}, getStr("responsive.editDeviceList"))
);
},

View File

@@ -30,7 +30,7 @@ module.exports = createClass({
return dom.header(
{
id: "global-toolbar",
className: "toolbar",
className: "container",
},
dom.span(
{

View File

@@ -6,6 +6,7 @@
DevToolsModules(
'browser.js',
'device-modal.js',
'device-selector.js',
'global-toolbar.js',
'resizable-viewport.js',

View File

@@ -28,6 +28,7 @@ module.exports = createClass({
onContentResize: PropTypes.func.isRequired,
onResizeViewport: PropTypes.func.isRequired,
onRotateViewport: PropTypes.func.isRequired,
onUpdateDeviceModalOpen: PropTypes.func.isRequired,
},
displayName: "ResizableViewport",
@@ -123,6 +124,7 @@ module.exports = createClass({
onContentResize,
onResizeViewport,
onRotateViewport,
onUpdateDeviceModalOpen,
} = this.props;
let resizeHandleClass = "viewport-resize-handle";
@@ -145,6 +147,7 @@ module.exports = createClass({
onChangeViewportDevice,
onResizeViewport,
onRotateViewport,
onUpdateDeviceModalOpen,
}),
dom.div(
{

View File

@@ -17,6 +17,7 @@ module.exports = createClass({
onChangeViewportDevice: PropTypes.func.isRequired,
onResizeViewport: PropTypes.func.isRequired,
onRotateViewport: PropTypes.func.isRequired,
onUpdateDeviceModalOpen: PropTypes.func.isRequired,
},
displayName: "ViewportToolbar",
@@ -30,17 +31,19 @@ module.exports = createClass({
onChangeViewportDevice,
onResizeViewport,
onRotateViewport,
onUpdateDeviceModalOpen,
} = this.props;
return dom.div(
{
className: "toolbar viewport-toolbar",
className: "viewport-toolbar container",
},
DeviceSelector({
devices,
selectedDevice,
onChangeViewportDevice,
onResizeViewport,
onUpdateDeviceModalOpen,
}),
dom.button({
className: "viewport-rotate-button toolbar-button devtools-button",

View File

@@ -22,6 +22,7 @@ module.exports = createClass({
onContentResize: PropTypes.func.isRequired,
onResizeViewport: PropTypes.func.isRequired,
onRotateViewport: PropTypes.func.isRequired,
onUpdateDeviceModalOpen: PropTypes.func.isRequired,
},
displayName: "Viewport",
@@ -59,8 +60,9 @@ module.exports = createClass({
location,
screenshot,
viewport,
onContentResize,
onBrowserMounted,
onContentResize,
onUpdateDeviceModalOpen,
} = this.props;
let {
@@ -83,6 +85,7 @@ module.exports = createClass({
onContentResize,
onResizeViewport,
onRotateViewport,
onUpdateDeviceModalOpen,
}),
ViewportDimension({
viewport,

View File

@@ -21,6 +21,7 @@ module.exports = createClass({
onContentResize: PropTypes.func.isRequired,
onResizeViewport: PropTypes.func.isRequired,
onRotateViewport: PropTypes.func.isRequired,
onUpdateDeviceModalOpen: PropTypes.func.isRequired,
},
displayName: "Viewports",
@@ -36,6 +37,7 @@ module.exports = createClass({
onContentResize,
onResizeViewport,
onRotateViewport,
onUpdateDeviceModalOpen,
} = this.props;
return dom.div(
@@ -54,6 +56,7 @@ module.exports = createClass({
onContentResize,
onResizeViewport,
onRotateViewport,
onUpdateDeviceModalOpen,
});
})
);

View File

@@ -0,0 +1,81 @@
/* 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 Services = require("Services");
const { Task } = require("resource://gre/modules/Task.jsm");
const { GetDevices } = require("devtools/client/shared/devices");
const { addDevice, addDeviceType } = require("./actions/devices");
const DISPLAYED_DEVICES_PREF = "devtools.responsive.html.displayedDeviceList";
/**
* Get the device catalog and load the devices onto the store.
*
* @param {Function} dispatch
* Action dispatch function
*/
let initDevices = Task.async(function*(dispatch) {
let deviceList = loadDeviceList();
let devices = yield GetDevices();
for (let type of devices.TYPES) {
dispatch(addDeviceType(type));
for (let device of devices[type]) {
if (device.os == "fxos") {
continue;
}
let newDevice = Object.assign({}, device, {
displayed: deviceList.includes(device.name) ?
true :
!!device.featured,
});
if (newDevice.displayed) {
deviceList.push(newDevice.name);
}
dispatch(addDevice(newDevice, type));
}
}
updateDeviceList(deviceList);
});
/**
* Returns an array containing the user preference of displayed devices.
*
* @return {Array} containing the device names that are to be displayed in the
* device catalog.
*/
function loadDeviceList() {
let deviceList = [];
if (Services.prefs.prefHasUserValue(DISPLAYED_DEVICES_PREF)) {
try {
deviceList = JSON.parse(Services.prefs.getCharPref(
DISPLAYED_DEVICES_PREF));
} catch (e) {
console.error(e);
}
}
return deviceList;
}
/**
* Update the displayed device list preference with the given device list.
*
* @param {Array} devices
* Array of device names that are displayed in the device catalog.
*/
function updateDeviceList(devices) {
Services.prefs.setCharPref(DISPLAYED_DEVICES_PREF, JSON.stringify(devices));
}
exports.initDevices = initDevices;
exports.loadDeviceList = loadDeviceList;
exports.updateDeviceList = updateDeviceList;

View File

@@ -6,7 +6,9 @@
*/
.theme-light {
--box-shadow: 0 4px 4px 0 rgba(155, 155, 155, 0.26);
--rdm-box-shadow: 0 4px 4px 0 rgba(155, 155, 155, 0.26);
--submit-button-active-background-color: rgba(0,0,0,0.12);
--submit-button-active-color: var(--theme-body-color);
--viewport-active-color: var(--theme-body-color);
--viewport-selection-arrow: url("./images/select-arrow.svg#light");
--viewport-selection-arrow-selected:
@@ -14,7 +16,9 @@
}
.theme-dark {
--box-shadow: 0 4px 4px 0 rgba(105, 105, 105, 0.26);
--rdm-box-shadow: 0 4px 4px 0 rgba(105, 105, 105, 0.26);
--submit-button-active-background-color: var(--toolbar-tab-hover-active);
--submit-button-active-color: var(--theme-selection-color);
--viewport-active-color: var(--theme-selection-color);
--viewport-selection-arrow: url("./images/select-arrow.svg#dark");
--viewport-selection-arrow-selected:
@@ -51,10 +55,10 @@ html, body {
}
/**
* Common style for toolbars and toolbar buttons
* Common style for containers and toolbar buttons
*/
.toolbar {
.container {
background-color: var(--theme-toolbar-background);
border: 1px solid var(--theme-splitter-color);
}
@@ -80,7 +84,7 @@ html, body {
#global-toolbar {
color: var(--theme-body-color-alt);
border-radius: 2px;
box-shadow: var(--box-shadow);
box-shadow: var(--rdm-box-shadow);
margin: 30px 0;
padding: 4px 5px;
display: inline-flex;
@@ -142,7 +146,7 @@ html, body {
.resizable-viewport {
border: 1px solid var(--theme-splitter-color);
box-shadow: var(--box-shadow);
box-shadow: var(--rdm-box-shadow);
position: relative;
}
@@ -308,3 +312,88 @@ html, body {
.viewport-dimension-separator {
-moz-user-select: none;
}
/**
* Device Modal
*/
.device-modal {
border-radius: 2px;
box-shadow: var(--rdm-box-shadow);
position: absolute;
margin: auto;
top: 0;
bottom: 0;
left: 0;
right: 0;
width: 642px;
height: 612px;
}
.device-modal.hidden {
display: none;
}
.device-modal-content {
display: flex;
flex-direction: column;
flex-wrap: wrap;
overflow: auto;
height: 550px;
width: 600px;
margin: 20px;
}
#device-close-button,
#device-close-button::before {
position: absolute;
top: 5px;
right: 2px;
width: 12px;
height: 12px;
}
#device-close-button::before {
background-image: url("./images/close.svg");
margin: -6px 0 0 -6px;
}
.device-type {
display: flex;
flex-direction: column;
padding: 10px;
}
.device-header {
font-weight: bold;
text-transform: capitalize;
padding: 0 0 3px 23px;
}
.device-label {
padding-bottom: 3px;
}
.device-input-checkbox {
margin-right: 5px;
}
#device-submit-button {
background-color: var(--theme-tab-toolbar-background);
border-width: 1px 0 0 0;
border-top-width: 1px;
border-top-style: solid;
border-top-color: var(--theme-splitter-color);
color: var(--theme-body-color);
width: 100%;
height: 20px;
}
#device-submit-button:hover {
background-color: var(--toolbar-tab-hover);
}
#device-submit-button:hover:active {
background-color: var(--submit-button-active-background-color);
color: var(--submit-button-active-color);
}

View File

@@ -13,7 +13,7 @@ const { require } = BrowserLoader({
baseURI: "resource://devtools/client/responsive.html/",
window: this
});
const { GetDevices } = require("devtools/client/shared/devices");
const { Task } = require("resource://gre/modules/Task.jsm");
const Telemetry = require("devtools/client/shared/telemetry");
const { loadSheet } = require("sdk/stylesheet/utils");
@@ -22,9 +22,9 @@ const { createFactory, createElement } =
const ReactDOM = require("devtools/client/shared/vendor/react-dom");
const { Provider } = require("devtools/client/shared/vendor/react-redux");
const { initDevices } = require("./devices");
const App = createFactory(require("./app"));
const Store = require("./store");
const { addDevice, addDeviceType } = require("./actions/devices");
const { changeLocation } = require("./actions/location");
const { addViewport, resizeViewport } = require("./actions/viewports");
@@ -34,7 +34,7 @@ let bootstrap = {
store: null,
init() {
init: Task.async(function*() {
// Load a special UA stylesheet to reset certain styles such as dropdown
// lists.
loadSheet(window,
@@ -42,11 +42,11 @@ let bootstrap = {
"agent");
this.telemetry.toolOpened("responsive");
let store = this.store = Store();
yield initDevices(this.dispatch.bind(this));
let provider = createElement(Provider, { store }, App());
ReactDOM.render(provider, document.querySelector("#root"));
this.initDevices();
window.postMessage({ type: "init" }, "*");
},
}),
destroy() {
this.store = null;
@@ -69,19 +69,6 @@ let bootstrap = {
this.store.dispatch(action);
},
initDevices() {
GetDevices().then(devices => {
for (let type of devices.TYPES) {
this.dispatch(addDeviceType(type));
for (let device of devices[type]) {
if (device.os != "fxos") {
this.dispatch(addDevice(device, type));
}
}
}
});
},
};
window.addEventListener("load", function onLoad() {

View File

@@ -16,6 +16,7 @@ DIRS += [
DevToolsModules(
'app.js',
'constants.js',
'devices.js',
'index.css',
'manager.js',
'reducers.js',

View File

@@ -7,10 +7,13 @@
const {
ADD_DEVICE,
ADD_DEVICE_TYPE,
UPDATE_DEVICE_DISPLAYED,
UPDATE_DEVICE_MODAL_OPEN,
} = require("../actions/index");
const INITIAL_DEVICES = {
types: [],
isModalOpen: false,
};
let reducers = {
@@ -28,6 +31,26 @@ let reducers = {
});
},
[UPDATE_DEVICE_DISPLAYED](devices, { device, deviceType, displayed }) {
let newDevices = devices[deviceType].map(d => {
if (d == device) {
d.displayed = displayed;
}
return d;
});
return Object.assign({}, devices, {
[deviceType]: newDevices,
});
},
[UPDATE_DEVICE_MODAL_OPEN](devices, { isOpen }) {
return Object.assign({}, devices, {
isModalOpen: isOpen,
});
},
};
module.exports = function(devices = INITIAL_DEVICES, action) {

View File

@@ -9,6 +9,8 @@ support-files =
!/devtools/client/framework/test/shared-head.js
!/devtools/client/framework/test/shared-redux-head.js
[browser_device_modal_exit.js]
[browser_device_modal_submit.js]
[browser_device_width.js]
[browser_exit_button.js]
[browser_mouse_resize.js]

View File

@@ -0,0 +1,38 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test submitting display device changes on the device modal
const TEST_URL = "data:text/html;charset=utf-8,";
addRDMTask(TEST_URL, function* ({ ui }) {
let { store, document } = ui.toolWindow;
let modal = document.querySelector(".device-modal");
let closeButton = document.querySelector("#device-close-button");
// Wait until the viewport has been added
yield waitUntilState(store, state => state.viewports.length == 1);
openDeviceModal(ui);
let deviceListBefore = loadDeviceList();
info("Check the first unchecked device and exit the modal.");
let uncheckedCb = [...document.querySelectorAll(".device-input-checkbox")]
.filter(cb => !cb.checked)[0];
let value = uncheckedCb.value;
uncheckedCb.click();
closeButton.click();
ok(modal.classList.contains("hidden"),
"The device modal is hidden on exit.");
info("Check that the device list remains unchanged after exitting.");
let deviceListAfter = loadDeviceList();
is(deviceListBefore.length, deviceListAfter.length,
"Got expected number of displayed devices.");
ok(!deviceListAfter.includes(value),
value + " was not added to displayed device list.");
});

View File

@@ -0,0 +1,59 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test submitting display device changes on the device modal
const TEST_URL = "data:text/html;charset=utf-8,";
addRDMTask(TEST_URL, function* ({ ui }) {
let { store, document } = ui.toolWindow;
let modal = document.querySelector(".device-modal");
let select = document.querySelector(".viewport-device-selector");
let submitButton = document.querySelector("#device-submit-button");
// Wait until the viewport has been added
yield waitUntilState(store, state => state.viewports.length == 1);
openDeviceModal(ui);
info("Checking displayed device checkboxes are checked in the device modal.");
let checkedCbs = [...document.querySelectorAll(".device-input-checkbox")]
.filter(cb => cb.checked);
let deviceList = loadDeviceList();
is(deviceList.length, checkedCbs.length,
"Got expected number of displayed devices.");
for (let cb of checkedCbs) {
ok(deviceList.includes(cb.value), cb.value + " is correctly checked.");
}
info("Check the first unchecked device and submit new device list.");
let uncheckedCb = [...document.querySelectorAll(".device-input-checkbox")]
.filter(cb => !cb.checked)[0];
let value = uncheckedCb.value;
uncheckedCb.click();
submitButton.click();
ok(modal.classList.contains("hidden"),
"The device modal is hidden on submit.");
info("Checking new device is added to the displayed device list.");
deviceList = loadDeviceList();
ok(deviceList.includes(value), value + " added to displayed device list.");
info("Checking new device is added to the device selector.");
let options = [...select.options];
is(options.length - 2, deviceList.length,
"Got expected number of devices in device selector.");
ok(options.filter(o => o.value === value)[0],
value + " added to the device selector.");
info("Reopen device modal and check new device is correctly checked");
openDeviceModal(ui);
ok([...document.querySelectorAll(".device-input-checkbox")]
.filter(cb => cb.checked && cb.value === value)[0],
value + " is checked in the device modal.");
});

View File

@@ -1,5 +1,5 @@
{
"TYPES": [ "phones" ],
"TYPES": [ "phones", "tablets", "laptops", "televisions", "consoles", "watches" ],
"phones": [
{
"name": "Firefox OS Flame",
@@ -20,6 +20,632 @@
"touch": true,
"firefoxOS": true,
"os": "fxos"
},
{
"name": "Alcatel One Touch Fire C",
"width": 320,
"height": 480,
"pixelRatio": 1,
"userAgent": "Mozilla/5.0 (Mobile; ALCATELOneTouch4019X; rv:28.0) Gecko/28.0 Firefox/28.0",
"touch": true,
"firefoxOS": true,
"os": "fxos"
},
{
"name": "Alcatel One Touch Fire E",
"width": 320,
"height": 480,
"pixelRatio": 2,
"userAgent": "Mozilla/5.0 (Mobile; ALCATELOneTouch6015X; rv:32.0) Gecko/32.0 Firefox/32.0",
"touch": true,
"firefoxOS": true,
"os": "fxos"
},
{
"name": "Apple iPhone 4",
"width": 320,
"height": 480,
"pixelRatio": 2,
"userAgent": "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_2_1 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148 Safari/6533.18.5",
"touch": true,
"firefoxOS": false,
"os": "ios"
},
{
"name": "Apple iPhone 5",
"width": 320,
"height": 568,
"pixelRatio": 2,
"userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X; en-us) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53",
"touch": true,
"firefoxOS": false,
"os": "ios"
},
{
"name": "Apple iPhone 5s",
"width": 320,
"height": 568,
"pixelRatio": 2,
"userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 9_2_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13D15 Safari/601.1",
"touch": true,
"firefoxOS": false,
"os": "ios",
"featured": true
},
{
"name": "Apple iPhone 6",
"width": 375,
"height": 667,
"pixelRatio": 2,
"userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/600.1.3 (KHTML, like Gecko) Version/8.0 Mobile/12A4345d Safari/600.1.4",
"touch": true,
"firefoxOS": false,
"os": "ios"
},
{
"name": "Apple iPhone 6 Plus",
"width": 414,
"height": 736,
"pixelRatio": 3,
"userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/600.1.3 (KHTML, like Gecko) Version/8.0 Mobile/12A4345d Safari/600.1.4",
"touch": true,
"firefoxOS": false,
"os": "ios",
"featured": true
},
{
"name": "Apple iPhone 6s",
"width": 375,
"height": 667,
"pixelRatio": 2,
"userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/600.1.3 (KHTML, like Gecko) Version/8.0 Mobile/12A4345d Safari/600.1.4",
"touch": true,
"firefoxOS": false,
"os": "ios",
"featured": true
},
{
"name": "Apple iPhone 6s Plus",
"width": 414,
"height": 736,
"pixelRatio": 3,
"userAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/600.1.3 (KHTML, like Gecko) Version/8.0 Mobile/12A4345d Safari/600.1.4",
"touch": true,
"firefoxOS": false,
"os": "ios"
},
{
"name": "BlackBerry Z30",
"width": 360,
"height": 640,
"pixelRatio": 2,
"userAgent": "Mozilla/5.0 (BB10; Touch) AppleWebKit/537.10+ (KHTML, like Gecko) Version/10.0.9.2372 Mobile Safari/537.10+",
"touch": true,
"firefoxOS": false,
"os": "blackberryos"
},
{
"name": "Geeksphone Keon",
"width": 320,
"height": 480,
"pixelRatio": 1,
"userAgent": "Mozilla/5.0 (Mobile; rv:39.0) Gecko/39.0 Firefox/39.0",
"touch": true,
"firefoxOS": true,
"os": "android"
},
{
"name": "Geeksphone Peak, Revolution",
"width": 360,
"height": 640,
"pixelRatio": 1.5,
"userAgent": "Mozilla/5.0 (Mobile; rv:39.0) Gecko/39.0 Firefox/39.0",
"touch": true,
"firefoxOS": true,
"os": "android"
},
{
"name": "Google Nexus S",
"width": 320,
"height": 533,
"pixelRatio": 1.5,
"userAgent": "Mozilla/5.0 (Linux; U; Android 2.3.4; en-us; Nexus S Build/GRJ22) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
"touch": true,
"firefoxOS": true,
"os": "android"
},
{
"name": "Google Nexus 4",
"width": 384,
"height": 640,
"pixelRatio": 2,
"userAgent": "Mozilla/5.0 (Linux; Android 4.4.4; en-us; Nexus 4 Build/JOP40D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2307.2 Mobile Safari/537.36",
"touch": true,
"firefoxOS": true,
"os": "android",
"featured": true
},
{
"name": "Google Nexus 5",
"width": 360,
"height": 640,
"pixelRatio": 3,
"userAgent": "Mozilla/5.0 (Linux; Android 4.4.4; en-us; Nexus 5 Build/JOP40D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2307.2 Mobile Safari/537.36",
"touch": true,
"firefoxOS": true,
"os": "android",
"featured": true
},
{
"name": "Google Nexus 6",
"width": 412,
"height": 732,
"pixelRatio": 3.5,
"userAgent": "Mozilla/5.0 (Linux; Android 5.1.1; Nexus 6 Build/LYZ28E) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.23 Mobile Safari/537.36",
"touch": true,
"firefoxOS": true,
"os": "android",
"featured": true
},
{
"name": "Intex Cloud Fx",
"width": 320,
"height": 480,
"pixelRatio": 1,
"userAgent": "Mozilla/5.0 (Mobile; rv:32.0) Gecko/32.0 Firefox/32.0",
"touch": true,
"firefoxOS": true,
"os": "fxos"
},
{
"name": "KDDI Fx0",
"width": 360,
"height": 640,
"pixelRatio": 2,
"userAgent": "Mozilla/5.0 (Mobile; LGL25; rv:32.0) Gecko/32.0 Firefox/32.0",
"touch": true,
"firefoxOS": true,
"os": "fxos"
},
{
"name": "LG Fireweb",
"width": 320,
"height": 480,
"pixelRatio": 1,
"userAgent": "Mozilla/5.0 (Mobile; LG-D300; rv:18.1) Gecko/18.1 Firefox/18.1",
"touch": true,
"firefoxOS": true,
"os": "fxos"
},
{
"name": "LG Optimus L70",
"width": 384,
"height": 640,
"pixelRatio": 1.25,
"userAgent": "Mozilla/5.0 (Linux; U; Android 4.4.2; en-us; LGMS323 Build/KOT49I.MS32310c) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/30.0.1599.103 Mobile Safari/537.36",
"touch": true,
"firefoxOS": false,
"os": "android"
},
{
"name": "Nokia Lumia 520",
"width": 320,
"height": 533,
"pixelRatio": 1.4,
"userAgent": "Mozilla/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident/6.0; IEMobile/10.0; ARM; Touch; NOKIA; Lumia 520)",
"touch": true,
"firefoxOS": false,
"os": "android",
"featured": true
},
{
"name": "Nokia N9",
"width": 360,
"height": 640,
"pixelRatio": 1,
"userAgent": "Mozilla/5.0 (MeeGo; NokiaN9) AppleWebKit/534.13 (KHTML, like Gecko) NokiaBrowser/8.5.0 Mobile Safari/534.13",
"touch": true,
"firefoxOS": false,
"os": "android"
},
{
"name": "OnePlus One",
"width": 360,
"height": 640,
"pixelRatio": 3,
"userAgent": "Mozilla/5.0 (Android 5.1.1; Mobile; rv:43.0) Gecko/43.0 Firefox/43.0",
"touch": true,
"firefoxOS": false,
"os": "android"
},
{
"name": "Samsung Galaxy S3",
"width": 360,
"height": 640,
"pixelRatio": 2,
"userAgent": "Mozilla/5.0 (Linux; U; Android 4.0; en-us; GT-I9300 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30",
"touch": true,
"firefoxOS": false,
"os": "android"
},
{
"name": "Samsung Galaxy S4",
"width": 360,
"height": 640,
"pixelRatio": 3,
"userAgent": "Mozilla/5.0 (Linux; Android 4.4.2; GT-I9505 Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Version/1.5 Chrome/28.0.1500.94 Mobile Safari/537.36",
"touch": true,
"firefoxOS": false,
"os": "android"
},
{
"name": "Samsung Galaxy S5",
"width": 360,
"height": 640,
"pixelRatio": 3,
"userAgent": "Mozilla/5.0 (Linux; Android 4.4.2; GT-I9505 Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Version/1.5 Chrome/28.0.1500.94 Mobile Safari/537.36",
"touch": true,
"firefoxOS": false,
"os": "android",
"featured": true
},
{
"name": "Samsung Galaxy S6",
"width": 360,
"height": 640,
"pixelRatio": 4,
"userAgent": "Mozilla/5.0 (Linux; Android 4.4.2; GT-I9505 Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Version/1.5 Chrome/28.0.1500.94 Mobile Safari/537.36",
"touch": true,
"firefoxOS": false,
"os": "android",
"featured": true
},
{
"name": "Sony Xperia Z3",
"width": 360,
"height": 640,
"pixelRatio": 3,
"userAgent": "Mozilla/5.0 (Mobile; rv:39.0) Gecko/39.0 Firefox/39.0",
"touch": true,
"firefoxOS": true,
"os": "android"
},
{
"name": "Spice Fire One Mi-FX1",
"width": 320,
"height": 480,
"pixelRatio": 1,
"userAgent": "Mozilla/5.0 (Mobile; rv:28.0) Gecko/28.0 Firefox/28.0",
"touch": true,
"firefoxOS": true,
"os": "fxos"
},
{
"name": "Symphony GoFox F15",
"width": 320,
"height": 480,
"pixelRatio": 1,
"userAgent": "Mozilla/5.0 (Mobile; rv:30.0) Gecko/30.0 Firefox/30.0",
"touch": true,
"firefoxOS": true,
"os": "fxos"
},
{
"name": "ZTE Open",
"width": 320,
"height": 480,
"pixelRatio": 1,
"userAgent": "Mozilla/5.0 (Mobile; ZTEOPEN; rv:18.1) Gecko/18.0 Firefox/18.1",
"touch": true,
"firefoxOS": true,
"os": "fxos"
},
{
"name": "ZTE Open II",
"width": 320,
"height": 480,
"pixelRatio": 1,
"userAgent": "Mozilla/5.0 (Mobile; OPEN2; rv:28.0) Gecko/28.0 Firefox/28.0",
"touch": true,
"firefoxOS": true,
"os": "fxos"
},
{
"name": "ZTE Open C",
"width": 320,
"height": 450,
"pixelRatio": 1.5,
"userAgent": "Mozilla/5.0 (Mobile; OPENC; rv:32.0) Gecko/32.0 Firefox/32.0",
"touch": true,
"firefoxOS": true,
"os": "fxos"
},
{
"name": "Zen Fire 105",
"width": 320,
"height": 480,
"pixelRatio": 1,
"userAgent": "Mozilla/5.0 (Mobile; rv:28.0) Gecko/28.0 Firefox/28.0",
"touch": true,
"firefoxOS": true,
"os": "fxos"
}
],
"tablets": [
{
"name": "Amazon Kindle Fire HDX 8.9",
"width": 1280,
"height": 800,
"pixelRatio": 2,
"userAgent": "Mozilla/5.0 (Linux; U; en-us; KFAPWI Build/JDQ39) AppleWebKit/535.19 (KHTML, like Gecko) Silk/3.13 Safari/535.19 Silk-Accelerated=true",
"touch": true,
"firefoxOS": false,
"os": "fireos",
"featured": true
},
{
"name": "Apple iPad",
"width": 1024,
"height": 768,
"pixelRatio": 2,
"userAgent": "Mozilla/5.0 (iPad; CPU OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53",
"touch": true,
"firefoxOS": false,
"os": "ios"
},
{
"name": "Apple iPad Air 2",
"width": 1024,
"height": 768,
"pixelRatio": 2,
"userAgent": "Mozilla/5.0 (iPad; CPU OS 4_3_5 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8L1 Safari/6533.18.5",
"touch": true,
"firefoxOS": false,
"os": "ios",
"featured": true
},
{
"name": "Apple iPad Mini",
"width": 1024,
"height": 768,
"pixelRatio": 1,
"userAgent": "Mozilla/5.0 (iPad; CPU OS 4_3_5 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8L1 Safari/6533.18.5",
"touch": true,
"firefoxOS": false,
"os": "ios"
},
{
"name": "Apple iPad Mini 2",
"width": 1024,
"height": 768,
"pixelRatio": 2,
"userAgent": "Mozilla/5.0 (iPad; CPU OS 4_3_5 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8L1 Safari/6533.18.5",
"touch": true,
"firefoxOS": false,
"os": "ios",
"featured": true
},
{
"name": "BlackBerry PlayBook",
"width": 1024,
"height": 600,
"pixelRatio": 1,
"userAgent": "Mozilla/5.0 (PlayBook; U; RIM Tablet OS 2.1.0; en-US) AppleWebKit/536.2+ (KHTML like Gecko) Version/7.2.1.0 Safari/536.2+",
"touch": true,
"firefoxOS": false,
"os": "blackberryos"
},
{
"name": "Foxconn InFocus",
"width": 1280,
"height": 800,
"pixelRatio": 1,
"userAgent": "Mozilla/5.0 (Tablet; rv:32.0) Gecko/32.0 Firefox/32.0",
"touch": true,
"firefoxOS": true,
"os": "android"
},
{
"name": "Google Nexus 7",
"width": 960,
"height": 600,
"pixelRatio": 2,
"userAgent": "Mozilla/5.0 (Linux; Android 4.3; Nexus 7 Build/JSS15Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2307.2 Mobile Safari/537.36",
"touch": true,
"firefoxOS": false,
"os": "android",
"featured": true
},
{
"name": "Google Nexus 10",
"width": 1280,
"height": 800,
"pixelRatio": 2,
"userAgent": "Mozilla/5.0 (Linux; Android 4.3; Nexus 10 Build/JSS15Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2307.2 Mobile Safari/537.36",
"touch": true,
"firefoxOS": false,
"os": "android"
},
{
"name": "Samsung Galaxy Note 2",
"width": 360,
"height": 640,
"pixelRatio": 2,
"userAgent": "Mozilla/5.0 (Linux; U; Android 4.1; en-us; GT-N7100 Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30",
"touch": true,
"firefoxOS": false,
"os": "android"
},
{
"name": "Samsung Galaxy Note 3",
"width": 360,
"height": 640,
"pixelRatio": 3,
"userAgent": "Mozilla/5.0 (Linux; U; Android 4.3; en-us; SM-N900T Build/JSS15J) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30",
"touch": true,
"firefoxOS": false,
"os": "android",
"featured": true
},
{
"name": "Tesla Model S",
"width": 1200,
"height": 1920,
"pixelRatio": 1,
"userAgent": "Mozilla/5.0 (X11; Linux) AppleWebKit/534.34 (KHTML, like Gecko) QtCarBrowser Safari/534.34",
"touch": true,
"firefoxOS": false,
"os": "linux"
},
{
"name": "VIA Vixen",
"width": 1024,
"height": 600,
"pixelRatio": 1,
"userAgent": "Mozilla/5.0 (Tablet; rv:32.0) Gecko/32.0 Firefox/32.0",
"touch": true,
"firefoxOS": true,
"os": "fxos"
}
],
"laptops": [
{
"name": "Laptop (1366 x 768)",
"width": 1366,
"height": 768,
"pixelRatio": 1,
"userAgent": "",
"touch": false,
"firefoxOS": false,
"os": "windows",
"featured": true
},
{
"name": "Laptop (1920 x 1080)",
"width": 1280,
"height": 720,
"pixelRatio": 1.5,
"userAgent": "",
"touch": false,
"firefoxOS": false,
"os": "windows",
"featured": true
},
{
"name": "Laptop (1920 x 1080) with touch",
"width": 1280,
"height": 720,
"pixelRatio": 1.5,
"userAgent": "",
"touch": true,
"firefoxOS": false,
"os": "windows"
}
],
"televisions": [
{
"name": "720p HD Television",
"width": 1280,
"height": 720,
"pixelRatio": 1,
"userAgent": "",
"touch": false,
"firefoxOS": true,
"os": "custom"
},
{
"name": "1080p Full HD Television",
"width": 1920,
"height": 1080,
"pixelRatio": 1,
"userAgent": "",
"touch": false,
"firefoxOS": true,
"os": "custom"
},
{
"name": "4K Ultra HD Television",
"width": 3840,
"height": 2160,
"pixelRatio": 1,
"userAgent": "",
"touch": false,
"firefoxOS": true,
"os": "custom"
}
],
"consoles": [
{
"name": "Nintendo 3DS",
"width": 320,
"height": 240,
"pixelRatio": 1,
"userAgent": "Mozilla/5.0 (Nintendo 3DS; U; ; en) Version/1.7585.EU",
"touch": true,
"firefoxOS": false,
"os": "nintendo"
},
{
"name": "Nintendo Wii U Gamepad",
"width": 854,
"height": 480,
"pixelRatio": 0.87,
"userAgent": "Mozilla/5.0 (Nintendo WiiU) AppleWebKit/536.28 (KHTML, like Gecko) NX/3.0.3.12.15 NintendoBrowser/4.1.1.9601.EU",
"touch": true,
"firefoxOS": false,
"os": "nintendo"
},
{
"name": "Sony PlayStation Vita",
"width": 960,
"height": 544,
"pixelRatio": 1,
"userAgent": "Mozilla/5.0 (Playstation Vita 1.61) AppleWebKit/531.22.8 (KHTML, like Gecko) Silk/3.2",
"touch": true,
"firefoxOS": false,
"os": "playstation"
}
],
"watches": [
{
"name": "LG G Watch",
"width": 280,
"height": 280,
"pixelRatio": 1,
"userAgent": "",
"touch": true,
"firefoxOS": true,
"os": "android"
},
{
"name": "LG G Watch R",
"width": 320,
"height": 320,
"pixelRatio": 1,
"userAgent": "",
"touch": true,
"firefoxOS": true,
"os": "android"
},
{
"name": "Motorola Moto 360",
"width": 320,
"height": 290,
"pixelRatio": 1,
"userAgent": "Mozilla/5.0 (Linux; Android 5.0.1; Moto 360 Build/LWX48T) AppleWebkit/537.36 (KHTML, like Gecko) Chrome/19.77.34.5 Mobile Safari/537.36",
"touch": true,
"firefoxOS": true,
"os": "android"
},
{
"name": "Samsung Gear Live",
"width": 320,
"height": 320,
"pixelRatio": 1,
"userAgent": "",
"touch": true,
"firefoxOS": true,
"os": "android"
}
]
}

View File

@@ -26,6 +26,7 @@ SimpleTest.requestCompleteLog();
SimpleTest.waitForExplicitFinish();
DevToolsUtils.testing = true;
Services.prefs.clearUserPref("devtools.responsive.html.displayedDeviceList");
Services.prefs.setCharPref("devtools.devices.url",
TEST_URI_ROOT + "devices.json");
Services.prefs.setBoolPref("devtools.responsive.html.enabled", true);
@@ -34,8 +35,12 @@ registerCleanupFunction(() => {
DevToolsUtils.testing = false;
Services.prefs.clearUserPref("devtools.devices.url");
Services.prefs.clearUserPref("devtools.responsive.html.enabled");
Services.prefs.clearUserPref("devtools.responsive.html.displayedDeviceList");
});
const { ResponsiveUIManager } = Cu.import("resource://devtools/client/responsivedesign/responsivedesign.jsm", {});
const { loadDeviceList } = require("devtools/client/responsive.html/devices");
const OPEN_DEVICE_MODAL_VALUE = "OPEN_DEVICE_MODAL";
/**
* Open responsive design mode for the given tab.
@@ -125,3 +130,25 @@ var setViewportSize = Task.async(function* (ui, manager, width, height) {
yield resized;
}
});
function openDeviceModal(ui) {
let { document } = ui.toolWindow;
let select = document.querySelector(".viewport-device-selector");
let modal = document.querySelector(".device-modal");
let editDeviceOption = [...select.options].filter(o => {
return o.value === OPEN_DEVICE_MODAL_VALUE;
})[0];
info("Checking initial device modal state");
ok(modal.classList.contains("hidden"),
"The device modal is hidden by default.");
info("Opening device modal through device selector.");
EventUtils.synthesizeMouseAtCenter(select, {type: "mousedown"},
ui.toolWindow);
EventUtils.synthesizeMouseAtCenter(editDeviceOption, {type: "mouseup"},
ui.toolWindow);
ok(!modal.classList.contains("hidden"),
"The device modal is displayed.");
}

View File

@@ -0,0 +1,37 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
// Test updating the device `displayed` property
const {
addDevice,
addDeviceType,
updateDeviceDisplayed,
} = require("devtools/client/responsive.html/actions/devices");
add_task(function*() {
let store = Store();
const { getState, dispatch } = store;
let device = {
"name": "Firefox OS Flame",
"width": 320,
"height": 570,
"pixelRatio": 1.5,
"userAgent": "Mozilla/5.0 (Mobile; rv:39.0) Gecko/39.0 Firefox/39.0",
"touch": true,
"firefoxOS": true,
"os": "fxos"
};
dispatch(addDeviceType("phones"));
dispatch(addDevice(device, "phones"));
dispatch(updateDeviceDisplayed(device, "phones", true));
equal(getState().devices.phones.length, 1,
"Correct number of phones");
ok(getState().devices.phones[0].displayed,
"Device phone list contains enabled Firefox OS Flame");
});

View File

@@ -11,3 +11,4 @@ firefox-appdir = browser
[test_change_viewport_device.js]
[test_resize_viewport.js]
[test_rotate_viewport.js]
[test_update_device_displayed.js]

View File

@@ -32,9 +32,12 @@ const device = {
// Whether or not it is a touch device
touch: PropTypes.bool,
// The operating system of the device
// The operating system of the device
os: PropTypes.String,
// Whether or not the device is displayed in the device selector
displayed: PropTypes.bool,
};
/**
@@ -63,6 +66,9 @@ exports.devices = {
// An array of watch devices
watches: PropTypes.arrayOf(PropTypes.shape(device)),
// Whether or not the device modal is open
isModalOpen: PropTypes.bool,
};
/**

View File

@@ -28,7 +28,7 @@ xul|scrollbar[orient="horizontal"] {
}
xul|scrollbar xul|thumb {
background-color: rgba(170,170,170,0.2) !important;
background-color: rgba(170, 170, 170, .2) !important; /* --toolbar-tab-hover */
-moz-appearance: none !important;
border-width: 0px !important;
border-radius: 3px !important;

View File

@@ -5,6 +5,8 @@
/* CSS Variables specific to the devtools toolbar that aren't defined by the themes */
.theme-light {
--toolbar-tab-hover: rgba(170, 170, 170, .2);
--toolbar-tab-hover-active: rgba(170, 170, 170, .4);
--searchbox-background-color: #ffee99;
--searchbox-border-color: #ffbf00;
--searcbox-no-match-background-color: #ffe5e5;
@@ -22,6 +24,8 @@
}
.theme-dark {
--toolbar-tab-hover: hsla(206, 37%, 4%, .2);
--toolbar-tab-hover-active: hsla(206, 37%, 4%, .4);
--searchbox-background-color: #4d4222;
--searchbox-border-color: #d99f2b;
--searcbox-no-match-background-color: #402325;
@@ -271,7 +275,7 @@
.theme-light .devtools-toolbarbutton[label]:not([text-as-image]):not([type=menu-button]),
.theme-light .devtools-toolbarbutton[data-text-only],
.theme-light #toolbox-buttons .devtools-toolbarbutton[text-as-image] {
background-color: rgba(170, 170, 170, .2); /* Splitter */
background-color: var(--toolbar-tab-hover);
}
.theme-dark .devtools-toolbarbutton[label]:not([text-as-image]):not([type=menu-button]),
.theme-dark .devtools-toolbarbutton[data-text-only],
@@ -299,7 +303,7 @@
.theme-light .devtools-button:not(:empty):not([disabled]):hover:active,
.theme-light #toolbox-buttons .devtools-toolbarbutton:not([disabled])[text-as-image]:hover:active,
.theme-light .devtools-toolbarbutton:not(:-moz-any([checked=true],[disabled],[text-as-image]))[label]:hover:active {
background: rgba(170, 170, 170, .4); /* Splitters */
background: var(--toolbar-tab-hover-active);
}
.theme-dark .devtools-toolbarbutton:not([disabled])[label][checked=true],
@@ -729,10 +733,10 @@
}
.command-button:hover {
background-color: hsla(206,37%,4%,.2);
background-color: var(--toolbar-tab-hover);
}
.command-button:hover:active, .command-button[checked=true]:not(:hover) {
background-color: hsla(206,37%,4%,.4);
background-color: var(--toolbar-tab-hover-active)
}
.command-button > image {
@@ -867,21 +871,19 @@
}
.theme-dark .devtools-tab:hover {
background-color: hsla(206,37%,4%,.2);
color: #ced3d9;
}
.theme-light .devtools-tab:hover {
background-color: rgba(170,170,170,.2);
.devtools-tab:hover {
background-color: var(--toolbar-tab-hover);
}
.theme-dark .devtools-tab:hover:active {
background-color: hsla(206,37%,4%,.4);
color: var(--theme-selection-color);
}
.theme-light .devtools-tab:hover:active {
background-color: rgba(170,170,170,.4);
.devtools-tab:hover:active {
background-color: var(--toolbar-tab-hover-active);
}
.devtools-tab:not([selected])[highlighted] {