зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1487857 - Part I: Rearranging devices setting view to new design. r=gl,flod
This is part 1 of implementing the redesigned device settings panel. In this patch we are rearranging the existing device settings view to match the new design. Differential Revision: https://phabricator.services.mozilla.com/D15734 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
cce04c17b8
Коммит
ab764ec7dc
|
@ -70,41 +70,38 @@ responsive.customDeviceName=Custom Device
|
|||
# name of the device we're staring from, such as "Apple iPhone 6".
|
||||
responsive.customDeviceNameFromBase=%1$S (Custom)
|
||||
|
||||
# LOCALIZATION NOTE (responsive.addDevice): Button text that reveals a form to
|
||||
# LOCALIZATION NOTE (responsive.addDevice2): Button text that reveals a form to
|
||||
# be used for adding custom devices.
|
||||
responsive.addDevice=Add Device
|
||||
responsive.addDevice2=Add Custom Device…
|
||||
|
||||
# LOCALIZATION NOTE (responsive.deviceAdderName): Label of form field for the
|
||||
# name of a new device. The available width is very low, so you might see
|
||||
# overlapping text if the length is much longer than 5 or so characters.
|
||||
# name of a new device.
|
||||
responsive.deviceAdderName=Name
|
||||
|
||||
# LOCALIZATION NOTE (responsive.deviceAdderSize): Label of form field for the
|
||||
# size of a new device. The available width is very low, so you might see
|
||||
# overlapping text if the length is much longer than 5 or so characters.
|
||||
# size of a new device.
|
||||
responsive.deviceAdderSize=Size
|
||||
|
||||
# LOCALIZATION NOTE (responsive.deviceAdderPixelRatio): Label of form field for
|
||||
# the device pixel ratio of a new device. The available width is very low, so you
|
||||
# might see overlapping text if the length is much longer than 5 or so
|
||||
# characters.
|
||||
responsive.deviceAdderPixelRatio=DPR
|
||||
# LOCALIZATION NOTE (responsive.deviceAdderPixelRatio2): Label of form field for
|
||||
# the device pixel ratio of a new device.
|
||||
responsive.deviceAdderPixelRatio2=Device Pixel Ratio
|
||||
|
||||
# LOCALIZATION NOTE (responsive.deviceAdderUserAgent): Label of form field for
|
||||
# the user agent of a new device. The available width is very low, so you might
|
||||
# see overlapping text if the length is much longer than 5 or so characters.
|
||||
responsive.deviceAdderUserAgent=UA
|
||||
# LOCALIZATION NOTE (responsive.deviceAdderUserAgent2): Label of form field for
|
||||
# the user agent of a new device.
|
||||
responsive.deviceAdderUserAgent2=User Agent String
|
||||
|
||||
# LOCALIZATION NOTE (responsive.deviceAdderTouch): Label of form field for the
|
||||
# touch input support of a new device. The available width is very low, so you
|
||||
# might see overlapping text if the length is much longer than 5 or so
|
||||
# characters.
|
||||
responsive.deviceAdderTouch=Touch
|
||||
# LOCALIZATION NOTE (responsive.deviceAdderTouch2): Label of form field for the
|
||||
# touch input support of a new device.
|
||||
responsive.deviceAdderTouch2=Touch Screen
|
||||
|
||||
# LOCALIZATION NOTE (responsive.deviceAdderSave): Button text that submits a
|
||||
# form to add a new device.
|
||||
responsive.deviceAdderSave=Save
|
||||
|
||||
# LOCALIZATION NOTE (responsive.deviceAdderCancel): Button text that cancels a
|
||||
# form to add a new device.
|
||||
responsive.deviceAdderCancel=Cancel
|
||||
|
||||
# LOCALIZATION NOTE (responsive.deviceDetails): Tooltip that appears when
|
||||
# hovering on a device in the device modal. %1$S is the width of the device.
|
||||
# %2$S is the height of the device. %3$S is the device pixel ratio value of the
|
||||
|
@ -142,3 +139,11 @@ responsive.settingOnboarding.content=New: Change to left-alignment or edit reloa
|
|||
responsive.customUserAgent=Custom User Agent
|
||||
|
||||
responsive.showUserAgentInput=Show user agent
|
||||
|
||||
# LOCALIZATION NOTE (responsive.deviceSettings): The header text for the device settings
|
||||
# view.
|
||||
responsive.deviceSettings=Device Settings
|
||||
|
||||
# LOCALIZATION NOTE (responsive.deviceNameAlreadyInUse): This is the text shown when adding a new
|
||||
# device with an already existing device name.
|
||||
responsive.deviceNameAlreadyInUse=Device name already in use
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
/* 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 { PureComponent } = require("devtools/client/shared/vendor/react");
|
||||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
|
||||
const { getFormatStr } = require("../utils/l10n");
|
||||
const Types = require("../types");
|
||||
|
||||
class Device extends PureComponent {
|
||||
static get propTypes() {
|
||||
return {
|
||||
// props.children are the buttons rendered as part of custom device label.
|
||||
children: PropTypes.oneOfType([
|
||||
PropTypes.arrayOf(PropTypes.node),
|
||||
PropTypes.node,
|
||||
]),
|
||||
device: PropTypes.shape(Types.devices).isRequired,
|
||||
onDeviceCheckboxChange: PropTypes.func.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
// Whether or not the device's input label is checked.
|
||||
isChecked: this.props.device.isChecked,
|
||||
};
|
||||
|
||||
this.onCheckboxChanged = this.onCheckboxChanged.bind(this);
|
||||
}
|
||||
|
||||
onCheckboxChanged(e) {
|
||||
this.setState(prevState => {
|
||||
return { isChecked: !prevState.isChecked };
|
||||
});
|
||||
|
||||
this.props.onDeviceCheckboxChange(e);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { children, device } = this.props;
|
||||
const details = getFormatStr(
|
||||
"responsive.deviceDetails", device.width, device.height,
|
||||
device.pixelRatio, device.userAgent, device.touch
|
||||
);
|
||||
|
||||
return (
|
||||
dom.label(
|
||||
{
|
||||
className: "device-label",
|
||||
key: device.name,
|
||||
title: details,
|
||||
},
|
||||
dom.input({
|
||||
className: "device-input-checkbox",
|
||||
name: device.name,
|
||||
type: "checkbox",
|
||||
value: device.name,
|
||||
checked: device.isChecked,
|
||||
onChange: this.onCheckboxChanged,
|
||||
}),
|
||||
dom.span({ className: "device-name" },
|
||||
device.name
|
||||
),
|
||||
children
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Device;
|
|
@ -0,0 +1,186 @@
|
|||
/* 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 { createFactory, createRef, PureComponent } = require("devtools/client/shared/vendor/react");
|
||||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
|
||||
const ViewportDimension = createFactory(require("./ViewportDimension"));
|
||||
|
||||
const { getStr } = require("../utils/l10n");
|
||||
const Types = require("../types");
|
||||
|
||||
class DeviceForm extends PureComponent {
|
||||
static get propTypes() {
|
||||
return {
|
||||
buttonText: PropTypes.string,
|
||||
formType: PropTypes.string.isRequired,
|
||||
device: PropTypes.shape(Types.device).isRequired,
|
||||
onSave: PropTypes.func.isRequired,
|
||||
validateName: PropTypes.func.isRequired,
|
||||
viewportTemplate: PropTypes.shape(Types.viewport).isRequired,
|
||||
onDeviceFormHide: PropTypes.func.isRequired,
|
||||
onDeviceFormShow: PropTypes.func.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
const {
|
||||
height,
|
||||
width,
|
||||
} = this.props.viewportTemplate;
|
||||
|
||||
this.state = {
|
||||
isShown: false,
|
||||
height,
|
||||
width,
|
||||
};
|
||||
|
||||
this.nameInputRef = createRef();
|
||||
this.pixelRatioInputRef = createRef();
|
||||
this.touchInputRef = createRef();
|
||||
this.userAgentInputRef = createRef();
|
||||
|
||||
this.onChangeSize = this.onChangeSize.bind(this);
|
||||
this.onDeviceFormHide = this.onDeviceFormHide.bind(this);
|
||||
this.onDeviceFormShow = this.onDeviceFormShow.bind(this);
|
||||
this.onDeviceFormSave = this.onDeviceFormSave.bind(this);
|
||||
}
|
||||
|
||||
onChangeSize(_, width, height) {
|
||||
this.setState({
|
||||
width,
|
||||
height,
|
||||
});
|
||||
}
|
||||
|
||||
onDeviceFormSave() {
|
||||
if (!this.pixelRatioInputRef.current.checkValidity()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.props.validateName(this.nameInputRef.current.value)) {
|
||||
this.nameInputRef.current
|
||||
.setCustomValidity(getStr("responsive.deviceNameAlreadyInUse"));
|
||||
return;
|
||||
}
|
||||
|
||||
this.props.onSave({
|
||||
name: this.nameInputRef.current.value.trim(),
|
||||
width: this.state.width,
|
||||
height: this.state.height,
|
||||
pixelRatio: parseFloat(this.pixelRatioInputRef.current.value),
|
||||
userAgent: this.userAgentInputRef.current.value,
|
||||
touch: this.touchInputRef.current.checked,
|
||||
});
|
||||
|
||||
this.onDeviceFormHide();
|
||||
}
|
||||
|
||||
onDeviceFormHide() {
|
||||
this.setState({ isShown: false });
|
||||
|
||||
// Ensure that we have onDeviceFormHide before calling it.
|
||||
if (this.props.onDeviceFormHide) {
|
||||
this.props.onDeviceFormHide();
|
||||
}
|
||||
}
|
||||
|
||||
onDeviceFormShow() {
|
||||
this.setState({ isShown: true });
|
||||
|
||||
// Ensure that we have onDeviceFormShow before calling it.
|
||||
if (this.props.onDeviceFormShow) {
|
||||
this.props.onDeviceFormShow();
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { buttonText, device, formType } = this.props;
|
||||
const { isShown, width, height } = this.state;
|
||||
|
||||
if (!isShown) {
|
||||
return (
|
||||
dom.button(
|
||||
{
|
||||
id: `device-${formType}-button`,
|
||||
className: "devtools-button",
|
||||
onClick: this.onDeviceFormShow,
|
||||
},
|
||||
buttonText,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
dom.form({ id: "device-form" },
|
||||
dom.label({ id: "device-form-name", className: formType },
|
||||
dom.span({ className: "device-form-label" },
|
||||
getStr("responsive.deviceAdderName")
|
||||
),
|
||||
dom.input({
|
||||
defaultValue: device.name,
|
||||
ref: this.nameInputRef,
|
||||
})
|
||||
),
|
||||
dom.label({ id: "device-form-size" },
|
||||
dom.span({ className: "device-form-label" },
|
||||
getStr("responsive.deviceAdderSize")
|
||||
),
|
||||
ViewportDimension({
|
||||
viewport: { width, height },
|
||||
doResizeViewport: this.onChangeSize,
|
||||
onRemoveDeviceAssociation: () => {},
|
||||
})
|
||||
),
|
||||
dom.label({ id: "device-form-pixel-ratio" },
|
||||
dom.span({ className: "device-form-label" },
|
||||
getStr("responsive.deviceAdderPixelRatio2")
|
||||
),
|
||||
dom.input({
|
||||
type: "number",
|
||||
step: "any",
|
||||
defaultValue: device.pixelRatio,
|
||||
ref: this.pixelRatioInputRef,
|
||||
})
|
||||
),
|
||||
dom.label({ id: "device-form-user-agent" },
|
||||
dom.span({ className: "device-form-label" },
|
||||
getStr("responsive.deviceAdderUserAgent2")
|
||||
),
|
||||
dom.input({
|
||||
defaultValue: device.userAgent,
|
||||
ref: this.userAgentInputRef,
|
||||
})
|
||||
),
|
||||
dom.label({ id: "device-form-touch" },
|
||||
dom.input({
|
||||
defaultChecked: device.touch,
|
||||
type: "checkbox",
|
||||
ref: this.touchInputRef,
|
||||
}),
|
||||
dom.span({ className: "device-form-label" },
|
||||
getStr("responsive.deviceAdderTouch2")
|
||||
)
|
||||
),
|
||||
dom.div({ className: "device-form-buttons" },
|
||||
dom.button({ id: "device-form-save", onClick: this.onDeviceFormSave },
|
||||
getStr("responsive.deviceAdderSave")
|
||||
),
|
||||
dom.button({ id: "device-form-cancel", onClick: this.onDeviceFormHide },
|
||||
getStr("responsive.deviceAdderCancel")
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = DeviceForm;
|
|
@ -0,0 +1,70 @@
|
|||
/* 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 { createFactory, PureComponent } = require("devtools/client/shared/vendor/react");
|
||||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
|
||||
const Types = require("../types");
|
||||
|
||||
const Device = createFactory(require("./Device"));
|
||||
|
||||
class DeviceList extends PureComponent {
|
||||
static get propTypes() {
|
||||
return {
|
||||
devices: PropTypes.shape(Types.devices).isRequired,
|
||||
onDeviceCheckboxChange: PropTypes.func.isRequired,
|
||||
onRemoveCustomDevice: PropTypes.func.isRequired,
|
||||
type: PropTypes.string.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
renderCustomDevice(device) {
|
||||
const { onRemoveCustomDevice, onDeviceCheckboxChange, type } = this.props;
|
||||
|
||||
// Show a remove button for custom devices.
|
||||
const removeDeviceButton = dom.button({
|
||||
id: "device-editor-remove",
|
||||
className: "device-remove-button devtools-button",
|
||||
onClick: () => onRemoveCustomDevice(device),
|
||||
});
|
||||
|
||||
return Device(
|
||||
{
|
||||
device,
|
||||
key: device.name,
|
||||
type,
|
||||
onDeviceCheckboxChange,
|
||||
},
|
||||
removeDeviceButton
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { devices, type, onDeviceCheckboxChange } = this.props;
|
||||
|
||||
return (
|
||||
dom.div({ className: "device-list"},
|
||||
devices[type].map(device => {
|
||||
if (type === "custom") {
|
||||
return this.renderCustomDevice(device);
|
||||
}
|
||||
|
||||
return Device({
|
||||
device,
|
||||
key: device.name,
|
||||
type,
|
||||
onDeviceCheckboxChange,
|
||||
});
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = DeviceList;
|
|
@ -10,9 +10,10 @@ const { createFactory, PureComponent } = require("devtools/client/shared/vendor/
|
|||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
|
||||
const DeviceAdder = createFactory(require("./DeviceAdder"));
|
||||
const DeviceForm = createFactory(require("./DeviceForm"));
|
||||
const DeviceList = createFactory(require("./DeviceList"));
|
||||
|
||||
const { getStr, getFormatStr } = require("../utils/l10n");
|
||||
const { getFormatStr, getStr } = require("../utils/l10n");
|
||||
const Types = require("../types");
|
||||
|
||||
class DeviceModal extends PureComponent {
|
||||
|
@ -31,7 +32,9 @@ class DeviceModal extends PureComponent {
|
|||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {};
|
||||
this.state = {
|
||||
isDeviceFormShown: false,
|
||||
};
|
||||
for (const type of this.props.devices.types) {
|
||||
for (const device of this.props.devices[type]) {
|
||||
this.state[device.name] = device.displayed;
|
||||
|
@ -40,8 +43,11 @@ class DeviceModal extends PureComponent {
|
|||
|
||||
this.onAddCustomDevice = this.onAddCustomDevice.bind(this);
|
||||
this.onDeviceCheckboxChange = this.onDeviceCheckboxChange.bind(this);
|
||||
this.onDeviceFormShow = this.onDeviceFormShow.bind(this);
|
||||
this.onDeviceFormHide = this.onDeviceFormHide.bind(this);
|
||||
this.onDeviceModalSubmit = this.onDeviceModalSubmit.bind(this);
|
||||
this.onKeyDown = this.onKeyDown.bind(this);
|
||||
this.validateAddDeviceFormNameField = this.validateAddDeviceFormNameField.bind(this);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
|
@ -69,6 +75,14 @@ class DeviceModal extends PureComponent {
|
|||
});
|
||||
}
|
||||
|
||||
onDeviceFormShow() {
|
||||
this.setState({ isDeviceFormShown: true });
|
||||
}
|
||||
|
||||
onDeviceFormHide() {
|
||||
this.setState({ isDeviceFormShown: false });
|
||||
}
|
||||
|
||||
onDeviceModalSubmit() {
|
||||
const {
|
||||
devices,
|
||||
|
@ -115,24 +129,100 @@ class DeviceModal extends PureComponent {
|
|||
}
|
||||
}
|
||||
|
||||
renderAddDeviceForm(devices, viewportTemplate) {
|
||||
// If a device is currently selected, fold its attributes into a single object for use
|
||||
// as the starting values of the form. If no device is selected, use the values for
|
||||
// the current window.
|
||||
const deviceTemplate = viewportTemplate;
|
||||
if (viewportTemplate.device) {
|
||||
const device = devices[viewportTemplate.deviceType].find(d => {
|
||||
return d.name == viewportTemplate.device;
|
||||
});
|
||||
Object.assign(deviceTemplate, {
|
||||
pixelRatio: device.pixelRatio,
|
||||
userAgent: device.userAgent,
|
||||
touch: device.touch,
|
||||
name: getFormatStr("responsive.customDeviceNameFromBase", device.name),
|
||||
});
|
||||
} else {
|
||||
Object.assign(deviceTemplate, {
|
||||
pixelRatio: window.devicePixelRatio,
|
||||
userAgent: navigator.userAgent,
|
||||
touch: false,
|
||||
name: getStr("responsive.customDeviceName"),
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
DeviceForm({
|
||||
formType: "add",
|
||||
buttonText: getStr("responsive.addDevice2"),
|
||||
device: deviceTemplate,
|
||||
onDeviceFormHide: this.onDeviceFormHide,
|
||||
onDeviceFormShow: this.onDeviceFormShow,
|
||||
onSave: this.onAddCustomDevice,
|
||||
validateName: this.validateAddDeviceFormNameField,
|
||||
viewportTemplate,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
renderDevices() {
|
||||
const sortedDevices = {};
|
||||
for (const type of this.props.devices.types) {
|
||||
sortedDevices[type] = this.props.devices[type]
|
||||
.sort((a, b) => a.name.localeCompare(b.name));
|
||||
|
||||
sortedDevices[type].forEach(device => {
|
||||
device.isChecked = this.state[device.name];
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
this.props.devices.types.map(type => {
|
||||
return sortedDevices[type].length ?
|
||||
dom.div(
|
||||
{
|
||||
className: `device-type device-type-${type}`,
|
||||
key: type,
|
||||
},
|
||||
dom.header({ className: "device-header" }, type),
|
||||
DeviceList({
|
||||
devices: sortedDevices,
|
||||
type,
|
||||
onDeviceCheckboxChange: this.onDeviceCheckboxChange,
|
||||
onRemoveCustomDevice: this.props.onRemoveCustomDevice,
|
||||
})
|
||||
)
|
||||
:
|
||||
null;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the name field's value by checking if the added device's name already
|
||||
* exists in the custom devices list.
|
||||
*
|
||||
* @param {String} value
|
||||
* The input field value for the device name.
|
||||
* @return {Boolean} true if device name is valid, false otherwise.
|
||||
*/
|
||||
validateAddDeviceFormNameField(value) {
|
||||
const { devices } = this.props;
|
||||
const nameFieldValue = value.trim();
|
||||
const deviceFound = devices.custom.find(device => device.name == nameFieldValue);
|
||||
|
||||
return !deviceFound;
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
deviceAdderViewportTemplate,
|
||||
devices,
|
||||
onRemoveCustomDevice,
|
||||
onUpdateDeviceModal,
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
onAddCustomDevice,
|
||||
} = this;
|
||||
|
||||
const sortedDevices = {};
|
||||
for (const type of devices.types) {
|
||||
sortedDevices[type] = Object.assign([], devices[type])
|
||||
.sort((a, b) => a.name.localeCompare(b.name));
|
||||
}
|
||||
|
||||
return (
|
||||
dom.div(
|
||||
{
|
||||
|
@ -140,65 +230,26 @@ class DeviceModal extends PureComponent {
|
|||
className: this.props.devices.isModalOpen ? "opened" : "closed",
|
||||
},
|
||||
dom.div({ className: "device-modal" },
|
||||
dom.button({
|
||||
id: "device-close-button",
|
||||
className: "devtools-button",
|
||||
onClick: () => onUpdateDeviceModal(false),
|
||||
}),
|
||||
dom.div({ className: "device-modal-content" },
|
||||
devices.types.map(type => {
|
||||
return dom.div(
|
||||
{
|
||||
className: `device-type device-type-${type}`,
|
||||
key: type,
|
||||
},
|
||||
dom.header({ className: "device-header" },
|
||||
type
|
||||
),
|
||||
sortedDevices[type].map(device => {
|
||||
const details = getFormatStr(
|
||||
"responsive.deviceDetails", device.width, device.height,
|
||||
device.pixelRatio, device.userAgent, device.touch
|
||||
);
|
||||
|
||||
let removeDeviceButton;
|
||||
if (type == "custom") {
|
||||
removeDeviceButton = dom.button({
|
||||
className: "device-remove-button devtools-button",
|
||||
onClick: () => onRemoveCustomDevice(device),
|
||||
});
|
||||
}
|
||||
|
||||
return dom.label(
|
||||
{
|
||||
className: "device-label",
|
||||
key: device.name,
|
||||
title: details,
|
||||
},
|
||||
dom.input({
|
||||
className: "device-input-checkbox",
|
||||
type: "checkbox",
|
||||
value: device.name,
|
||||
checked: this.state[device.name],
|
||||
onChange: this.onDeviceCheckboxChange,
|
||||
}),
|
||||
dom.span(
|
||||
{
|
||||
className: "device-name",
|
||||
},
|
||||
device.name
|
||||
),
|
||||
removeDeviceButton
|
||||
);
|
||||
dom.div({ className: "device-modal-header" },
|
||||
!this.state.isDeviceFormShown ?
|
||||
dom.header({ className: "device-modal-title" },
|
||||
getStr("responsive.deviceSettings"),
|
||||
dom.button({
|
||||
id: "device-close-button",
|
||||
className: "devtools-button",
|
||||
onClick: () => onUpdateDeviceModal(false),
|
||||
})
|
||||
);
|
||||
})
|
||||
)
|
||||
:
|
||||
null,
|
||||
this.renderAddDeviceForm(devices, deviceAdderViewportTemplate)
|
||||
),
|
||||
dom.div({
|
||||
className: `device-modal-content
|
||||
${this.state.isDeviceFormShown ? " form-shown" : ""}`,
|
||||
},
|
||||
this.renderDevices()
|
||||
),
|
||||
DeviceAdder({
|
||||
devices,
|
||||
viewportTemplate: deviceAdderViewportTemplate,
|
||||
onAddCustomDevice,
|
||||
}),
|
||||
dom.button(
|
||||
{
|
||||
id: "device-submit-button",
|
||||
|
|
|
@ -7,7 +7,9 @@
|
|||
DevToolsModules(
|
||||
'App.js',
|
||||
'Browser.js',
|
||||
'DeviceAdder.js',
|
||||
'Device.js',
|
||||
'DeviceForm.js',
|
||||
'DeviceList.js',
|
||||
'DeviceModal.js',
|
||||
'DevicePixelRatioMenu.js',
|
||||
'DeviceSelector.js',
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
--submit-button-active-color: var(--theme-body-color);
|
||||
--viewport-active-color: #3b3b3b;
|
||||
--input-invalid-border-color: var(--red-60);
|
||||
--custom-device-button-hover: var(--grey-30);
|
||||
}
|
||||
|
||||
:root.theme-dark {
|
||||
|
@ -19,6 +20,7 @@
|
|||
--submit-button-active-color: var(--theme-selection-color);
|
||||
--viewport-active-color: #fcfcfc;
|
||||
--input-invalid-border-color: var(--red-50);
|
||||
--custom-device-button-hover: var(--grey-10-a20)
|
||||
}
|
||||
|
||||
* {
|
||||
|
@ -395,6 +397,8 @@ body,
|
|||
}
|
||||
|
||||
.device-modal {
|
||||
display: grid;
|
||||
grid-template-rows: minmax(80px, auto) auto 20px;
|
||||
background-color: var(--theme-toolbar-background);
|
||||
border: 1px solid var(--theme-splitter-color);
|
||||
border-radius: 2px;
|
||||
|
@ -405,10 +409,12 @@ body,
|
|||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
width: 800px;
|
||||
max-width: 90%;
|
||||
height: 650px;
|
||||
width: 90%;
|
||||
height: 90%;
|
||||
max-width: 750px;
|
||||
max-height: 730px;
|
||||
z-index: 1;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Handles the opening/closing of the modal */
|
||||
|
@ -432,12 +438,98 @@ body,
|
|||
}
|
||||
|
||||
.device-modal-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: wrap;
|
||||
display: grid;
|
||||
grid-row-gap: 30px;
|
||||
overflow: auto;
|
||||
height: 515px;
|
||||
margin: 20px 20px 0;
|
||||
height: 100%;
|
||||
padding: 10px 32px 50px 32px;
|
||||
}
|
||||
|
||||
.device-modal-content.form-shown {
|
||||
padding-top: 30px;
|
||||
}
|
||||
|
||||
/* On screens that are >750px*/
|
||||
@media (min-width: 750px) {
|
||||
#device-form {
|
||||
grid-template-areas: "name size dpr"
|
||||
"user-agent touch buttons";
|
||||
}
|
||||
|
||||
#device-form-name input,
|
||||
#device-form-user-agent input {
|
||||
width: 350px;
|
||||
}
|
||||
|
||||
.device-modal-content {
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
grid-template-areas: "phone phone custom"
|
||||
"tablet laptop tv";
|
||||
}
|
||||
}
|
||||
|
||||
/* On screens that are between 450px and 749px */
|
||||
@media (min-width: 450px) and (max-width: 749px) {
|
||||
#device-form {
|
||||
grid-template-areas: "name size"
|
||||
"user-agent dpr"
|
||||
"touch buttons";
|
||||
grid-template-columns: 2fr 1fr;
|
||||
}
|
||||
|
||||
#device-form-name {
|
||||
grid-area: name;
|
||||
}
|
||||
|
||||
#device-form-name input,
|
||||
#device-form-user-agent input {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.device-modal-content {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-template-areas: "phone phone"
|
||||
"tablet laptop"
|
||||
"tv custom";
|
||||
}
|
||||
}
|
||||
|
||||
/* On screens that are <450px */
|
||||
@media (max-width: 449px) {
|
||||
#device-form {
|
||||
grid-template-areas: "name"
|
||||
"size"
|
||||
"dpr"
|
||||
"user-agent"
|
||||
"touch"
|
||||
"buttons";
|
||||
}
|
||||
|
||||
#device-form-name input,
|
||||
#device-form-user-agent input {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
#device-form-size {
|
||||
justify-self: unset;
|
||||
}
|
||||
|
||||
.device-modal-content {
|
||||
grid-template-areas: "phone"
|
||||
"phone"
|
||||
"tablet"
|
||||
"laptop"
|
||||
"tv"
|
||||
"custom";
|
||||
}
|
||||
|
||||
.device-type.device-type-phones .device-list {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.device-modal-header {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
#device-close-button {
|
||||
|
@ -453,28 +545,65 @@ body,
|
|||
.device-type {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.device-header {
|
||||
font-weight: bold;
|
||||
font-size: 17px;
|
||||
margin-bottom: 7px;
|
||||
height: 20px;
|
||||
text-transform: capitalize;
|
||||
padding: 0 0 3px 23px;
|
||||
}
|
||||
|
||||
.device-label {
|
||||
color: var(--theme-body-color);
|
||||
padding-bottom: 3px;
|
||||
padding-bottom: 5px;
|
||||
padding-top: 5px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
/* Largest size without horizontal scrollbars */
|
||||
max-width: 181px;
|
||||
}
|
||||
|
||||
.device-label > button {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.device-label:focus-within > button,
|
||||
.device-label:hover > button {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.device-label:focus-within,
|
||||
.device-label:hover {
|
||||
background-color: var(--toolbarbutton-hover-background);
|
||||
}
|
||||
|
||||
.device-modal-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.device-modal-header > #device-add-button {
|
||||
margin: 30px 75px 0 30px;
|
||||
}
|
||||
|
||||
.device-modal-header > #device-form {
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.device-list {
|
||||
display: grid;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.device-input-checkbox {
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.device-modal-title {
|
||||
font-size: 22px;
|
||||
margin: 30px 0 0px 30px;
|
||||
}
|
||||
|
||||
.device-name {
|
||||
flex: 1;
|
||||
}
|
||||
|
@ -506,85 +635,168 @@ body,
|
|||
}
|
||||
|
||||
/**
|
||||
* Device Adder
|
||||
* Device Form
|
||||
*/
|
||||
|
||||
#device-adder {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin: 0 20px;
|
||||
#device-form {
|
||||
display: grid;
|
||||
width: 100%;
|
||||
background-color: var(--theme-toolbar-background);
|
||||
min-height: 150px;
|
||||
padding-left: 20px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid var(--theme-splitter-color);
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
#device-adder-content {
|
||||
display: flex;
|
||||
#device-add-button {
|
||||
margin-right: 70px;
|
||||
}
|
||||
|
||||
#device-adder-column-1 {
|
||||
flex: 1;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
#device-adder-column-2 {
|
||||
flex: 2;
|
||||
}
|
||||
|
||||
#device-adder button {
|
||||
background-color: var(--theme-tab-toolbar-background);
|
||||
#device-add-button,
|
||||
#device-form button {
|
||||
background-color: rgba(12, 12, 13, 0.1);
|
||||
border: 1px solid var(--theme-splitter-color);
|
||||
border-radius: 2px;
|
||||
color: var(--theme-body-color);
|
||||
margin: 0 auto;
|
||||
cursor: pointer;
|
||||
width: 167px;
|
||||
height: 32px;
|
||||
}
|
||||
|
||||
#device-adder label {
|
||||
#device-editor-remove {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
#device-editor-remove.device-remove-button:focus-within,
|
||||
#device-editor-remove.device-remove-button:hover {
|
||||
background-color: var(--custom-device-button-hover);
|
||||
}
|
||||
|
||||
#device-form label {
|
||||
display: flex;
|
||||
margin-bottom: 5px;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
#device-adder label > input,
|
||||
#device-adder label > .viewport-dimension {
|
||||
flex: 1;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#device-adder label > .viewport-dimension {
|
||||
border-bottom: 1px solid transparent;
|
||||
#device-form label > .viewport-dimension {
|
||||
color: var(--theme-body-color-inactive);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
transition: all 0.25s ease;
|
||||
}
|
||||
|
||||
#device-adder label > .viewport-dimension.editing {
|
||||
border-bottom-color: var(--theme-selection-background);
|
||||
}
|
||||
|
||||
#device-adder label > .viewport-dimension.editing.invalid {
|
||||
border-bottom-color: #d92215;
|
||||
}
|
||||
|
||||
#device-adder input {
|
||||
#device-form input {
|
||||
background: transparent;
|
||||
border: 1px solid transparent;
|
||||
border: 1px solid;
|
||||
border-radius: 2px;
|
||||
text-align: center;
|
||||
color: var(--theme-body-color-inactive);
|
||||
transition: all 0.25s ease;
|
||||
}
|
||||
|
||||
#device-adder input:focus {
|
||||
color: var(--viewport-active-color);
|
||||
#device-form #device-form-name input,
|
||||
#device-form #device-form-user-agent input {
|
||||
text-align: left;
|
||||
padding-left: 12px;
|
||||
padding-right: 12px;
|
||||
}
|
||||
|
||||
#device-adder label > input:focus,
|
||||
#device-adder label > .viewport-dimension:focus {
|
||||
border-bottom: 1px solid var(--theme-selection-background);
|
||||
#device-form input:focus {
|
||||
color: var(--viewport-active-color);
|
||||
border-color: var(--blue-55);
|
||||
}
|
||||
|
||||
#device-form label > input:focus,
|
||||
#device-form label > .viewport-dimension:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.device-adder-label {
|
||||
display: inline-block;
|
||||
margin-right: 5px;
|
||||
min-width: 35px;
|
||||
#device-form-pixel-ratio {
|
||||
grid-area: dpr;
|
||||
}
|
||||
|
||||
#device-form-pixel-ratio input {
|
||||
-moz-appearance: textfield;
|
||||
}
|
||||
|
||||
#device-form-user-agent {
|
||||
grid-area: user-agent;
|
||||
}
|
||||
|
||||
#device-form-name input,
|
||||
#device-form-pixel-ratio input,
|
||||
#device-form-user-agent input,
|
||||
#device-form-size input {
|
||||
height: 35px;
|
||||
}
|
||||
|
||||
#device-form #device-form-touch {
|
||||
flex-direction: row;
|
||||
grid-area: touch;
|
||||
}
|
||||
|
||||
#device-form-touch .device-form-label {
|
||||
align-self: center;
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
#device-form #device-form-save {
|
||||
background-color: #0060DF;
|
||||
color: #fff;
|
||||
border:1px solid #0060DF;
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
#device-form-size {
|
||||
grid-area: size;
|
||||
}
|
||||
|
||||
#device-form-size input,
|
||||
#device-form #device-form-cancel {
|
||||
width: 60px;
|
||||
}
|
||||
|
||||
#device-form-save,
|
||||
#device-form-cancel {
|
||||
align-self: center;
|
||||
}
|
||||
|
||||
.device-form-buttons {
|
||||
display: flex;
|
||||
grid-area: buttons;
|
||||
justify-content: space-evenly;
|
||||
width: 154px;
|
||||
}
|
||||
|
||||
.device-form-label {
|
||||
display: inline-block;
|
||||
margin: 0 5px 5px 0;
|
||||
min-width: 35px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
/* Device Types */
|
||||
|
||||
.device-type-phones {
|
||||
grid-area: phone;
|
||||
}
|
||||
|
||||
.device-type-phones .device-list {
|
||||
grid-template-columns: repeat(2, auto);
|
||||
}
|
||||
|
||||
.device-type-custom {
|
||||
grid-area: custom;
|
||||
align-self: start;
|
||||
}
|
||||
|
||||
.device-type-tablets {
|
||||
grid-area: tablet;
|
||||
}
|
||||
|
||||
.device-type-laptops {
|
||||
grid-area: laptop;
|
||||
}
|
||||
|
||||
.device-type-televisions {
|
||||
grid-area: tv;
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ addRDMTask(TEST_URL, async function({ ui }) {
|
|||
await openDeviceModal(ui);
|
||||
|
||||
info("Reveal device adder form, check that defaults match the viewport");
|
||||
const adderShow = document.getElementById("device-adder-show");
|
||||
const adderShow = document.getElementById("device-add-button");
|
||||
adderShow.click();
|
||||
testDeviceAdder(ui, {
|
||||
name: "Custom Device",
|
||||
|
@ -82,7 +82,7 @@ addRDMTask(TEST_URL, async function({ ui }) {
|
|||
await openDeviceModal(ui);
|
||||
|
||||
info("Reveal device adder form, check that defaults are based on selected device");
|
||||
const adderShow = document.getElementById("device-adder-show");
|
||||
const adderShow = document.getElementById("device-add-button");
|
||||
adderShow.click();
|
||||
testDeviceAdder(ui, Object.assign({}, device, {
|
||||
name: "Test Device (Custom)",
|
||||
|
@ -126,7 +126,7 @@ addRDMTask(TEST_URL, async function({ ui }) {
|
|||
await openDeviceModal(ui);
|
||||
|
||||
info("Reveal device adder form");
|
||||
const adderShow = document.querySelector("#device-adder-show");
|
||||
const adderShow = document.querySelector("#device-add-button");
|
||||
adderShow.click();
|
||||
|
||||
info("Fill out device adder form by setting details to unicode device and save");
|
||||
|
@ -171,12 +171,12 @@ addRDMTask(TEST_URL, async function({ ui }) {
|
|||
function testDeviceAdder(ui, expected) {
|
||||
const { document } = ui.toolWindow;
|
||||
|
||||
const nameInput = document.querySelector("#device-adder-name input");
|
||||
const nameInput = document.querySelector("#device-form-name input");
|
||||
const [ widthInput, heightInput ] =
|
||||
document.querySelectorAll("#device-adder-size input");
|
||||
const pixelRatioInput = document.querySelector("#device-adder-pixel-ratio input");
|
||||
const userAgentInput = document.querySelector("#device-adder-user-agent input");
|
||||
const touchInput = document.querySelector("#device-adder-touch input");
|
||||
document.querySelectorAll("#device-form-size input");
|
||||
const pixelRatioInput = document.querySelector("#device-form-pixel-ratio input");
|
||||
const userAgentInput = document.querySelector("#device-form-user-agent input");
|
||||
const touchInput = document.querySelector("#device-form-touch input");
|
||||
|
||||
is(nameInput.value, expected.name, "Device name matches");
|
||||
is(parseInt(widthInput.value, 10), expected.width, "Width matches");
|
||||
|
|
|
@ -39,14 +39,14 @@ addRDMTask(TEST_URL, async function({ ui }) {
|
|||
await openDeviceModal(ui);
|
||||
|
||||
info("Reveal device adder form");
|
||||
let adderShow = document.querySelector("#device-adder-show");
|
||||
let adderShow = document.querySelector("#device-add-button");
|
||||
adderShow.click();
|
||||
|
||||
info("Add test device 1");
|
||||
await addDeviceInModal(ui, device1);
|
||||
|
||||
info("Reveal device adder form");
|
||||
adderShow = document.querySelector("#device-adder-show");
|
||||
adderShow = document.querySelector("#device-add-button");
|
||||
adderShow.click();
|
||||
|
||||
info("Add test device 2");
|
||||
|
|
|
@ -480,12 +480,12 @@ function addDeviceInModal(ui, device) {
|
|||
ui.toolWindow.require("devtools/client/shared/vendor/react-dom-test-utils");
|
||||
const { document, store } = ui.toolWindow;
|
||||
|
||||
const nameInput = document.querySelector("#device-adder-name input");
|
||||
const nameInput = document.querySelector("#device-form-name input");
|
||||
const [ widthInput, heightInput ] =
|
||||
document.querySelectorAll("#device-adder-size input");
|
||||
const pixelRatioInput = document.querySelector("#device-adder-pixel-ratio input");
|
||||
const userAgentInput = document.querySelector("#device-adder-user-agent input");
|
||||
const touchInput = document.querySelector("#device-adder-touch input");
|
||||
document.querySelectorAll("#device-form-size input");
|
||||
const pixelRatioInput = document.querySelector("#device-form-pixel-ratio input");
|
||||
const userAgentInput = document.querySelector("#device-form-user-agent input");
|
||||
const touchInput = document.querySelector("#device-form-touch input");
|
||||
|
||||
nameInput.value = device.name;
|
||||
Simulate.change(nameInput);
|
||||
|
@ -503,7 +503,7 @@ function addDeviceInModal(ui, device) {
|
|||
Simulate.change(touchInput);
|
||||
|
||||
const existingCustomDevices = store.getState().devices.custom.length;
|
||||
const adderSave = document.querySelector("#device-adder-save");
|
||||
const adderSave = document.querySelector("#device-form-save");
|
||||
const saved = waitUntilState(store, state =>
|
||||
state.devices.custom.length == existingCustomDevices + 1
|
||||
);
|
||||
|
|
Загрузка…
Ссылка в новой задаче