зеркало из https://github.com/mozilla/gecko-dev.git
Backed out 19 changesets (bug 1467572) for devtools failures on browser_net_telemetry_throttle_changed.js. CLOSED TREE
Backed out changeset 39123899178c (bug 1467572) Backed out changeset 62fcbe25665c (bug 1467572) Backed out changeset 5ef6c1c42747 (bug 1467572) Backed out changeset e295be61276e (bug 1467572) Backed out changeset 41d85a6f8a2a (bug 1467572) Backed out changeset 4e6b95a6c506 (bug 1467572) Backed out changeset 36d459a24020 (bug 1467572) Backed out changeset abb52c2c68ab (bug 1467572) Backed out changeset 470b9ce4ba0f (bug 1467572) Backed out changeset 37609995dc8f (bug 1467572) Backed out changeset 636bf5ce96f7 (bug 1467572) Backed out changeset 5880a55d2ee8 (bug 1467572) Backed out changeset 0f19f84bb2ed (bug 1467572) Backed out changeset e83526778ccd (bug 1467572) Backed out changeset c42448ca6e4a (bug 1467572) Backed out changeset 934fb24dad26 (bug 1467572) Backed out changeset 6102b9ef805b (bug 1467572) Backed out changeset 7aaea1245d27 (bug 1467572) Backed out changeset 7793f8a2b14f (bug 1467572) --HG-- rename : devtools/client/shared/components/menu/utils.js => devtools/client/netmonitor/src/utils/menu.js rename : devtools/client/responsive.html/components/App.js => devtools/client/responsive.html/app.js rename : devtools/client/responsive.html/components/DevicePixelRatioMenu.js => devtools/client/responsive.html/components/DevicePixelRatioSelector.js rename : devtools/client/responsive.html/components/Toolbar.js => devtools/client/responsive.html/components/GlobalToolbar.js rename : devtools/client/responsive.html/components/SettingsMenu.js => devtools/client/responsive.html/components/ReloadConditions.js rename : devtools/client/shared/components/throttling/NetworkThrottlingMenu.js => devtools/client/shared/components/throttling/NetworkThrottlingSelector.js
This commit is contained in:
Родитель
702d2b2570
Коммит
e67c081821
|
@ -27,6 +27,10 @@ let whitelist = [
|
|||
{sourceName: /highlighters\.css$/i,
|
||||
errorMessage: /Unknown pseudo-class.*moz-native-anonymous/i,
|
||||
isFromDevTools: true},
|
||||
// Responsive Design Mode CSS uses a UA-only pseudo-class, see Bug 1241714.
|
||||
{sourceName: /responsive-ua\.css$/i,
|
||||
errorMessage: /Unknown pseudo-class.*moz-dropdown-list/i,
|
||||
isFromDevTools: true},
|
||||
// UA-only media features.
|
||||
{sourceName: /\b(autocomplete-item|svg)\.css$/,
|
||||
errorMessage: /Expected media feature name but found \u2018-moz.*/i,
|
||||
|
|
|
@ -34,14 +34,14 @@ class ThreePaneOnboardingTooltip {
|
|||
this.onLearnMoreLinkClick = this.onLearnMoreLinkClick.bind(this);
|
||||
|
||||
const container = doc.createElementNS(XHTML_NS, "div");
|
||||
container.className = "onboarding-container";
|
||||
container.className = "three-pane-onboarding-container";
|
||||
|
||||
const icon = doc.createElementNS(XHTML_NS, "span");
|
||||
icon.className = "onboarding-icon";
|
||||
icon.className = "three-pane-onboarding-icon";
|
||||
container.appendChild(icon);
|
||||
|
||||
const content = doc.createElementNS(XHTML_NS, "div");
|
||||
content.className = "onboarding-content";
|
||||
content.className = "three-pane-onboarding-content";
|
||||
container.appendChild(content);
|
||||
|
||||
const message = doc.createElementNS(XHTML_NS, "div");
|
||||
|
@ -53,7 +53,7 @@ class ThreePaneOnboardingTooltip {
|
|||
message.append(messageString.substring(0, learnMoreStartIndex));
|
||||
|
||||
this.learnMoreLink = doc.createElementNS(XHTML_NS, "a");
|
||||
this.learnMoreLink.className = "onboarding-link";
|
||||
this.learnMoreLink.className = "three-pane-onboarding-link";
|
||||
this.learnMoreLink.href = "#";
|
||||
this.learnMoreLink.textContent = learnMoreString;
|
||||
|
||||
|
@ -62,7 +62,7 @@ class ThreePaneOnboardingTooltip {
|
|||
content.append(message);
|
||||
|
||||
this.closeButton = doc.createElementNS(XHTML_NS, "button");
|
||||
this.closeButton.className = "onboarding-close-button devtools-button";
|
||||
this.closeButton.className = "three-pane-onboarding-close-button devtools-button";
|
||||
container.appendChild(this.closeButton);
|
||||
|
||||
this.closeButton.addEventListener("click", this.onCloseButtonClick);
|
||||
|
|
|
@ -265,7 +265,6 @@ devtools.jar:
|
|||
skin/images/read-only.svg (themes/images/read-only.svg)
|
||||
skin/images/reveal.svg (themes/images/reveal.svg)
|
||||
skin/images/select-arrow.svg (themes/images/select-arrow.svg)
|
||||
skin/images/settings.svg (themes/images/settings.svg)
|
||||
|
||||
# Debugger
|
||||
skin/images/debugger/angular.svg (themes/images/debugger/angular.svg)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
# 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/.
|
||||
|
||||
# LOCALIZATION NOTE These strings are used inside the NetworkThrottlingMenu
|
||||
# LOCALIZATION NOTE These strings are used inside the NetworkThrottlingSelector
|
||||
# component used to throttle network bandwidth.
|
||||
#
|
||||
# The correct localization of this file might be to keep it in
|
||||
|
|
|
@ -11,32 +11,44 @@
|
|||
# A good criteria is the language in which you'd find the best
|
||||
# documentation on web development on the web.
|
||||
|
||||
# LOCALIZATION NOTE (responsive.editDeviceList2): Context menu item displayed in the
|
||||
# device selector.
|
||||
responsive.editDeviceList2=Edit List…
|
||||
# LOCALIZATION NOTE (responsive.editDeviceList): option displayed in the device
|
||||
# selector
|
||||
responsive.editDeviceList=Edit list…
|
||||
|
||||
# LOCALIZATION NOTE (responsive.exit): Tooltip text of the exit button.
|
||||
# LOCALIZATION NOTE (responsive.exit): tooltip text of the exit button.
|
||||
responsive.exit=Close Responsive Design Mode
|
||||
|
||||
# LOCALIZATION NOTE (responsive.rotate): Tooltip text of the rotate button.
|
||||
# LOCALIZATION NOTE (responsive.rotate): tooltip text of the rotate button.
|
||||
responsive.rotate=Rotate viewport
|
||||
|
||||
# LOCALIZATION NOTE (responsive.done): Button text in the device list modal
|
||||
# LOCALIZATION NOTE (responsive.deviceListLoading): placeholder text for
|
||||
# device selector when it's still fetching devices
|
||||
responsive.deviceListLoading=Loading…
|
||||
|
||||
# LOCALIZATION NOTE (responsive.deviceListError): placeholder text for
|
||||
# device selector when an error occurred
|
||||
responsive.deviceListError=No list available
|
||||
|
||||
# LOCALIZATION NOTE (responsive.done): button text in the device list modal
|
||||
responsive.done=Done
|
||||
|
||||
# LOCALIZATION NOTE (responsive.responsiveMode): Placeholder text for the
|
||||
# device selector.
|
||||
responsive.responsiveMode=Responsive
|
||||
# LOCALIZATION NOTE (responsive.noDeviceSelected): placeholder text for the
|
||||
# device selector
|
||||
responsive.noDeviceSelected=no device selected
|
||||
|
||||
# LOCALIZATION NOTE (responsive.enableTouch): Tooltip text for the touch
|
||||
# simulation button when it's disabled.
|
||||
# LOCALIZATION NOTE (responsive.title): the title displayed in the global
|
||||
# toolbar
|
||||
responsive.title=Responsive Design Mode
|
||||
|
||||
# LOCALIZATION NOTE (responsive.enableTouch): tooltip text for the touch
|
||||
# simulation button when it's disabled
|
||||
responsive.enableTouch=Enable touch simulation
|
||||
|
||||
# LOCALIZATION NOTE (responsive.disableTouch): Tooltip text for the touch
|
||||
# simulation button when it's enabled.
|
||||
# LOCALIZATION NOTE (responsive.disableTouch): tooltip text for the touch
|
||||
# simulation button when it's enabled
|
||||
responsive.disableTouch=Disable touch simulation
|
||||
|
||||
# LOCALIZATION NOTE (responsive.screenshot): Tooltip of the screenshot button.
|
||||
# LOCALIZATION NOTE (responsive.screenshot): tooltip of the screenshot button.
|
||||
responsive.screenshot=Take a screenshot of the viewport
|
||||
|
||||
# LOCALIZATION NOTE (responsive.screenshotGeneratedFilename): The auto generated
|
||||
|
@ -50,11 +62,11 @@ responsive.screenshotGeneratedFilename=Screen Shot %1$S at %2$S
|
|||
# non-remote tab.
|
||||
responsive.remoteOnly=Responsive Design Mode is only available for remote browser tabs, such as those used for web content in multi-process Firefox.
|
||||
|
||||
# LOCALIZATION NOTE (responsive.changeDevicePixelRatio): Tooltip for the
|
||||
# LOCALIZATION NOTE (responsive.changeDevicePixelRatio): tooltip for the
|
||||
# device pixel ratio dropdown when is enabled.
|
||||
responsive.changeDevicePixelRatio=Change device pixel ratio of the viewport
|
||||
|
||||
# LOCALIZATION NOTE (responsive.devicePixelRatio.auto): Tooltip for the device pixel ratio
|
||||
# LOCALIZATION NOTE (responsive.devicePixelRatio.auto): tooltip for the device pixel ratio
|
||||
# dropdown when it is disabled because a device is selected.
|
||||
# The argument (%1$S) is the selected device (e.g. iPhone 6) that set
|
||||
# automatically the device pixel ratio value.
|
||||
|
@ -116,6 +128,14 @@ responsive.deviceDetails=Size: %1$S x %2$S\nDPR: %3$S\nUA: %4$S\nTouch: %5$S
|
|||
# the device pixel ratio. %1$S is the devicePixelRatio value of the device.
|
||||
responsive.devicePixelRatioOption=DPR: %1$S
|
||||
|
||||
# LOCALIZATION NOTE (responsive.reloadConditions.label): Label on button to open a menu
|
||||
# used to choose whether to reload the page automatically when certain actions occur.
|
||||
responsive.reloadConditions.label=Reload when…
|
||||
|
||||
# LOCALIZATION NOTE (responsive.reloadConditions.title): Title on button to open a menu
|
||||
# used to choose whether to reload the page automatically when certain actions occur.
|
||||
responsive.reloadConditions.title=Choose whether to reload the page automatically when certain actions occur
|
||||
|
||||
# LOCALIZATION NOTE (responsive.reloadConditions.touchSimulation): Label on checkbox used
|
||||
# to select whether to reload when touch simulation is toggled.
|
||||
responsive.reloadConditions.touchSimulation=Reload when touch simulation is toggled
|
||||
|
@ -128,12 +148,3 @@ responsive.reloadConditions.userAgent=Reload when user agent is changed
|
|||
# shown on first open to clarify that some features need a reload to apply. %1$S is the
|
||||
# label on the reload conditions menu (responsive.reloadConditions.label).
|
||||
responsive.reloadNotification.description=Device simulation changes require a reload to fully apply. Automatic reloads are disabled by default to avoid losing any changes in DevTools. You can enable reloading via the “%1$S” menu.
|
||||
|
||||
# LOCALIZATION NOTE (responsive.leftAlignViewport): Label on checkbox used in the settings
|
||||
# menu.
|
||||
responsive.leftAlignViewport = Left-align Viewport
|
||||
|
||||
# LOCALIZATION NOTE (responsive.settingOnboarding.content): This is the content shown in
|
||||
# the setting onboarding tooltip that is displayed below the settings menu button in
|
||||
# Responsive Design Mode.
|
||||
responsive.settingOnboarding.content=New: Change to left-alignment or edit reload behavior here.
|
||||
|
|
|
@ -73,13 +73,33 @@
|
|||
background-image: var(--play-icon-url);
|
||||
}
|
||||
|
||||
.devtools-button.devtools-har-button {
|
||||
margin: 0 0 0 2px;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* style for dropdown button */
|
||||
.devtools-drop-down-button {
|
||||
background-image: var(--select-arrow-image) !important;
|
||||
background-repeat: no-repeat !important;
|
||||
margin-inline-start: 6px;
|
||||
fill: var(--theme-toolbar-photon-icon-color);
|
||||
-moz-context-properties: fill;
|
||||
}
|
||||
|
||||
/* style for title holder inside a dropdown button */
|
||||
.devtools-drop-down-button .title {
|
||||
padding-top: 0.15em;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
/* HAR button */
|
||||
|
||||
#devtools-har-button {
|
||||
width: 35px;
|
||||
margin-inline-start: 2px;
|
||||
padding-inline-start: 0;
|
||||
padding-inline-end: 12px;
|
||||
padding-right: 12px;
|
||||
background-position: right center;
|
||||
}
|
||||
|
||||
|
@ -88,10 +108,8 @@
|
|||
width: 24px;
|
||||
}
|
||||
|
||||
/* Throttling Button */
|
||||
|
||||
#network-throttling-menu {
|
||||
margin-inline-start: 6px;
|
||||
#devtools-har-button:not(:hover) {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.devtools-checkbox {
|
||||
|
@ -114,6 +132,24 @@
|
|||
margin-inline-end: 7px;
|
||||
}
|
||||
|
||||
/* Throttling Button */
|
||||
|
||||
#global-network-throttling-selector:not(:hover) {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
#global-network-throttling-selector {
|
||||
width: 92px;
|
||||
background-position: right 4px center;
|
||||
padding-left: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Make sure spacing between text and icon is uniform*/
|
||||
#global-network-throttling-selector .title{
|
||||
width: 85%;
|
||||
}
|
||||
|
||||
/* Filter input within the Toolbar */
|
||||
|
||||
.devtools-toolbar-group .devtools-filterinput {
|
||||
|
|
|
@ -17,6 +17,7 @@ const {
|
|||
getTypeFilteredRequests,
|
||||
} = require("../selectors/index");
|
||||
const { autocompleteProvider } = require("../utils/filter-autocomplete-provider");
|
||||
const { LocalizationHelper } = require("devtools/shared/l10n");
|
||||
const { L10N } = require("../utils/l10n");
|
||||
const { fetchNetworkUpdatePacket } = require("../utils/request-utils");
|
||||
|
||||
|
@ -27,7 +28,6 @@ const {
|
|||
const LEARN_MORE_URL = getFilterBoxURL();
|
||||
|
||||
// Components
|
||||
const NetworkThrottlingMenu = createFactory(require("devtools/client/shared/components/throttling/NetworkThrottlingMenu"));
|
||||
const SearchBox = createFactory(require("devtools/client/shared/components/SearchBox"));
|
||||
|
||||
const { button, div, input, label, span } = dom;
|
||||
|
@ -51,13 +51,17 @@ const ENABLE_PERSISTENT_LOGS_LABEL =
|
|||
L10N.getStr("netmonitor.toolbar.enablePersistentLogs.label");
|
||||
const DISABLE_CACHE_TOOLTIP = L10N.getStr("netmonitor.toolbar.disableCache.tooltip");
|
||||
const DISABLE_CACHE_LABEL = L10N.getStr("netmonitor.toolbar.disableCache.label");
|
||||
const NO_THROTTLING_LABEL = new LocalizationHelper(
|
||||
"devtools/client/locales/network-throttling.properties"
|
||||
).getStr("responsive.noThrottling");
|
||||
|
||||
// Menu
|
||||
loader.lazyRequireGetter(this, "showMenu", "devtools/client/shared/components/menu/utils", true);
|
||||
loader.lazyRequireGetter(this, "showMenu", "devtools/client/netmonitor/src/utils/menu", true);
|
||||
loader.lazyRequireGetter(this, "HarMenuUtils", "devtools/client/netmonitor/src/har/har-menu-utils", true);
|
||||
|
||||
// Throttling
|
||||
const Types = require("devtools/client/shared/components/throttling/types");
|
||||
const throttlingProfiles = require("devtools/client/shared/components/throttling/profiles");
|
||||
const { changeNetworkThrottling } = require("devtools/client/shared/components/throttling/actions");
|
||||
|
||||
/**
|
||||
|
@ -278,18 +282,54 @@ class Toolbar extends Component {
|
|||
}
|
||||
|
||||
/**
|
||||
* Render network throttling menu button.
|
||||
* Render network throttling selector button.
|
||||
*/
|
||||
renderThrottlingMenu() {
|
||||
renderThrottlingSelector() {
|
||||
const {
|
||||
networkThrottling,
|
||||
} = this.props;
|
||||
|
||||
const selectedProfile = networkThrottling.enabled ?
|
||||
networkThrottling.profile : NO_THROTTLING_LABEL;
|
||||
return button({
|
||||
id: "global-network-throttling-selector",
|
||||
title: selectedProfile,
|
||||
className: "devtools-button devtools-drop-down-button",
|
||||
onClick: evt => {
|
||||
this.showThrottlingSelector(evt.target);
|
||||
},
|
||||
},
|
||||
dom.span({className: "title"},
|
||||
selectedProfile)
|
||||
);
|
||||
}
|
||||
|
||||
showThrottlingSelector(menuButton) {
|
||||
const {
|
||||
networkThrottling,
|
||||
onChangeNetworkThrottling,
|
||||
} = this.props;
|
||||
|
||||
return NetworkThrottlingMenu({
|
||||
networkThrottling,
|
||||
onChangeNetworkThrottling,
|
||||
const menuItems = throttlingProfiles.map(profile => {
|
||||
return {
|
||||
label: profile.id,
|
||||
type: "checkbox",
|
||||
checked: networkThrottling.enabled &&
|
||||
(profile.id == networkThrottling.profile),
|
||||
click: () => onChangeNetworkThrottling(true, profile.id),
|
||||
};
|
||||
});
|
||||
|
||||
menuItems.unshift("-");
|
||||
|
||||
menuItems.unshift({
|
||||
label: NO_THROTTLING_LABEL,
|
||||
type: "checkbox",
|
||||
checked: !networkThrottling.enabled,
|
||||
click: () => onChangeNetworkThrottling(false, ""),
|
||||
});
|
||||
|
||||
showMenu(menuItems, { button: menuButton });
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -299,7 +339,7 @@ class Toolbar extends Component {
|
|||
return button({
|
||||
id: "devtools-har-button",
|
||||
title: TOOLBAR_HAR_BUTTON,
|
||||
className: "devtools-button devtools-dropdown-button",
|
||||
className: "devtools-button devtools-har-button devtools-drop-down-button",
|
||||
onClick: evt => {
|
||||
this.showHarMenu(evt.target);
|
||||
},
|
||||
|
@ -398,7 +438,7 @@ class Toolbar extends Component {
|
|||
this.renderPersistlogCheckbox(persistentLogsEnabled, togglePersistentLogs),
|
||||
this.renderCacheCheckbox(browserCacheDisabled, toggleBrowserCache),
|
||||
this.renderSeparator(),
|
||||
this.renderThrottlingMenu(),
|
||||
this.renderThrottlingSelector(),
|
||||
this.renderHarButton(),
|
||||
)
|
||||
)
|
||||
|
@ -414,7 +454,7 @@ class Toolbar extends Component {
|
|||
this.renderPersistlogCheckbox(persistentLogsEnabled, togglePersistentLogs),
|
||||
this.renderCacheCheckbox(browserCacheDisabled, toggleBrowserCache),
|
||||
this.renderSeparator(),
|
||||
this.renderThrottlingMenu(),
|
||||
this.renderThrottlingSelector(),
|
||||
this.renderHarButton(),
|
||||
),
|
||||
span({ className: "devtools-toolbar-group devtools-toolbar-two-rows-2" },
|
||||
|
|
|
@ -7,23 +7,14 @@
|
|||
const Menu = require("devtools/client/framework/menu");
|
||||
const MenuItem = require("devtools/client/framework/menu-item");
|
||||
|
||||
loader.lazyRequireGetter(this, "getTopLevelWindow", "devtools/client/responsive.html/utils/window", true);
|
||||
|
||||
/**
|
||||
* Helper function for opening context menu.
|
||||
*
|
||||
* @param {Array} items
|
||||
* List of menu items.
|
||||
* @param {Array} items List of menu items.
|
||||
* @param {Object} options:
|
||||
* @property {Element} button
|
||||
* Button element used to open the menu.
|
||||
* @property {Number} screenX
|
||||
* Screen x coordinate of the menu on the screen.
|
||||
* @property {Number} screenY
|
||||
* Screen y coordinate of the menu on the screen.
|
||||
* @property {Boolean} useTopLevelWindow
|
||||
* Whether or not the top level window needs to be fetched. This option is used
|
||||
* by RDM.
|
||||
* @property {Number} screenX coordinate of the menu on the screen
|
||||
* @property {Number} screenY coordinate of the menu on the screen
|
||||
* @property {Object} button parent used to open the menu
|
||||
*/
|
||||
function showMenu(items, options) {
|
||||
if (items.length === 0) {
|
||||
|
@ -64,14 +55,7 @@ function showMenu(items, options) {
|
|||
screenY = rect.bottom + defaultView.mozInnerScreenY;
|
||||
}
|
||||
|
||||
let doc;
|
||||
if (options.useTopLevelWindow) {
|
||||
doc = getTopLevelWindow(window).document;
|
||||
} else {
|
||||
doc = window.parent.document;
|
||||
}
|
||||
|
||||
menu.popup(screenX, screenY, { doc });
|
||||
menu.popup(screenX, screenY, { doc: window.parent.document });
|
||||
}
|
||||
|
||||
module.exports = {
|
|
@ -15,6 +15,7 @@ DevToolsModules(
|
|||
'headers-provider.js',
|
||||
'l10n.js',
|
||||
'mdn-utils.js',
|
||||
'menu.js',
|
||||
'open-request-in-tab.js',
|
||||
'prefs.js',
|
||||
'request-utils.js',
|
||||
|
|
|
@ -17,7 +17,7 @@ const {
|
|||
loader.lazyRequireGetter(this, "Curl", "devtools/client/shared/curl", true);
|
||||
loader.lazyRequireGetter(this, "saveAs", "devtools/client/shared/file-saver", true);
|
||||
loader.lazyRequireGetter(this, "copyString", "devtools/shared/platform/clipboard", true);
|
||||
loader.lazyRequireGetter(this, "showMenu", "devtools/client/shared/components/menu/utils", true);
|
||||
loader.lazyRequireGetter(this, "showMenu", "devtools/client/netmonitor/src/utils/menu", true);
|
||||
loader.lazyRequireGetter(this, "openRequestInTab", "devtools/client/netmonitor/src/utils/firefox/open-request-in-tab", true);
|
||||
loader.lazyRequireGetter(this, "HarMenuUtils", "devtools/client/netmonitor/src/har/har-menu-utils", true);
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const { showMenu } = require("devtools/client/shared/components/menu/utils");
|
||||
const { showMenu } = require("devtools/client/netmonitor/src/utils/menu");
|
||||
const { HEADERS } = require("../constants");
|
||||
const { L10N } = require("../utils/l10n");
|
||||
|
||||
|
|
|
@ -73,8 +73,7 @@ const webpackConfig = {
|
|||
|
||||
"devtools/client/framework/devtools": path.join(__dirname, "../../client/shared/webpack/shims/framework-devtools-shim"),
|
||||
"devtools/client/framework/menu": "devtools-modules/src/menu",
|
||||
|
||||
"devtools/client/shared/components/menu/utils": "devtools-contextmenu",
|
||||
"devtools/client/netmonitor/src/utils/menu": "devtools-contextmenu",
|
||||
|
||||
"devtools/client/shared/vendor/react": "react",
|
||||
"devtools/client/shared/vendor/react-dom": "react-dom",
|
||||
|
|
|
@ -310,20 +310,12 @@ pref("devtools.editor.detectindentation", true);
|
|||
pref("devtools.editor.enableCodeFolding", true);
|
||||
pref("devtools.editor.autocomplete", true);
|
||||
|
||||
// Whether or not the viewports are left aligned.
|
||||
pref("devtools.responsive.leftAlignViewport.enabled", false);
|
||||
// Whether to reload when touch simulation is toggled
|
||||
pref("devtools.responsive.reloadConditions.touchSimulation", false);
|
||||
// Whether to reload when user agent is changed
|
||||
pref("devtools.responsive.reloadConditions.userAgent", false);
|
||||
// Whether to show the notification about reloading to apply emulation
|
||||
pref("devtools.responsive.reloadNotification.enabled", true);
|
||||
// Whether to show the settings onboarding tooltip only in release or beta builds.
|
||||
#if defined(RELEASE_OR_BETA)
|
||||
pref("devtools.responsive.show-setting-tooltip", true);
|
||||
#else
|
||||
pref("devtools.responsive.show-setting-tooltip", false);
|
||||
#endif
|
||||
|
||||
// Enable new about:debugging.
|
||||
pref("devtools.aboutdebugging.new-enabled", false);
|
||||
|
|
|
@ -81,9 +81,6 @@ createEnum([
|
|||
// Indicates when the screenshot action ends.
|
||||
"TAKE_SCREENSHOT_END",
|
||||
|
||||
// Toggles the left alignment of the viewports.
|
||||
"TOGGLE_LEFT_ALIGNMENT",
|
||||
|
||||
// Update the device display state in the device selector.
|
||||
"UPDATE_DEVICE_DISPLAYED",
|
||||
|
||||
|
|
|
@ -12,6 +12,5 @@ DevToolsModules(
|
|||
'reload-conditions.js',
|
||||
'screenshot.js',
|
||||
'touch-simulation.js',
|
||||
'ui.js',
|
||||
'viewports.js',
|
||||
)
|
||||
|
|
|
@ -12,7 +12,7 @@ const {
|
|||
} = require("./index");
|
||||
|
||||
const { getFormatStr } = require("../utils/l10n");
|
||||
const { getTopLevelWindow } = require("../utils/window");
|
||||
const { getToplevelWindow } = require("../utils/window");
|
||||
const e10s = require("../utils/e10s");
|
||||
const Services = require("Services");
|
||||
|
||||
|
@ -40,7 +40,7 @@ function createScreenshotFor(node) {
|
|||
}
|
||||
|
||||
function saveToFile(data, filename) {
|
||||
const chromeWindow = getTopLevelWindow(window);
|
||||
const chromeWindow = getToplevelWindow(window);
|
||||
const chromeDocument = chromeWindow.document;
|
||||
|
||||
// append .png extension to filename if it doesn't exist
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
/* 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 {
|
||||
TOGGLE_LEFT_ALIGNMENT,
|
||||
} = require("./index");
|
||||
|
||||
module.exports = {
|
||||
|
||||
toggleLeftAlignment(enabled) {
|
||||
return {
|
||||
type: TOGGLE_LEFT_ALIGNMENT,
|
||||
enabled,
|
||||
};
|
||||
},
|
||||
|
||||
};
|
|
@ -11,31 +11,28 @@ const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
|||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
const { connect } = require("devtools/client/shared/vendor/react-redux");
|
||||
|
||||
const DeviceModal = createFactory(require("./DeviceModal"));
|
||||
const Toolbar = createFactory(require("./Toolbar"));
|
||||
const Viewports = createFactory(require("./Viewports"));
|
||||
|
||||
const {
|
||||
addCustomDevice,
|
||||
removeCustomDevice,
|
||||
updateDeviceDisplayed,
|
||||
updateDeviceModal,
|
||||
updatePreferredDevices,
|
||||
} = require("../actions/devices");
|
||||
} = require("./actions/devices");
|
||||
const { changeNetworkThrottling } = require("devtools/client/shared/components/throttling/actions");
|
||||
const { changeReloadCondition } = require("../actions/reload-conditions");
|
||||
const { takeScreenshot } = require("../actions/screenshot");
|
||||
const { changeTouchSimulation } = require("../actions/touch-simulation");
|
||||
const { toggleLeftAlignment } = require("../actions/ui");
|
||||
const { changeReloadCondition } = require("./actions/reload-conditions");
|
||||
const { takeScreenshot } = require("./actions/screenshot");
|
||||
const { changeTouchSimulation } = require("./actions/touch-simulation");
|
||||
const {
|
||||
changeDevice,
|
||||
changePixelRatio,
|
||||
removeDeviceAssociation,
|
||||
resizeViewport,
|
||||
rotateViewport,
|
||||
} = require("../actions/viewports");
|
||||
|
||||
const Types = require("../types");
|
||||
} = require("./actions/viewports");
|
||||
const DeviceModal = createFactory(require("./components/DeviceModal"));
|
||||
const GlobalToolbar = createFactory(require("./components/GlobalToolbar"));
|
||||
const Viewports = createFactory(require("./components/Viewports"));
|
||||
const Types = require("./types");
|
||||
|
||||
class App extends Component {
|
||||
static get propTypes() {
|
||||
|
@ -53,7 +50,6 @@ class App extends Component {
|
|||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.onAddCustomDevice = this.onAddCustomDevice.bind(this);
|
||||
this.onBrowserMounted = this.onBrowserMounted.bind(this);
|
||||
this.onChangeDevice = this.onChangeDevice.bind(this);
|
||||
|
@ -69,7 +65,6 @@ class App extends Component {
|
|||
this.onResizeViewport = this.onResizeViewport.bind(this);
|
||||
this.onRotateViewport = this.onRotateViewport.bind(this);
|
||||
this.onScreenshot = this.onScreenshot.bind(this);
|
||||
this.onToggleLeftAlignment = this.onToggleLeftAlignment.bind(this);
|
||||
this.onUpdateDeviceDisplayed = this.onUpdateDeviceDisplayed.bind(this);
|
||||
this.onUpdateDeviceModal = this.onUpdateDeviceModal.bind(this);
|
||||
}
|
||||
|
@ -164,10 +159,6 @@ class App extends Component {
|
|||
this.props.dispatch(takeScreenshot());
|
||||
}
|
||||
|
||||
onToggleLeftAlignment() {
|
||||
this.props.dispatch(toggleLeftAlignment());
|
||||
}
|
||||
|
||||
onUpdateDeviceDisplayed(device, deviceType, displayed) {
|
||||
this.props.dispatch(updateDeviceDisplayed(device, deviceType, displayed));
|
||||
}
|
||||
|
@ -203,17 +194,17 @@ class App extends Component {
|
|||
onResizeViewport,
|
||||
onRotateViewport,
|
||||
onScreenshot,
|
||||
onToggleLeftAlignment,
|
||||
onUpdateDeviceDisplayed,
|
||||
onUpdateDeviceModal,
|
||||
} = this;
|
||||
|
||||
if (!viewports.length) {
|
||||
return null;
|
||||
}
|
||||
let selectedDevice = "";
|
||||
let selectedPixelRatio = { value: 0 };
|
||||
|
||||
const selectedDevice = viewports[0].device;
|
||||
const selectedPixelRatio = viewports[0].pixelRatio;
|
||||
if (viewports.length) {
|
||||
selectedDevice = viewports[0].device;
|
||||
selectedPixelRatio = viewports[0].pixelRatio;
|
||||
}
|
||||
|
||||
let deviceAdderViewportTemplate = {};
|
||||
if (devices.modalOpenedFromViewport !== null) {
|
||||
|
@ -224,7 +215,7 @@ class App extends Component {
|
|||
{
|
||||
id: "app",
|
||||
},
|
||||
Toolbar({
|
||||
GlobalToolbar({
|
||||
devices,
|
||||
displayPixelRatio,
|
||||
networkThrottling,
|
||||
|
@ -233,27 +224,24 @@ class App extends Component {
|
|||
selectedDevice,
|
||||
selectedPixelRatio,
|
||||
touchSimulation,
|
||||
viewport: viewports[0],
|
||||
onChangeDevice,
|
||||
onChangeNetworkThrottling,
|
||||
onChangePixelRatio,
|
||||
onChangeReloadCondition,
|
||||
onChangeTouchSimulation,
|
||||
onExit,
|
||||
onRemoveDeviceAssociation,
|
||||
onResizeViewport,
|
||||
onRotateViewport,
|
||||
onScreenshot,
|
||||
onToggleLeftAlignment,
|
||||
onUpdateDeviceModal,
|
||||
}),
|
||||
Viewports({
|
||||
devices,
|
||||
screenshot,
|
||||
viewports,
|
||||
onBrowserMounted,
|
||||
onChangeDevice,
|
||||
onContentResize,
|
||||
onRemoveDeviceAssociation,
|
||||
onRotateViewport,
|
||||
onResizeViewport,
|
||||
onUpdateDeviceModal,
|
||||
}),
|
||||
DeviceModal({
|
||||
deviceAdderViewportTemplate,
|
|
@ -9,12 +9,12 @@
|
|||
const Services = require("Services");
|
||||
const flags = require("devtools/shared/flags");
|
||||
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 dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
|
||||
const e10s = require("../utils/e10s");
|
||||
const message = require("../utils/message");
|
||||
const { getTopLevelWindow } = require("../utils/window");
|
||||
const { getToplevelWindow } = require("../utils/window");
|
||||
|
||||
const FRAME_SCRIPT = "resource://devtools/client/responsive.html/browser/content.js";
|
||||
|
||||
|
@ -114,7 +114,7 @@ class Browser extends PureComponent {
|
|||
mm.loadFrameScript(FRAME_SCRIPT, true);
|
||||
await ready;
|
||||
|
||||
const browserWindow = getTopLevelWindow(window);
|
||||
const browserWindow = getToplevelWindow(window);
|
||||
const requiresFloatingScrollbars =
|
||||
!browserWindow.matchMedia("(-moz-overlay-scrollbars)").matches;
|
||||
|
||||
|
|
|
@ -6,14 +6,13 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react");
|
||||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
const { PureComponent, createFactory } = require("devtools/client/shared/vendor/react");
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
|
||||
const ViewportDimension = createFactory(require("./ViewportDimension.js"));
|
||||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
|
||||
const { getFormatStr, getStr } = require("../utils/l10n");
|
||||
const Types = require("../types");
|
||||
const ViewportDimension = createFactory(require("./ViewportDimension.js"));
|
||||
|
||||
class DeviceAdder extends PureComponent {
|
||||
static get propTypes() {
|
||||
|
@ -26,9 +25,7 @@ class DeviceAdder extends PureComponent {
|
|||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {};
|
||||
|
||||
this.onChangeSize = this.onChangeSize.bind(this);
|
||||
this.onDeviceAdderShow = this.onDeviceAdderShow.bind(this);
|
||||
this.onDeviceAdderSave = this.onDeviceAdderSave.bind(this);
|
||||
|
@ -46,7 +43,7 @@ class DeviceAdder extends PureComponent {
|
|||
});
|
||||
}
|
||||
|
||||
onChangeSize(_, width, height) {
|
||||
onChangeSize(width, height) {
|
||||
this.setState({
|
||||
width,
|
||||
height,
|
||||
|
@ -181,7 +178,7 @@ class DeviceAdder extends PureComponent {
|
|||
width,
|
||||
height,
|
||||
},
|
||||
onResizeViewport: this.onChangeSize,
|
||||
onChangeSize: this.onChangeSize,
|
||||
onRemoveDeviceAssociation: () => {},
|
||||
})
|
||||
),
|
||||
|
|
|
@ -6,14 +6,13 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const { createFactory, PureComponent } = require("devtools/client/shared/vendor/react");
|
||||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
const { PureComponent, createFactory } = require("devtools/client/shared/vendor/react");
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
|
||||
const DeviceAdder = createFactory(require("./DeviceAdder"));
|
||||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
|
||||
const { getStr, getFormatStr } = require("../utils/l10n");
|
||||
const Types = require("../types");
|
||||
const DeviceAdder = createFactory(require("./DeviceAdder"));
|
||||
|
||||
class DeviceModal extends PureComponent {
|
||||
static get propTypes() {
|
||||
|
@ -30,9 +29,7 @@ class DeviceModal extends PureComponent {
|
|||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {};
|
||||
|
||||
this.onAddCustomDevice = this.onAddCustomDevice.bind(this);
|
||||
this.onDeviceCheckboxChange = this.onDeviceCheckboxChange.bind(this);
|
||||
this.onDeviceModalSubmit = this.onDeviceModalSubmit.bind(this);
|
||||
|
@ -155,11 +152,11 @@ class DeviceModal extends PureComponent {
|
|||
},
|
||||
dom.div(
|
||||
{
|
||||
className: "device-modal",
|
||||
className: "device-modal container",
|
||||
},
|
||||
dom.button({
|
||||
id: "device-close-button",
|
||||
className: "devtools-button",
|
||||
className: "toolbar-button devtools-button",
|
||||
onClick: () => onUpdateDeviceModal(false),
|
||||
}),
|
||||
dom.div(
|
||||
|
@ -187,7 +184,7 @@ class DeviceModal extends PureComponent {
|
|||
let removeDeviceButton;
|
||||
if (type == "custom") {
|
||||
removeDeviceButton = dom.button({
|
||||
className: "device-remove-button devtools-button",
|
||||
className: "device-remove-button toolbar-button devtools-button",
|
||||
onClick: () => onRemoveCustomDevice(device),
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,93 +0,0 @@
|
|||
/* 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 { getStr, getFormatStr } = require("../utils/l10n");
|
||||
const Types = require("../types");
|
||||
|
||||
loader.lazyRequireGetter(this, "showMenu", "devtools/client/shared/components/menu/utils", true);
|
||||
|
||||
const PIXEL_RATIO_PRESET = [1, 2, 3];
|
||||
|
||||
class DevicePixelRatioMenu extends PureComponent {
|
||||
static get propTypes() {
|
||||
return {
|
||||
devices: PropTypes.shape(Types.devices).isRequired,
|
||||
displayPixelRatio: Types.pixelRatio.value.isRequired,
|
||||
selectedDevice: PropTypes.string.isRequired,
|
||||
selectedPixelRatio: PropTypes.shape(Types.pixelRatio).isRequired,
|
||||
onChangePixelRatio: PropTypes.func.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.onShowDevicePixelMenu = this.onShowDevicePixelMenu.bind(this);
|
||||
}
|
||||
|
||||
onShowDevicePixelMenu(event) {
|
||||
const {
|
||||
displayPixelRatio,
|
||||
onChangePixelRatio,
|
||||
} = this.props;
|
||||
|
||||
const menuItems = PIXEL_RATIO_PRESET.map(value => {
|
||||
return {
|
||||
label: getFormatStr("responsive.devicePixelRatioOption", value),
|
||||
type: "checkbox",
|
||||
checked: displayPixelRatio === value,
|
||||
click: () => onChangePixelRatio(+value),
|
||||
};
|
||||
});
|
||||
|
||||
showMenu(menuItems, {
|
||||
button: event.target,
|
||||
useTopLevelWindow: true,
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
devices,
|
||||
displayPixelRatio,
|
||||
selectedDevice,
|
||||
selectedPixelRatio,
|
||||
} = this.props;
|
||||
|
||||
const isDisabled = devices.listState !== Types.loadableState.LOADED ||
|
||||
selectedDevice !== "";
|
||||
|
||||
let title;
|
||||
if (isDisabled) {
|
||||
title = getFormatStr("responsive.devicePixelRatio.auto", selectedDevice);
|
||||
} else {
|
||||
title = getStr("responsive.changeDevicePixelRatio");
|
||||
}
|
||||
|
||||
return (
|
||||
dom.button(
|
||||
{
|
||||
id: "device-pixel-ratio-menu",
|
||||
className: "devtools-button devtools-dropdown-button",
|
||||
disabled: isDisabled,
|
||||
title,
|
||||
onClick: this.onShowDevicePixelMenu,
|
||||
},
|
||||
dom.span({ className: "title" },
|
||||
getFormatStr("responsive.devicePixelRatioOption",
|
||||
selectedPixelRatio.value || displayPixelRatio)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = DevicePixelRatioMenu;
|
|
@ -0,0 +1,136 @@
|
|||
/* 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 Types = require("../types");
|
||||
const { getStr, getFormatStr } = require("../utils/l10n");
|
||||
const labelForOption = value => getFormatStr("responsive.devicePixelRatioOption", value);
|
||||
|
||||
const PIXEL_RATIO_PRESET = [1, 2, 3];
|
||||
|
||||
const createVisibleOption = value => {
|
||||
const label = labelForOption(value);
|
||||
return dom.option({
|
||||
value,
|
||||
title: label,
|
||||
key: value,
|
||||
}, label);
|
||||
};
|
||||
|
||||
const createHiddenOption = value => {
|
||||
const label = labelForOption(value);
|
||||
return dom.option({
|
||||
value,
|
||||
title: label,
|
||||
hidden: true,
|
||||
disabled: true,
|
||||
}, label);
|
||||
};
|
||||
|
||||
class DevicePixelRatioSelector extends PureComponent {
|
||||
static get propTypes() {
|
||||
return {
|
||||
devices: PropTypes.shape(Types.devices).isRequired,
|
||||
displayPixelRatio: Types.pixelRatio.value.isRequired,
|
||||
selectedDevice: PropTypes.string.isRequired,
|
||||
selectedPixelRatio: PropTypes.shape(Types.pixelRatio).isRequired,
|
||||
onChangePixelRatio: PropTypes.func.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
isFocused: false
|
||||
};
|
||||
|
||||
this.onFocusChange = this.onFocusChange.bind(this);
|
||||
this.onSelectChange = this.onSelectChange.bind(this);
|
||||
}
|
||||
|
||||
onFocusChange({type}) {
|
||||
this.setState({
|
||||
isFocused: type === "focus"
|
||||
});
|
||||
}
|
||||
|
||||
onSelectChange({ target }) {
|
||||
this.props.onChangePixelRatio(+target.value);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
devices,
|
||||
displayPixelRatio,
|
||||
selectedDevice,
|
||||
selectedPixelRatio,
|
||||
} = this.props;
|
||||
|
||||
const hiddenOptions = [];
|
||||
|
||||
for (const type of devices.types) {
|
||||
for (const 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);
|
||||
}
|
||||
|
||||
const state = devices.listState;
|
||||
const isDisabled = (state !== Types.loadableState.LOADED) || (selectedDevice !== "");
|
||||
let selectorClass = "toolbar-dropdown";
|
||||
let title;
|
||||
|
||||
if (isDisabled) {
|
||||
selectorClass += " disabled";
|
||||
title = getFormatStr("responsive.devicePixelRatio.auto", selectedDevice);
|
||||
} else {
|
||||
title = getStr("responsive.changeDevicePixelRatio");
|
||||
|
||||
if (selectedPixelRatio.value) {
|
||||
selectorClass += " selected";
|
||||
}
|
||||
}
|
||||
|
||||
if (this.state.isFocused) {
|
||||
selectorClass += " focused";
|
||||
}
|
||||
|
||||
let listContent = PIXEL_RATIO_PRESET.map(createVisibleOption);
|
||||
|
||||
if (state == Types.loadableState.LOADED) {
|
||||
listContent = listContent.concat(hiddenOptions.map(createHiddenOption));
|
||||
}
|
||||
|
||||
return dom.select(
|
||||
{
|
||||
id: "global-device-pixel-ratio-selector",
|
||||
value: selectedPixelRatio.value || displayPixelRatio,
|
||||
disabled: isDisabled,
|
||||
onChange: this.onSelectChange,
|
||||
onFocus: this.onFocusChange,
|
||||
onBlur: this.onFocusChange,
|
||||
className: selectorClass,
|
||||
title: title
|
||||
},
|
||||
...listContent
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = DevicePixelRatioSelector;
|
|
@ -4,14 +4,13 @@
|
|||
|
||||
"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 { getStr } = require("../utils/l10n");
|
||||
const Types = require("../types");
|
||||
const { PureComponent } = require("devtools/client/shared/vendor/react");
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
|
||||
loader.lazyRequireGetter(this, "showMenu", "devtools/client/shared/components/menu/utils", true);
|
||||
const Types = require("../types");
|
||||
const OPEN_DEVICE_MODAL_VALUE = "OPEN_DEVICE_MODAL";
|
||||
|
||||
class DeviceSelector extends PureComponent {
|
||||
static get propTypes() {
|
||||
|
@ -27,54 +26,31 @@ class DeviceSelector extends PureComponent {
|
|||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.onShowDeviceMenu = this.onShowDeviceMenu.bind(this);
|
||||
this.onSelectChange = this.onSelectChange.bind(this);
|
||||
}
|
||||
|
||||
onShowDeviceMenu(event) {
|
||||
onSelectChange({ target }) {
|
||||
const {
|
||||
devices,
|
||||
selectedDevice,
|
||||
viewportId,
|
||||
onChangeDevice,
|
||||
onResizeViewport,
|
||||
onUpdateDeviceModal,
|
||||
} = this.props;
|
||||
|
||||
const menuItems = [];
|
||||
|
||||
if (target.value === OPEN_DEVICE_MODAL_VALUE) {
|
||||
onUpdateDeviceModal(true, viewportId);
|
||||
return;
|
||||
}
|
||||
for (const type of devices.types) {
|
||||
for (const device of devices[type]) {
|
||||
if (device.displayed) {
|
||||
menuItems.push({
|
||||
label: device.name,
|
||||
type: "checkbox",
|
||||
checked: selectedDevice === device.name,
|
||||
click: () => {
|
||||
onResizeViewport(viewportId, device.width, device.height);
|
||||
onChangeDevice(viewportId, device, type);
|
||||
},
|
||||
});
|
||||
if (device.name === target.value) {
|
||||
onResizeViewport(device.width, device.height);
|
||||
onChangeDevice(device, type);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
menuItems.sort(function(a, b) {
|
||||
return a.label.localeCompare(b.label);
|
||||
});
|
||||
|
||||
if (menuItems.length > 0) {
|
||||
menuItems.push("-");
|
||||
}
|
||||
|
||||
menuItems.push({
|
||||
label: getStr("responsive.editDeviceList2"),
|
||||
click: () => onUpdateDeviceModal(true, viewportId),
|
||||
});
|
||||
|
||||
showMenu(menuItems, {
|
||||
button: event.target,
|
||||
useTopLevelWindow: true,
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -83,19 +59,71 @@ class DeviceSelector extends PureComponent {
|
|||
selectedDevice,
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
dom.button(
|
||||
{
|
||||
id: "device-selector",
|
||||
className: "devtools-button devtools-dropdown-button",
|
||||
disabled: devices.listState !== Types.loadableState.LOADED,
|
||||
title: selectedDevice,
|
||||
onClick: this.onShowDeviceMenu,
|
||||
const options = [];
|
||||
for (const type of devices.types) {
|
||||
for (const device of devices[type]) {
|
||||
if (device.displayed) {
|
||||
options.push(device);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
options.sort(function(a, b) {
|
||||
return a.name.localeCompare(b.name);
|
||||
});
|
||||
|
||||
let selectClass = "viewport-device-selector toolbar-dropdown";
|
||||
if (selectedDevice) {
|
||||
selectClass += " selected";
|
||||
}
|
||||
|
||||
const state = devices.listState;
|
||||
let listContent;
|
||||
|
||||
if (state == Types.loadableState.LOADED) {
|
||||
listContent = [
|
||||
dom.option({
|
||||
value: "",
|
||||
title: "",
|
||||
disabled: true,
|
||||
hidden: true,
|
||||
},
|
||||
dom.span({ className: "title" },
|
||||
selectedDevice || getStr("responsive.responsiveMode")
|
||||
)
|
||||
)
|
||||
getStr("responsive.noDeviceSelected")),
|
||||
options.map(device => {
|
||||
return dom.option({
|
||||
key: device.name,
|
||||
value: device.name,
|
||||
title: "",
|
||||
}, device.name);
|
||||
}),
|
||||
dom.option({
|
||||
value: OPEN_DEVICE_MODAL_VALUE,
|
||||
title: "",
|
||||
}, getStr("responsive.editDeviceList"))];
|
||||
} else if (state == Types.loadableState.LOADING
|
||||
|| state == Types.loadableState.INITIALIZED) {
|
||||
listContent = [dom.option({
|
||||
value: "",
|
||||
title: "",
|
||||
disabled: true,
|
||||
}, getStr("responsive.deviceListLoading"))];
|
||||
} else if (state == Types.loadableState.ERROR) {
|
||||
listContent = [dom.option({
|
||||
value: "",
|
||||
title: "",
|
||||
disabled: true,
|
||||
}, getStr("responsive.deviceListError"))];
|
||||
}
|
||||
|
||||
return dom.select(
|
||||
{
|
||||
className: selectClass,
|
||||
value: selectedDevice,
|
||||
title: selectedDevice,
|
||||
onChange: this.onSelectChange,
|
||||
disabled: (state !== Types.loadableState.LOADED),
|
||||
},
|
||||
...listContent
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
/* 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 { PureComponent, createFactory } = require("devtools/client/shared/vendor/react");
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
|
||||
const { getStr } = require("../utils/l10n");
|
||||
const Types = require("../types");
|
||||
const DevicePixelRatioSelector = createFactory(require("./DevicePixelRatioSelector"));
|
||||
const NetworkThrottlingSelector = createFactory(require("devtools/client/shared/components/throttling/NetworkThrottlingSelector"));
|
||||
const ReloadConditions = createFactory(require("./ReloadConditions"));
|
||||
|
||||
class GlobalToolbar extends PureComponent {
|
||||
static get propTypes() {
|
||||
return {
|
||||
devices: PropTypes.shape(Types.devices).isRequired,
|
||||
displayPixelRatio: Types.pixelRatio.value.isRequired,
|
||||
networkThrottling: PropTypes.shape(Types.networkThrottling).isRequired,
|
||||
reloadConditions: PropTypes.shape(Types.reloadConditions).isRequired,
|
||||
screenshot: PropTypes.shape(Types.screenshot).isRequired,
|
||||
selectedDevice: PropTypes.string.isRequired,
|
||||
selectedPixelRatio: PropTypes.shape(Types.pixelRatio).isRequired,
|
||||
touchSimulation: PropTypes.shape(Types.touchSimulation).isRequired,
|
||||
onChangeNetworkThrottling: PropTypes.func.isRequired,
|
||||
onChangePixelRatio: PropTypes.func.isRequired,
|
||||
onChangeReloadCondition: PropTypes.func.isRequired,
|
||||
onChangeTouchSimulation: PropTypes.func.isRequired,
|
||||
onExit: PropTypes.func.isRequired,
|
||||
onScreenshot: PropTypes.func.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
devices,
|
||||
displayPixelRatio,
|
||||
networkThrottling,
|
||||
reloadConditions,
|
||||
screenshot,
|
||||
selectedDevice,
|
||||
selectedPixelRatio,
|
||||
touchSimulation,
|
||||
onChangeNetworkThrottling,
|
||||
onChangePixelRatio,
|
||||
onChangeReloadCondition,
|
||||
onChangeTouchSimulation,
|
||||
onExit,
|
||||
onScreenshot,
|
||||
} = this.props;
|
||||
|
||||
let touchButtonClass = "toolbar-button devtools-button";
|
||||
if (touchSimulation.enabled) {
|
||||
touchButtonClass += " checked";
|
||||
}
|
||||
|
||||
return dom.header(
|
||||
{
|
||||
id: "global-toolbar",
|
||||
className: "container",
|
||||
},
|
||||
dom.span(
|
||||
{
|
||||
className: "title",
|
||||
},
|
||||
getStr("responsive.title")
|
||||
),
|
||||
NetworkThrottlingSelector({
|
||||
networkThrottling,
|
||||
onChangeNetworkThrottling,
|
||||
}),
|
||||
DevicePixelRatioSelector({
|
||||
devices,
|
||||
displayPixelRatio,
|
||||
selectedDevice,
|
||||
selectedPixelRatio,
|
||||
onChangePixelRatio,
|
||||
}),
|
||||
ReloadConditions({
|
||||
reloadConditions,
|
||||
onChangeReloadCondition,
|
||||
}),
|
||||
dom.button({
|
||||
id: "global-touch-simulation-button",
|
||||
className: touchButtonClass,
|
||||
title: (touchSimulation.enabled ?
|
||||
getStr("responsive.disableTouch") : getStr("responsive.enableTouch")),
|
||||
onClick: () => onChangeTouchSimulation(!touchSimulation.enabled),
|
||||
}),
|
||||
dom.button({
|
||||
id: "global-screenshot-button",
|
||||
className: "toolbar-button devtools-button",
|
||||
title: getStr("responsive.screenshot"),
|
||||
onClick: onScreenshot,
|
||||
disabled: screenshot.isCapturing,
|
||||
}),
|
||||
dom.button({
|
||||
id: "global-exit-button",
|
||||
className: "toolbar-button devtools-button",
|
||||
title: getStr("responsive.exit"),
|
||||
onClick: onExit,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = GlobalToolbar;
|
|
@ -0,0 +1,49 @@
|
|||
/* 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 { PureComponent, createFactory } = require("devtools/client/shared/vendor/react");
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
|
||||
const Types = require("../types");
|
||||
const { getStr } = require("../utils/l10n");
|
||||
const ToggleMenu = createFactory(require("./ToggleMenu"));
|
||||
|
||||
class ReloadConditions extends PureComponent {
|
||||
static get propTypes() {
|
||||
return {
|
||||
reloadConditions: PropTypes.shape(Types.reloadConditions).isRequired,
|
||||
onChangeReloadCondition: PropTypes.func.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
reloadConditions,
|
||||
onChangeReloadCondition,
|
||||
} = this.props;
|
||||
|
||||
return ToggleMenu({
|
||||
id: "global-reload-conditions-menu",
|
||||
items: [
|
||||
{
|
||||
id: "touchSimulation",
|
||||
label: getStr("responsive.reloadConditions.touchSimulation"),
|
||||
checked: reloadConditions.touchSimulation,
|
||||
},
|
||||
{
|
||||
id: "userAgent",
|
||||
label: getStr("responsive.reloadConditions.userAgent"),
|
||||
checked: reloadConditions.userAgent,
|
||||
},
|
||||
],
|
||||
label: getStr("responsive.reloadConditions.label"),
|
||||
title: getStr("responsive.reloadConditions.title"),
|
||||
onChange: onChangeReloadCondition,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ReloadConditions;
|
|
@ -7,13 +7,13 @@
|
|||
"use strict";
|
||||
|
||||
const { Component, createFactory } = 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 Browser = createFactory(require("./Browser"));
|
||||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
|
||||
const Constants = require("../constants");
|
||||
const Types = require("../types");
|
||||
const Browser = createFactory(require("./Browser"));
|
||||
const ViewportToolbar = createFactory(require("./ViewportToolbar"));
|
||||
|
||||
const VIEWPORT_MIN_WIDTH = Constants.MIN_VIEWPORT_DIMENSION;
|
||||
const VIEWPORT_MIN_HEIGHT = Constants.MIN_VIEWPORT_DIMENSION;
|
||||
|
@ -21,14 +21,17 @@ const VIEWPORT_MIN_HEIGHT = Constants.MIN_VIEWPORT_DIMENSION;
|
|||
class ResizableViewport extends Component {
|
||||
static get propTypes() {
|
||||
return {
|
||||
leftAlignmentEnabled: PropTypes.bool.isRequired,
|
||||
devices: PropTypes.shape(Types.devices).isRequired,
|
||||
screenshot: PropTypes.shape(Types.screenshot).isRequired,
|
||||
swapAfterMount: PropTypes.bool.isRequired,
|
||||
viewport: PropTypes.shape(Types.viewport).isRequired,
|
||||
onBrowserMounted: PropTypes.func.isRequired,
|
||||
onChangeDevice: PropTypes.func.isRequired,
|
||||
onContentResize: PropTypes.func.isRequired,
|
||||
onRemoveDeviceAssociation: PropTypes.func.isRequired,
|
||||
onResizeViewport: PropTypes.func.isRequired,
|
||||
onRotateViewport: PropTypes.func.isRequired,
|
||||
onUpdateDeviceModal: PropTypes.func.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -43,75 +46,9 @@ class ResizableViewport extends Component {
|
|||
ignoreY: false,
|
||||
};
|
||||
|
||||
this.onRemoveDeviceAssociation = this.onRemoveDeviceAssociation.bind(this);
|
||||
this.onResizeDrag = this.onResizeDrag.bind(this);
|
||||
this.onResizeStart = this.onResizeStart.bind(this);
|
||||
this.onResizeStop = this.onResizeStop.bind(this);
|
||||
this.onResizeViewport = this.onResizeViewport.bind(this);
|
||||
}
|
||||
|
||||
onRemoveDeviceAssociation() {
|
||||
const {
|
||||
viewport,
|
||||
onRemoveDeviceAssociation,
|
||||
} = this.props;
|
||||
|
||||
onRemoveDeviceAssociation(viewport.id);
|
||||
}
|
||||
|
||||
onResizeDrag({ clientX, clientY }) {
|
||||
if (!this.state.isResizing) {
|
||||
return;
|
||||
}
|
||||
|
||||
let { lastClientX, lastClientY, ignoreX, ignoreY } = this.state;
|
||||
let deltaX = clientX - lastClientX;
|
||||
let deltaY = clientY - lastClientY;
|
||||
|
||||
if (!this.props.leftAlignmentEnabled) {
|
||||
// The viewport is centered horizontally, so horizontal resize resizes
|
||||
// by twice the distance the mouse was dragged - on left and right side.
|
||||
deltaX = deltaX * 2;
|
||||
}
|
||||
|
||||
if (ignoreX) {
|
||||
deltaX = 0;
|
||||
}
|
||||
if (ignoreY) {
|
||||
deltaY = 0;
|
||||
}
|
||||
|
||||
let width = this.props.viewport.width + deltaX;
|
||||
let height = this.props.viewport.height + deltaY;
|
||||
|
||||
if (width < VIEWPORT_MIN_WIDTH) {
|
||||
width = VIEWPORT_MIN_WIDTH;
|
||||
} else {
|
||||
lastClientX = clientX;
|
||||
}
|
||||
|
||||
if (height < VIEWPORT_MIN_HEIGHT) {
|
||||
height = VIEWPORT_MIN_HEIGHT;
|
||||
} else {
|
||||
lastClientY = clientY;
|
||||
}
|
||||
|
||||
// Update the viewport store with the new width and height.
|
||||
this.onResizeViewport(width, height);
|
||||
// Change the device selector back to an unselected device
|
||||
// TODO: Bug 1332754: Logic like this probably belongs in the action creator.
|
||||
if (this.props.viewport.device) {
|
||||
// In bug 1329843 and others, we may eventually stop this approach of removing the
|
||||
// the properties of the device on resize. However, at the moment, there is no
|
||||
// way to edit dPR when a device is selected, and there is no UI at all for editing
|
||||
// UA, so it's important to keep doing this for now.
|
||||
this.onRemoveDeviceAssociation();
|
||||
}
|
||||
|
||||
this.setState({
|
||||
lastClientX,
|
||||
lastClientY
|
||||
});
|
||||
this.onResizeDrag = this.onResizeDrag.bind(this);
|
||||
}
|
||||
|
||||
onResizeStart({ target, clientX, clientY }) {
|
||||
|
@ -140,22 +77,69 @@ class ResizableViewport extends Component {
|
|||
});
|
||||
}
|
||||
|
||||
onResizeViewport(width, height) {
|
||||
const {
|
||||
viewport,
|
||||
onResizeViewport,
|
||||
} = this.props;
|
||||
onResizeDrag({ clientX, clientY }) {
|
||||
if (!this.state.isResizing) {
|
||||
return;
|
||||
}
|
||||
|
||||
onResizeViewport(viewport.id, width, height);
|
||||
let { lastClientX, lastClientY, ignoreX, ignoreY } = this.state;
|
||||
// the viewport is centered horizontally, so horizontal resize resizes
|
||||
// by twice the distance the mouse was dragged - on left and right side.
|
||||
let deltaX = 2 * (clientX - lastClientX);
|
||||
let deltaY = (clientY - lastClientY);
|
||||
|
||||
if (ignoreX) {
|
||||
deltaX = 0;
|
||||
}
|
||||
if (ignoreY) {
|
||||
deltaY = 0;
|
||||
}
|
||||
|
||||
let width = this.props.viewport.width + deltaX;
|
||||
let height = this.props.viewport.height + deltaY;
|
||||
|
||||
if (width < VIEWPORT_MIN_WIDTH) {
|
||||
width = VIEWPORT_MIN_WIDTH;
|
||||
} else {
|
||||
lastClientX = clientX;
|
||||
}
|
||||
|
||||
if (height < VIEWPORT_MIN_HEIGHT) {
|
||||
height = VIEWPORT_MIN_HEIGHT;
|
||||
} else {
|
||||
lastClientY = clientY;
|
||||
}
|
||||
|
||||
// Update the viewport store with the new width and height.
|
||||
this.props.onResizeViewport(width, height);
|
||||
// Change the device selector back to an unselected device
|
||||
// TODO: Bug 1332754: Logic like this probably belongs in the action creator.
|
||||
if (this.props.viewport.device) {
|
||||
// In bug 1329843 and others, we may eventually stop this approach of removing the
|
||||
// the properties of the device on resize. However, at the moment, there is no
|
||||
// way to edit dPR when a device is selected, and there is no UI at all for editing
|
||||
// UA, so it's important to keep doing this for now.
|
||||
this.props.onRemoveDeviceAssociation();
|
||||
}
|
||||
|
||||
this.setState({
|
||||
lastClientX,
|
||||
lastClientY
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
devices,
|
||||
screenshot,
|
||||
swapAfterMount,
|
||||
viewport,
|
||||
onBrowserMounted,
|
||||
onChangeDevice,
|
||||
onContentResize,
|
||||
onResizeViewport,
|
||||
onRotateViewport,
|
||||
onUpdateDeviceModal,
|
||||
} = this.props;
|
||||
|
||||
let resizeHandleClass = "viewport-resize-handle";
|
||||
|
@ -168,40 +152,47 @@ class ResizableViewport extends Component {
|
|||
contentClass += " resizing";
|
||||
}
|
||||
|
||||
return (
|
||||
dom.div({ className: "viewport" },
|
||||
dom.div({ className: "resizable-viewport" },
|
||||
dom.div(
|
||||
{
|
||||
className: contentClass,
|
||||
style: {
|
||||
width: viewport.width + "px",
|
||||
height: viewport.height + "px",
|
||||
},
|
||||
},
|
||||
Browser({
|
||||
swapAfterMount,
|
||||
userContextId: viewport.userContextId,
|
||||
onBrowserMounted,
|
||||
onContentResize,
|
||||
})
|
||||
),
|
||||
dom.div({
|
||||
className: resizeHandleClass,
|
||||
onMouseDown: this.onResizeStart,
|
||||
}),
|
||||
dom.div({
|
||||
ref: "resizeBarX",
|
||||
className: "viewport-horizontal-resize-handle",
|
||||
onMouseDown: this.onResizeStart,
|
||||
}),
|
||||
dom.div({
|
||||
ref: "resizeBarY",
|
||||
className: "viewport-vertical-resize-handle",
|
||||
onMouseDown: this.onResizeStart,
|
||||
})
|
||||
)
|
||||
)
|
||||
return dom.div(
|
||||
{
|
||||
className: "resizable-viewport",
|
||||
},
|
||||
ViewportToolbar({
|
||||
devices,
|
||||
viewport,
|
||||
onChangeDevice,
|
||||
onResizeViewport,
|
||||
onRotateViewport,
|
||||
onUpdateDeviceModal,
|
||||
}),
|
||||
dom.div(
|
||||
{
|
||||
className: contentClass,
|
||||
style: {
|
||||
width: viewport.width + "px",
|
||||
height: viewport.height + "px",
|
||||
},
|
||||
},
|
||||
Browser({
|
||||
swapAfterMount,
|
||||
userContextId: viewport.userContextId,
|
||||
onBrowserMounted,
|
||||
onContentResize,
|
||||
})
|
||||
),
|
||||
dom.div({
|
||||
className: resizeHandleClass,
|
||||
onMouseDown: this.onResizeStart,
|
||||
}),
|
||||
dom.div({
|
||||
ref: "resizeBarX",
|
||||
className: "viewport-horizontal-resize-handle",
|
||||
onMouseDown: this.onResizeStart,
|
||||
}),
|
||||
dom.div({
|
||||
ref: "resizeBarY",
|
||||
className: "viewport-vertical-resize-handle",
|
||||
onMouseDown: this.onResizeStart,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,94 +0,0 @@
|
|||
/* 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 { connect } = require("devtools/client/shared/vendor/react-redux");
|
||||
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 { getStr } = require("../utils/l10n");
|
||||
const Types = require("../types");
|
||||
|
||||
loader.lazyRequireGetter(this, "showMenu", "devtools/client/shared/components/menu/utils", true);
|
||||
|
||||
class SettingsMenu extends PureComponent {
|
||||
static get propTypes() {
|
||||
return {
|
||||
leftAlignmentEnabled: PropTypes.bool.isRequired,
|
||||
reloadConditions: PropTypes.shape(Types.reloadConditions).isRequired,
|
||||
onChangeReloadCondition: PropTypes.func.isRequired,
|
||||
onToggleLeftAlignment: PropTypes.func.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.onToggleSettingMenu = this.onToggleSettingMenu.bind(this);
|
||||
}
|
||||
|
||||
onToggleSettingMenu(event) {
|
||||
const {
|
||||
leftAlignmentEnabled,
|
||||
reloadConditions,
|
||||
onChangeReloadCondition,
|
||||
onToggleLeftAlignment,
|
||||
} = this.props;
|
||||
|
||||
const menuItems = [
|
||||
{
|
||||
id: "toggleLeftAlignment",
|
||||
checked: leftAlignmentEnabled,
|
||||
label: getStr("responsive.leftAlignViewport"),
|
||||
type: "checkbox",
|
||||
click: () => {
|
||||
onToggleLeftAlignment();
|
||||
},
|
||||
},
|
||||
"-",
|
||||
{
|
||||
id: "touchSimulation",
|
||||
checked: reloadConditions.touchSimulation,
|
||||
label: getStr("responsive.reloadConditions.touchSimulation"),
|
||||
type: "checkbox",
|
||||
click: () => {
|
||||
onChangeReloadCondition("touchSimulation", !reloadConditions.touchSimulation);
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "userAgent",
|
||||
checked: reloadConditions.userAgent,
|
||||
label: getStr("responsive.reloadConditions.userAgent"),
|
||||
type: "checkbox",
|
||||
click: () => {
|
||||
onChangeReloadCondition("userAgent", !reloadConditions.userAgent);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
showMenu(menuItems, {
|
||||
button: event.target,
|
||||
useTopLevelWindow: true,
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
dom.button({
|
||||
id: "settings-button",
|
||||
className: "devtools-button",
|
||||
onClick: this.onToggleSettingMenu,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
leftAlignmentEnabled: state.ui.leftAlignmentEnabled,
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = connect(mapStateToProps)(SettingsMenu);
|
|
@ -0,0 +1,130 @@
|
|||
/* 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 { PureComponent } = require("devtools/client/shared/vendor/react");
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
|
||||
const MenuItem = {
|
||||
id: PropTypes.string.isRequired,
|
||||
label: PropTypes.string.isRequired,
|
||||
checked: PropTypes.bool,
|
||||
};
|
||||
|
||||
class ToggleMenu extends PureComponent {
|
||||
static get propTypes() {
|
||||
return {
|
||||
id: PropTypes.string,
|
||||
items: PropTypes.arrayOf(PropTypes.shape(MenuItem)).isRequired,
|
||||
label: PropTypes.string,
|
||||
title: PropTypes.string,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
isOpen: false,
|
||||
};
|
||||
|
||||
this.onItemChange = this.onItemChange.bind(this);
|
||||
this.onToggleOpen = this.onToggleOpen.bind(this);
|
||||
}
|
||||
|
||||
onItemChange({ target }) {
|
||||
const {
|
||||
onChange,
|
||||
} = this.props;
|
||||
|
||||
// Close menu after changing an item
|
||||
this.setState({
|
||||
isOpen: false,
|
||||
});
|
||||
|
||||
const id = target.name;
|
||||
onChange(id, target.checked);
|
||||
}
|
||||
|
||||
onToggleOpen() {
|
||||
const {
|
||||
isOpen,
|
||||
} = this.state;
|
||||
|
||||
this.setState({
|
||||
isOpen: !isOpen,
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
id: menuID,
|
||||
items,
|
||||
label: toggleLabel,
|
||||
title,
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
isOpen,
|
||||
} = this.state;
|
||||
|
||||
const {
|
||||
onItemChange,
|
||||
onToggleOpen,
|
||||
} = this;
|
||||
|
||||
const menuItems = items.map(({ id, label, checked }) => {
|
||||
const inputID = `devtools-menu-item-${id}`;
|
||||
|
||||
return dom.div(
|
||||
{
|
||||
className: "devtools-menu-item",
|
||||
key: id,
|
||||
},
|
||||
dom.input({
|
||||
type: "checkbox",
|
||||
id: inputID,
|
||||
name: id,
|
||||
checked,
|
||||
onChange: onItemChange,
|
||||
}),
|
||||
dom.label({
|
||||
htmlFor: inputID,
|
||||
}, label)
|
||||
);
|
||||
});
|
||||
|
||||
let menuClass = "devtools-menu";
|
||||
if (isOpen) {
|
||||
menuClass += " opened";
|
||||
}
|
||||
const menu = dom.div(
|
||||
{
|
||||
className: menuClass,
|
||||
},
|
||||
menuItems
|
||||
);
|
||||
|
||||
let buttonClass = "devtools-toggle-menu";
|
||||
buttonClass += " toolbar-dropdown toolbar-button devtools-button";
|
||||
if (isOpen || items.some(({ checked }) => checked)) {
|
||||
buttonClass += " selected";
|
||||
}
|
||||
return dom.div(
|
||||
{
|
||||
id: menuID,
|
||||
className: buttonClass,
|
||||
title,
|
||||
onClick: onToggleOpen,
|
||||
},
|
||||
toggleLabel,
|
||||
menu
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ToggleMenu;
|
|
@ -1,145 +0,0 @@
|
|||
/* 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 { PureComponent, createFactory } = 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 DevicePixelRatioMenu = createFactory(require("./DevicePixelRatioMenu"));
|
||||
const DeviceSelector = createFactory(require("./DeviceSelector"));
|
||||
const NetworkThrottlingMenu = createFactory(require("devtools/client/shared/components/throttling/NetworkThrottlingMenu"));
|
||||
const SettingsMenu = createFactory(require("./SettingsMenu"));
|
||||
const ViewportDimension = createFactory(require("./ViewportDimension"));
|
||||
|
||||
const { getStr } = require("../utils/l10n");
|
||||
const Types = require("../types");
|
||||
|
||||
class Toolbar extends PureComponent {
|
||||
static get propTypes() {
|
||||
return {
|
||||
devices: PropTypes.shape(Types.devices).isRequired,
|
||||
displayPixelRatio: Types.pixelRatio.value.isRequired,
|
||||
networkThrottling: PropTypes.shape(Types.networkThrottling).isRequired,
|
||||
reloadConditions: PropTypes.shape(Types.reloadConditions).isRequired,
|
||||
screenshot: PropTypes.shape(Types.screenshot).isRequired,
|
||||
selectedDevice: PropTypes.string.isRequired,
|
||||
selectedPixelRatio: PropTypes.shape(Types.pixelRatio).isRequired,
|
||||
touchSimulation: PropTypes.shape(Types.touchSimulation).isRequired,
|
||||
viewport: PropTypes.shape(Types.viewport).isRequired,
|
||||
onChangeDevice: PropTypes.func.isRequired,
|
||||
onChangeNetworkThrottling: PropTypes.func.isRequired,
|
||||
onChangePixelRatio: PropTypes.func.isRequired,
|
||||
onChangeReloadCondition: PropTypes.func.isRequired,
|
||||
onChangeTouchSimulation: PropTypes.func.isRequired,
|
||||
onExit: PropTypes.func.isRequired,
|
||||
onRemoveDeviceAssociation: PropTypes.func.isRequired,
|
||||
onResizeViewport: PropTypes.func.isRequired,
|
||||
onRotateViewport: PropTypes.func.isRequired,
|
||||
onScreenshot: PropTypes.func.isRequired,
|
||||
onToggleLeftAlignment: PropTypes.func.isRequired,
|
||||
onUpdateDeviceModal: PropTypes.func.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
devices,
|
||||
displayPixelRatio,
|
||||
networkThrottling,
|
||||
reloadConditions,
|
||||
screenshot,
|
||||
selectedDevice,
|
||||
selectedPixelRatio,
|
||||
touchSimulation,
|
||||
viewport,
|
||||
onChangeDevice,
|
||||
onChangeNetworkThrottling,
|
||||
onChangePixelRatio,
|
||||
onChangeReloadCondition,
|
||||
onChangeTouchSimulation,
|
||||
onExit,
|
||||
onRemoveDeviceAssociation,
|
||||
onResizeViewport,
|
||||
onRotateViewport,
|
||||
onScreenshot,
|
||||
onToggleLeftAlignment,
|
||||
onUpdateDeviceModal,
|
||||
} = this.props;
|
||||
|
||||
return dom.header(
|
||||
{ id: "toolbar" },
|
||||
DeviceSelector({
|
||||
devices,
|
||||
selectedDevice,
|
||||
viewportId: viewport.id,
|
||||
onChangeDevice,
|
||||
onResizeViewport,
|
||||
onUpdateDeviceModal,
|
||||
}),
|
||||
dom.div(
|
||||
{ id: "toolbar-center-controls" },
|
||||
ViewportDimension({
|
||||
viewport,
|
||||
onRemoveDeviceAssociation,
|
||||
onResizeViewport,
|
||||
}),
|
||||
dom.button({
|
||||
id: "rotate-button",
|
||||
className: "devtools-button",
|
||||
onClick: () => onRotateViewport(viewport.id),
|
||||
title: getStr("responsive.rotate"),
|
||||
}),
|
||||
dom.div({ className: "devtools-separator" }),
|
||||
DevicePixelRatioMenu({
|
||||
devices,
|
||||
displayPixelRatio,
|
||||
selectedDevice,
|
||||
selectedPixelRatio,
|
||||
onChangePixelRatio,
|
||||
}),
|
||||
dom.div({ className: "devtools-separator" }),
|
||||
NetworkThrottlingMenu({
|
||||
networkThrottling,
|
||||
onChangeNetworkThrottling,
|
||||
useTopLevelWindow: true,
|
||||
}),
|
||||
dom.div({ className: "devtools-separator" }),
|
||||
dom.button({
|
||||
id: "touch-simulation-button",
|
||||
className: "devtools-button" +
|
||||
(touchSimulation.enabled ? " checked" : ""),
|
||||
title: (touchSimulation.enabled ?
|
||||
getStr("responsive.disableTouch") : getStr("responsive.enableTouch")),
|
||||
onClick: () => onChangeTouchSimulation(!touchSimulation.enabled),
|
||||
})
|
||||
),
|
||||
dom.div(
|
||||
{ id: "toolbar-end-controls" },
|
||||
dom.button({
|
||||
id: "screenshot-button",
|
||||
className: "devtools-button",
|
||||
title: getStr("responsive.screenshot"),
|
||||
onClick: onScreenshot,
|
||||
disabled: screenshot.isCapturing,
|
||||
}),
|
||||
SettingsMenu({
|
||||
reloadConditions,
|
||||
onChangeReloadCondition,
|
||||
onToggleLeftAlignment,
|
||||
}),
|
||||
dom.div({ className: "devtools-separator" }),
|
||||
dom.button({
|
||||
id: "exit-button",
|
||||
className: "devtools-button",
|
||||
title: getStr("responsive.exit"),
|
||||
onClick: onExit,
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Toolbar;
|
|
@ -0,0 +1,120 @@
|
|||
/* 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 { Component, createFactory } = require("devtools/client/shared/vendor/react");
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
|
||||
const Types = require("../types");
|
||||
const ResizableViewport = createFactory(require("./ResizableViewport"));
|
||||
const ViewportDimension = createFactory(require("./ViewportDimension"));
|
||||
|
||||
class Viewport extends Component {
|
||||
static get propTypes() {
|
||||
return {
|
||||
devices: PropTypes.shape(Types.devices).isRequired,
|
||||
screenshot: PropTypes.shape(Types.screenshot).isRequired,
|
||||
swapAfterMount: PropTypes.bool.isRequired,
|
||||
viewport: PropTypes.shape(Types.viewport).isRequired,
|
||||
onBrowserMounted: PropTypes.func.isRequired,
|
||||
onChangeDevice: PropTypes.func.isRequired,
|
||||
onContentResize: PropTypes.func.isRequired,
|
||||
onRemoveDeviceAssociation: PropTypes.func.isRequired,
|
||||
onResizeViewport: PropTypes.func.isRequired,
|
||||
onRotateViewport: PropTypes.func.isRequired,
|
||||
onUpdateDeviceModal: PropTypes.func.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.onChangeDevice = this.onChangeDevice.bind(this);
|
||||
this.onRemoveDeviceAssociation = this.onRemoveDeviceAssociation.bind(this);
|
||||
this.onResizeViewport = this.onResizeViewport.bind(this);
|
||||
this.onRotateViewport = this.onRotateViewport.bind(this);
|
||||
}
|
||||
|
||||
onChangeDevice(device, deviceType) {
|
||||
const {
|
||||
viewport,
|
||||
onChangeDevice,
|
||||
} = this.props;
|
||||
|
||||
onChangeDevice(viewport.id, device, deviceType);
|
||||
}
|
||||
|
||||
onRemoveDeviceAssociation() {
|
||||
const {
|
||||
viewport,
|
||||
onRemoveDeviceAssociation,
|
||||
} = this.props;
|
||||
|
||||
onRemoveDeviceAssociation(viewport.id);
|
||||
}
|
||||
|
||||
onResizeViewport(width, height) {
|
||||
const {
|
||||
viewport,
|
||||
onResizeViewport,
|
||||
} = this.props;
|
||||
|
||||
onResizeViewport(viewport.id, width, height);
|
||||
}
|
||||
|
||||
onRotateViewport() {
|
||||
const {
|
||||
viewport,
|
||||
onRotateViewport,
|
||||
} = this.props;
|
||||
|
||||
onRotateViewport(viewport.id);
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
devices,
|
||||
screenshot,
|
||||
swapAfterMount,
|
||||
viewport,
|
||||
onBrowserMounted,
|
||||
onContentResize,
|
||||
onUpdateDeviceModal,
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
onChangeDevice,
|
||||
onRemoveDeviceAssociation,
|
||||
onRotateViewport,
|
||||
onResizeViewport,
|
||||
} = this;
|
||||
|
||||
return dom.div(
|
||||
{
|
||||
className: "viewport",
|
||||
},
|
||||
ViewportDimension({
|
||||
viewport,
|
||||
onChangeSize: onResizeViewport,
|
||||
onRemoveDeviceAssociation,
|
||||
}),
|
||||
ResizableViewport({
|
||||
devices,
|
||||
screenshot,
|
||||
swapAfterMount,
|
||||
viewport,
|
||||
onBrowserMounted,
|
||||
onChangeDevice,
|
||||
onContentResize,
|
||||
onRemoveDeviceAssociation,
|
||||
onResizeViewport,
|
||||
onRotateViewport,
|
||||
onUpdateDeviceModal,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Viewport;
|
|
@ -5,191 +5,13 @@
|
|||
"use strict";
|
||||
|
||||
const { Component } = 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 dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
const { isKeyIn } = require("../utils/key");
|
||||
const { MIN_VIEWPORT_DIMENSION } = require("../constants");
|
||||
|
||||
const Constants = require("../constants");
|
||||
const Types = require("../types");
|
||||
|
||||
class ViewportDimension extends Component {
|
||||
static get propTypes() {
|
||||
return {
|
||||
viewport: PropTypes.shape(Types.viewport).isRequired,
|
||||
onResizeViewport: PropTypes.func.isRequired,
|
||||
onRemoveDeviceAssociation: PropTypes.func.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
const { width, height } = props.viewport;
|
||||
|
||||
this.state = {
|
||||
width,
|
||||
height,
|
||||
isEditing: false,
|
||||
isWidthValid: true,
|
||||
isHeightValid: true,
|
||||
};
|
||||
|
||||
this.isInputValid = this.isInputValid.bind(this);
|
||||
this.onInputBlur = this.onInputBlur.bind(this);
|
||||
this.onInputChange = this.onInputChange.bind(this);
|
||||
this.onInputFocus = this.onInputFocus.bind(this);
|
||||
this.onInputKeyDown = this.onInputKeyDown.bind(this);
|
||||
this.onInputKeyUp = this.onInputKeyUp.bind(this);
|
||||
this.onInputSubmit = this.onInputSubmit.bind(this);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
const { width, height } = nextProps.viewport;
|
||||
|
||||
this.setState({
|
||||
width,
|
||||
height,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the given value is a number and greater than MIN_VIEWPORT_DIMENSION
|
||||
* and false otherwise.
|
||||
*/
|
||||
isInputValid(value) {
|
||||
return /^\d{2,4}$/.test(value) && parseInt(value, 10) >= MIN_VIEWPORT_DIMENSION;
|
||||
}
|
||||
|
||||
onInputBlur() {
|
||||
const { width, height } = this.props.viewport;
|
||||
|
||||
if (this.state.width != width || this.state.height != height) {
|
||||
this.onInputSubmit();
|
||||
}
|
||||
|
||||
this.setState({ isEditing: false });
|
||||
}
|
||||
|
||||
onInputChange({ target }, callback) {
|
||||
if (target.value.length > 4) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.widthInput == target) {
|
||||
this.setState({
|
||||
width: target.value,
|
||||
isWidthValid: this.isInputValid(target.value),
|
||||
}, callback);
|
||||
}
|
||||
|
||||
if (this.heightInput == target) {
|
||||
this.setState({
|
||||
height: target.value,
|
||||
isHeightValid: this.isInputValid(target.value),
|
||||
}, callback);
|
||||
}
|
||||
}
|
||||
|
||||
onInputFocus() {
|
||||
this.setState({ isEditing: true });
|
||||
}
|
||||
|
||||
onInputKeyDown(event) {
|
||||
const increment = getIncrement(event);
|
||||
if (!increment) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { target } = event;
|
||||
target.value = parseInt(target.value, 10) + increment;
|
||||
this.onInputChange(event, this.onInputSubmit);
|
||||
}
|
||||
|
||||
onInputKeyUp({ target, keyCode }) {
|
||||
// On Enter, submit the input
|
||||
if (keyCode == 13) {
|
||||
this.onInputSubmit();
|
||||
}
|
||||
|
||||
// On Esc, blur the target
|
||||
if (keyCode == 27) {
|
||||
target.blur();
|
||||
}
|
||||
}
|
||||
|
||||
onInputSubmit() {
|
||||
const {
|
||||
viewport,
|
||||
onRemoveDeviceAssociation,
|
||||
onResizeViewport,
|
||||
} = this.props;
|
||||
|
||||
if (!this.state.isWidthValid || !this.state.isHeightValid) {
|
||||
const { width, height } = viewport;
|
||||
|
||||
this.setState({
|
||||
width,
|
||||
height,
|
||||
isWidthValid: true,
|
||||
isHeightValid: true,
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Change the device selector back to an unselected device
|
||||
// TODO: Bug 1332754: Logic like this probably belongs in the action creator.
|
||||
if (viewport.device) {
|
||||
onRemoveDeviceAssociation(viewport.id);
|
||||
}
|
||||
|
||||
onResizeViewport(viewport.id,
|
||||
parseInt(this.state.width, 10), parseInt(this.state.height, 10));
|
||||
}
|
||||
|
||||
render() {
|
||||
return dom.div(
|
||||
{
|
||||
className:
|
||||
"viewport-dimension" +
|
||||
(this.state.isEditing ? " editing" : "") +
|
||||
(!this.state.isWidthValid || !this.state.isHeightValid ? " invalid" : ""),
|
||||
},
|
||||
dom.input({
|
||||
ref: input => {
|
||||
this.widthInput = input;
|
||||
},
|
||||
className: "viewport-dimension-input" +
|
||||
(this.state.isWidthValid ? "" : " invalid"),
|
||||
size: 4,
|
||||
value: this.state.width,
|
||||
onBlur: this.onInputBlur,
|
||||
onChange: this.onInputChange,
|
||||
onFocus: this.onInputFocus,
|
||||
onKeyDown: this.onInputKeyDown,
|
||||
onKeyUp: this.onInputKeyUp,
|
||||
}),
|
||||
dom.span({
|
||||
className: "viewport-dimension-separator",
|
||||
}, "×"),
|
||||
dom.input({
|
||||
ref: input => {
|
||||
this.heightInput = input;
|
||||
},
|
||||
className: "viewport-dimension-input" +
|
||||
(this.state.isHeightValid ? "" : " invalid"),
|
||||
size: 4,
|
||||
value: this.state.height,
|
||||
onBlur: this.onInputBlur,
|
||||
onChange: this.onInputChange,
|
||||
onFocus: this.onInputFocus,
|
||||
onKeyDown: this.onInputKeyDown,
|
||||
onKeyUp: this.onInputKeyUp,
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the increment/decrement step to use for the provided key event.
|
||||
*/
|
||||
|
@ -218,4 +40,186 @@ function getIncrement(event) {
|
|||
return increment;
|
||||
}
|
||||
|
||||
class ViewportDimension extends Component {
|
||||
static get propTypes() {
|
||||
return {
|
||||
viewport: PropTypes.shape(Types.viewport).isRequired,
|
||||
onChangeSize: PropTypes.func.isRequired,
|
||||
onRemoveDeviceAssociation: PropTypes.func.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const { width, height } = props.viewport;
|
||||
|
||||
this.state = {
|
||||
width,
|
||||
height,
|
||||
isEditing: false,
|
||||
isInvalid: false,
|
||||
};
|
||||
|
||||
this.validateInput = this.validateInput.bind(this);
|
||||
this.onInputBlur = this.onInputBlur.bind(this);
|
||||
this.onInputChange = this.onInputChange.bind(this);
|
||||
this.onInputFocus = this.onInputFocus.bind(this);
|
||||
this.onInputKeyDown = this.onInputKeyDown.bind(this);
|
||||
this.onInputKeyUp = this.onInputKeyUp.bind(this);
|
||||
this.onInputSubmit = this.onInputSubmit.bind(this);
|
||||
}
|
||||
|
||||
componentWillReceiveProps(nextProps) {
|
||||
const { width, height } = nextProps.viewport;
|
||||
|
||||
this.setState({
|
||||
width,
|
||||
height,
|
||||
});
|
||||
}
|
||||
|
||||
validateInput(value) {
|
||||
let isInvalid = true;
|
||||
|
||||
// Check the value is a number and greater than MIN_VIEWPORT_DIMENSION
|
||||
if (/^\d{3,4}$/.test(value) &&
|
||||
parseInt(value, 10) >= Constants.MIN_VIEWPORT_DIMENSION) {
|
||||
isInvalid = false;
|
||||
}
|
||||
|
||||
this.setState({
|
||||
isInvalid,
|
||||
});
|
||||
}
|
||||
|
||||
onInputBlur() {
|
||||
const { width, height } = this.props.viewport;
|
||||
|
||||
if (this.state.width != width || this.state.height != height) {
|
||||
this.onInputSubmit();
|
||||
}
|
||||
|
||||
this.setState({
|
||||
isEditing: false,
|
||||
inInvalid: false,
|
||||
});
|
||||
}
|
||||
|
||||
onInputChange({ target }, callback) {
|
||||
if (target.value.length > 4) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.refs.widthInput == target) {
|
||||
this.setState({ width: target.value }, callback);
|
||||
this.validateInput(target.value);
|
||||
}
|
||||
|
||||
if (this.refs.heightInput == target) {
|
||||
this.setState({ height: target.value }, callback);
|
||||
this.validateInput(target.value);
|
||||
}
|
||||
}
|
||||
|
||||
onInputFocus() {
|
||||
this.setState({
|
||||
isEditing: true,
|
||||
});
|
||||
}
|
||||
|
||||
onInputKeyDown(event) {
|
||||
const { target } = event;
|
||||
const increment = getIncrement(event);
|
||||
if (!increment) {
|
||||
return;
|
||||
}
|
||||
target.value = parseInt(target.value, 10) + increment;
|
||||
this.onInputChange(event, this.onInputSubmit);
|
||||
}
|
||||
|
||||
onInputKeyUp({ target, keyCode }) {
|
||||
// On Enter, submit the input
|
||||
if (keyCode == 13) {
|
||||
this.onInputSubmit();
|
||||
}
|
||||
|
||||
// On Esc, blur the target
|
||||
if (keyCode == 27) {
|
||||
target.blur();
|
||||
}
|
||||
}
|
||||
|
||||
onInputSubmit() {
|
||||
if (this.state.isInvalid) {
|
||||
const { width, height } = this.props.viewport;
|
||||
|
||||
this.setState({
|
||||
width,
|
||||
height,
|
||||
isInvalid: false,
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Change the device selector back to an unselected device
|
||||
// TODO: Bug 1332754: Logic like this probably belongs in the action creator.
|
||||
if (this.props.viewport.device) {
|
||||
this.props.onRemoveDeviceAssociation();
|
||||
}
|
||||
this.props.onChangeSize(parseInt(this.state.width, 10),
|
||||
parseInt(this.state.height, 10));
|
||||
}
|
||||
|
||||
render() {
|
||||
let editableClass = "viewport-dimension-editable";
|
||||
let inputClass = "viewport-dimension-input";
|
||||
|
||||
if (this.state.isEditing) {
|
||||
editableClass += " editing";
|
||||
inputClass += " editing";
|
||||
}
|
||||
|
||||
if (this.state.isInvalid) {
|
||||
editableClass += " invalid";
|
||||
}
|
||||
|
||||
return dom.div(
|
||||
{
|
||||
className: "viewport-dimension",
|
||||
},
|
||||
dom.div(
|
||||
{
|
||||
className: editableClass,
|
||||
},
|
||||
dom.input({
|
||||
ref: "widthInput",
|
||||
className: inputClass,
|
||||
size: 4,
|
||||
value: this.state.width,
|
||||
onBlur: this.onInputBlur,
|
||||
onChange: this.onInputChange,
|
||||
onFocus: this.onInputFocus,
|
||||
onKeyDown: this.onInputKeyDown,
|
||||
onKeyUp: this.onInputKeyUp,
|
||||
}),
|
||||
dom.span({
|
||||
className: "viewport-dimension-separator",
|
||||
}, "×"),
|
||||
dom.input({
|
||||
ref: "heightInput",
|
||||
className: inputClass,
|
||||
size: 4,
|
||||
value: this.state.height,
|
||||
onBlur: this.onInputBlur,
|
||||
onChange: this.onInputChange,
|
||||
onFocus: this.onInputFocus,
|
||||
onKeyDown: this.onInputKeyDown,
|
||||
onKeyUp: this.onInputKeyUp,
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ViewportDimension;
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
/* 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 { PureComponent, createFactory } = require("devtools/client/shared/vendor/react");
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
|
||||
const { getStr } = require("../utils/l10n");
|
||||
const Types = require("../types");
|
||||
const DeviceSelector = createFactory(require("./DeviceSelector"));
|
||||
|
||||
class ViewportToolbar extends PureComponent {
|
||||
static get propTypes() {
|
||||
return {
|
||||
devices: PropTypes.shape(Types.devices).isRequired,
|
||||
viewport: PropTypes.shape(Types.viewport).isRequired,
|
||||
onChangeDevice: PropTypes.func.isRequired,
|
||||
onResizeViewport: PropTypes.func.isRequired,
|
||||
onRotateViewport: PropTypes.func.isRequired,
|
||||
onUpdateDeviceModal: PropTypes.func.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
devices,
|
||||
viewport,
|
||||
onChangeDevice,
|
||||
onResizeViewport,
|
||||
onRotateViewport,
|
||||
onUpdateDeviceModal,
|
||||
} = this.props;
|
||||
|
||||
return dom.div(
|
||||
{
|
||||
className: "viewport-toolbar container",
|
||||
},
|
||||
DeviceSelector({
|
||||
devices,
|
||||
selectedDevice: viewport.device,
|
||||
viewportId: viewport.id,
|
||||
onChangeDevice,
|
||||
onResizeViewport,
|
||||
onUpdateDeviceModal,
|
||||
}),
|
||||
dom.button({
|
||||
className: "viewport-rotate-button toolbar-button devtools-button",
|
||||
onClick: onRotateViewport,
|
||||
title: getStr("responsive.rotate"),
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ViewportToolbar;
|
|
@ -4,89 +4,65 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const { connect } = require("devtools/client/shared/vendor/react-redux");
|
||||
const { Component, createFactory } = 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 ResizableViewport = createFactory(require("./ResizableViewport"));
|
||||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
|
||||
const Types = require("../types");
|
||||
const Viewport = createFactory(require("./Viewport"));
|
||||
|
||||
class Viewports extends Component {
|
||||
static get propTypes() {
|
||||
return {
|
||||
leftAlignmentEnabled: PropTypes.bool.isRequired,
|
||||
devices: PropTypes.shape(Types.devices).isRequired,
|
||||
screenshot: PropTypes.shape(Types.screenshot).isRequired,
|
||||
viewports: PropTypes.arrayOf(PropTypes.shape(Types.viewport)).isRequired,
|
||||
onBrowserMounted: PropTypes.func.isRequired,
|
||||
onChangeDevice: PropTypes.func.isRequired,
|
||||
onContentResize: PropTypes.func.isRequired,
|
||||
onRemoveDeviceAssociation: PropTypes.func.isRequired,
|
||||
onResizeViewport: PropTypes.func.isRequired,
|
||||
onRotateViewport: PropTypes.func.isRequired,
|
||||
onUpdateDeviceModal: PropTypes.func.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
leftAlignmentEnabled,
|
||||
devices,
|
||||
screenshot,
|
||||
viewports,
|
||||
onBrowserMounted,
|
||||
onChangeDevice,
|
||||
onContentResize,
|
||||
onRemoveDeviceAssociation,
|
||||
onResizeViewport,
|
||||
onRotateViewport,
|
||||
onUpdateDeviceModal,
|
||||
} = this.props;
|
||||
|
||||
const viewportSize = window.getViewportSize();
|
||||
// The viewport may not have been created yet. Default to justify-content: center
|
||||
// for the container.
|
||||
let justifyContent = "center";
|
||||
|
||||
// If the RDM viewport is bigger than the window's inner width, set the container's
|
||||
// justify-content to start so that the 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.
|
||||
if (leftAlignmentEnabled ||
|
||||
(viewportSize && viewportSize.width > window.innerWidth)) {
|
||||
justifyContent = "start";
|
||||
}
|
||||
|
||||
return (
|
||||
dom.div(
|
||||
{
|
||||
id: "viewports-container",
|
||||
style: {
|
||||
justifyContent,
|
||||
},
|
||||
},
|
||||
dom.div(
|
||||
{
|
||||
id: "viewports",
|
||||
className: leftAlignmentEnabled ? "left-aligned" : "",
|
||||
},
|
||||
viewports.map((viewport, i) => {
|
||||
return ResizableViewport({
|
||||
key: viewport.id,
|
||||
leftAlignmentEnabled,
|
||||
screenshot,
|
||||
swapAfterMount: i == 0,
|
||||
viewport,
|
||||
onBrowserMounted,
|
||||
onContentResize,
|
||||
onRemoveDeviceAssociation,
|
||||
onResizeViewport,
|
||||
});
|
||||
})
|
||||
)
|
||||
)
|
||||
return dom.div(
|
||||
{
|
||||
id: "viewports",
|
||||
},
|
||||
viewports.map((viewport, i) => {
|
||||
return Viewport({
|
||||
key: viewport.id,
|
||||
devices,
|
||||
screenshot,
|
||||
swapAfterMount: i == 0,
|
||||
viewport,
|
||||
onBrowserMounted,
|
||||
onChangeDevice,
|
||||
onContentResize,
|
||||
onRemoveDeviceAssociation,
|
||||
onResizeViewport,
|
||||
onRotateViewport,
|
||||
onUpdateDeviceModal,
|
||||
});
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const mapStateToProps = state => {
|
||||
return {
|
||||
leftAlignmentEnabled: state.ui.leftAlignmentEnabled,
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = connect(mapStateToProps)(Viewports);
|
||||
module.exports = Viewports;
|
||||
|
|
|
@ -5,15 +5,17 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
DevToolsModules(
|
||||
'App.js',
|
||||
'Browser.js',
|
||||
'DeviceAdder.js',
|
||||
'DeviceModal.js',
|
||||
'DevicePixelRatioMenu.js',
|
||||
'DevicePixelRatioSelector.js',
|
||||
'DeviceSelector.js',
|
||||
'GlobalToolbar.js',
|
||||
'ReloadConditions.js',
|
||||
'ResizableViewport.js',
|
||||
'SettingsMenu.js',
|
||||
'Toolbar.js',
|
||||
'ToggleMenu.js',
|
||||
'Viewport.js',
|
||||
'ViewportDimension.js',
|
||||
'Viewports.js',
|
||||
'ViewportToolbar.js',
|
||||
)
|
||||
|
|
|
@ -5,4 +5,4 @@
|
|||
"use strict";
|
||||
|
||||
// The minimum viewport width and height
|
||||
exports.MIN_VIEWPORT_DIMENSION = 50;
|
||||
exports.MIN_VIEWPORT_DIMENSION = 280;
|
||||
|
|
|
@ -5,17 +5,21 @@
|
|||
* CSS Variables specific to the responsive design mode
|
||||
*/
|
||||
|
||||
:root {
|
||||
.theme-light {
|
||||
--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-color: #999797;
|
||||
--viewport-hover-color: var(--theme-body-color);
|
||||
--viewport-active-color: #3b3b3b;
|
||||
}
|
||||
|
||||
:root.theme-dark {
|
||||
.theme-dark {
|
||||
--rdm-box-shadow: 0 4px 4px 0 rgba(105, 105, 105, 0.26);
|
||||
--submit-button-active-background-color: var(--theme-toolbar-hover-active);
|
||||
--submit-button-active-color: var(--theme-selection-color);
|
||||
--viewport-color: #c6ccd0;
|
||||
--viewport-hover-color: #dde1e4;
|
||||
--viewport-active-color: #fcfcfc;
|
||||
}
|
||||
|
||||
|
@ -25,27 +29,26 @@
|
|||
|
||||
:root,
|
||||
input,
|
||||
select,
|
||||
button {
|
||||
font-size: 12px;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
html,
|
||||
body,
|
||||
#root {
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.theme-dark body,
|
||||
.theme-dark button,
|
||||
.theme-dark input {
|
||||
color: var(--theme-toolbar-color);
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#app {
|
||||
/* Center the viewports container */
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
padding-top: 15px;
|
||||
padding-bottom: 1%;
|
||||
position: relative;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
@ -53,102 +56,223 @@ body,
|
|||
* Common styles for shared components
|
||||
*/
|
||||
|
||||
.devtools-separator {
|
||||
.container {
|
||||
background-color: var(--theme-toolbar-background);
|
||||
border: 1px solid var(--theme-splitter-color);
|
||||
}
|
||||
|
||||
.toolbar-button {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
border: none;
|
||||
color: var(--viewport-color);
|
||||
}
|
||||
|
||||
.toolbar-button:empty:hover:not(:disabled),
|
||||
.toolbar-button:empty:-moz-any(:hover:active, .checked):not(:disabled),
|
||||
.toolbar-button:not(:empty),
|
||||
.toolbar-button:hover:not(:empty):not(:disabled):not(.checked) {
|
||||
/* Reset background from .devtools-button */
|
||||
background: none;
|
||||
}
|
||||
|
||||
.toolbar-button:active::before {
|
||||
filter: var(--theme-icon-checked-filter);
|
||||
}
|
||||
|
||||
.toolbar-button.selected {
|
||||
color: var(--viewport-active-color);
|
||||
}
|
||||
|
||||
.toolbar-button:not(:disabled):hover {
|
||||
color: var(--viewport-hover-color);
|
||||
}
|
||||
|
||||
select {
|
||||
-moz-appearance: none;
|
||||
color: var(--viewport-color);
|
||||
border: none;
|
||||
height: 100%;
|
||||
margin: 0 1px;
|
||||
padding: 0 8px;
|
||||
text-align: center;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
select.selected {
|
||||
color: var(--viewport-active-color);
|
||||
}
|
||||
|
||||
select:not(:disabled):hover {
|
||||
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. */
|
||||
select:focus {
|
||||
color: var(--viewport-active-color);
|
||||
}
|
||||
|
||||
select > option {
|
||||
text-align: left;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
select > option,
|
||||
select > option:hover {
|
||||
color: var(--viewport-active-color);
|
||||
}
|
||||
|
||||
select > option.divider {
|
||||
border-top: 1px solid var(--theme-splitter-color);
|
||||
height: 0px;
|
||||
padding: 0;
|
||||
font-size: 0px;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toolbar
|
||||
* Toggle Menu
|
||||
*/
|
||||
|
||||
#toolbar {
|
||||
background-color: var(--theme-tab-toolbar-background);
|
||||
border-bottom: 1px solid var(--theme-splitter-color);
|
||||
display: grid;
|
||||
grid-template-columns: min-content auto min-content;
|
||||
width: 100%;
|
||||
min-height: 29px;
|
||||
-moz-user-select: none;
|
||||
.devtools-toggle-menu {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
#toolbar-center-controls,
|
||||
#toolbar-end-controls {
|
||||
.devtools-toggle-menu .devtools-menu {
|
||||
display: none;
|
||||
flex-direction: column;
|
||||
align-items: start;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 100%;
|
||||
z-index: 1;
|
||||
padding: 5px;
|
||||
border-radius: 2px;
|
||||
background-color: var(--theme-toolbar-background);
|
||||
box-shadow: var(--rdm-box-shadow);
|
||||
}
|
||||
|
||||
.devtools-toggle-menu .devtools-menu.opened {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.devtools-toggle-menu .devtools-menu-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#toolbar-center-controls {
|
||||
justify-self: center;
|
||||
/**
|
||||
* Common background for dropdowns like select and toggle menu
|
||||
*/
|
||||
.toolbar-dropdown,
|
||||
.toolbar-dropdown.devtools-button,
|
||||
.toolbar-dropdown.devtools-button:hover:not(:empty):not(:disabled):not(.checked) {
|
||||
background-color: var(--theme-toolbar-background);
|
||||
background-image: var(--select-arrow-image);
|
||||
background-position: 100% 50%;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 7px;
|
||||
-moz-context-properties: fill;
|
||||
fill: currentColor;
|
||||
}
|
||||
|
||||
#rotate-button::before {
|
||||
background-image: url("./images/rotate-viewport.svg");
|
||||
/**
|
||||
* Global Toolbar
|
||||
*/
|
||||
|
||||
#global-toolbar {
|
||||
color: var(--theme-body-color-alt);
|
||||
border-radius: 2px;
|
||||
box-shadow: var(--rdm-box-shadow);
|
||||
margin: 0 0 15px 0;
|
||||
padding: 4px 5px;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
-moz-user-select: none;
|
||||
}
|
||||
|
||||
#touch-simulation-button::before {
|
||||
#global-toolbar > .title {
|
||||
border-right: 1px solid var(--theme-splitter-color);
|
||||
padding: 1px 6px 0 2px;
|
||||
}
|
||||
|
||||
#global-toolbar > .toolbar-button:first-of-type {
|
||||
margin-inline-start: 8px;
|
||||
}
|
||||
|
||||
#global-toolbar > .toolbar-button::before {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
background-size: cover;
|
||||
}
|
||||
|
||||
#global-toolbar .toolbar-dropdown {
|
||||
background-position-x: right 5px;
|
||||
border-right: 1px solid var(--theme-splitter-color);
|
||||
padding-right: 15px;
|
||||
/* padding-left: 0; */
|
||||
}
|
||||
|
||||
#global-touch-simulation-button::before {
|
||||
background-image: url("./images/touch-events.svg");
|
||||
}
|
||||
|
||||
#screenshot-button::before {
|
||||
#global-screenshot-button::before {
|
||||
background-image: url("./images/screenshot.svg");
|
||||
}
|
||||
|
||||
#settings-button::before {
|
||||
background-image: url("chrome://devtools/skin/images/settings.svg");
|
||||
}
|
||||
|
||||
#exit-button::before {
|
||||
#global-exit-button::before {
|
||||
background-image: url("chrome://devtools/skin/images/close.svg");
|
||||
}
|
||||
|
||||
#screenshot-button:disabled {
|
||||
#global-screenshot-button:disabled {
|
||||
filter: var(--theme-icon-checked-filter);
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
#device-selector {
|
||||
align-self: center;
|
||||
background-position: right 4px center;
|
||||
margin-inline-start: 4px;
|
||||
#global-network-throttling-selector {
|
||||
height: 15px;
|
||||
padding-left: 0;
|
||||
width: 8em;
|
||||
width: 103px;
|
||||
}
|
||||
|
||||
#device-selector .title {
|
||||
width: 85%;
|
||||
}
|
||||
|
||||
#device-pixel-ratio-menu {
|
||||
width: 6em;
|
||||
#global-device-pixel-ratio-selector {
|
||||
-moz-user-select: none;
|
||||
color: var(--viewport-color);
|
||||
height: 15px;
|
||||
/* `max-width` is here to keep the UI compact if the device pixel ratio changes to a
|
||||
repeating decimal value. This can happen if you zoom the UI (Cmd + Plus / Minus on
|
||||
macOS for example). */
|
||||
max-width: 8em;
|
||||
background-position: right 4px center;
|
||||
padding-left: 0;
|
||||
}
|
||||
|
||||
#viewports-container {
|
||||
display: flex;
|
||||
overflow: auto;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
#global-device-pixel-ratio-selector.focused,
|
||||
#global-device-pixel-ratio-selector:not(.disabled):hover {
|
||||
color: var(--viewport-hover-color);
|
||||
}
|
||||
|
||||
.theme-light #viewports-container {
|
||||
background-color: #F5F5F6;
|
||||
#global-device-pixel-ratio-selector:focus {
|
||||
color: var(--viewport-active-color);
|
||||
}
|
||||
|
||||
#global-device-pixel-ratio-selector.selected {
|
||||
color: var(--viewport-active-color);
|
||||
}
|
||||
|
||||
#global-device-pixel-ratio-selector > 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 */
|
||||
white-space: nowrap;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
#viewports.left-aligned {
|
||||
margin-left: 16px;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -167,6 +291,28 @@ body,
|
|||
position: relative;
|
||||
}
|
||||
|
||||
/**
|
||||
* Viewport Toolbar
|
||||
*/
|
||||
|
||||
.viewport-toolbar {
|
||||
border-width: 0;
|
||||
border-bottom-width: 1px;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.viewport-rotate-button {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.viewport-rotate-button::before {
|
||||
background-image: url("./images/rotate-viewport.svg");
|
||||
}
|
||||
|
||||
/**
|
||||
* Viewport Content
|
||||
*/
|
||||
|
@ -230,38 +376,48 @@ body,
|
|||
}
|
||||
|
||||
/**
|
||||
* Viewport Dimension Input
|
||||
* Viewport Dimension Label
|
||||
*/
|
||||
|
||||
.viewport-dimension {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 1px;
|
||||
justify-content: center;
|
||||
font: 10px sans-serif;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.viewport-dimension-editable {
|
||||
border-bottom: 1px solid transparent;
|
||||
}
|
||||
|
||||
.viewport-dimension-editable,
|
||||
.viewport-dimension-input {
|
||||
color: var(--theme-body-color-inactive);
|
||||
transition: all 0.25s ease;
|
||||
}
|
||||
|
||||
.viewport-dimension-editable.editing,
|
||||
.viewport-dimension-input.editing {
|
||||
color: var(--viewport-active-color);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.viewport-dimension-editable.editing {
|
||||
border-bottom: 1px solid var(--theme-selection-background);
|
||||
}
|
||||
|
||||
.viewport-dimension-editable.editing.invalid {
|
||||
border-bottom: 1px solid #d92215;
|
||||
}
|
||||
|
||||
.viewport-dimension-input {
|
||||
border: 1px solid var(--theme-splitter-color);
|
||||
outline: none;
|
||||
background: transparent;
|
||||
border: none;
|
||||
text-align: center;
|
||||
width: 3em;
|
||||
}
|
||||
|
||||
.viewport-dimension-input:focus {
|
||||
border: 1px solid var(--theme-selection-background);
|
||||
transition: all 0.2s ease-in-out;
|
||||
}
|
||||
|
||||
.viewport-dimension-input.invalid:focus {
|
||||
border: 1px solid #d92215;
|
||||
}
|
||||
|
||||
.theme-dark .viewport-dimension-input {
|
||||
background-color: var(--theme-tab-toolbar-background);
|
||||
}
|
||||
|
||||
.viewport-dimension-separator {
|
||||
-moz-user-select: none;
|
||||
padding: 0 0.3em;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -292,8 +448,6 @@ body,
|
|||
}
|
||||
|
||||
.device-modal {
|
||||
background-color: var(--theme-toolbar-background);
|
||||
border: 1px solid var(--theme-splitter-color);
|
||||
border-radius: 2px;
|
||||
box-shadow: var(--rdm-box-shadow);
|
||||
position: absolute;
|
||||
|
@ -337,14 +491,18 @@ body,
|
|||
margin: 20px 20px 0;
|
||||
}
|
||||
|
||||
#device-close-button {
|
||||
#device-close-button,
|
||||
#device-close-button::before {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
right: 2px;
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
#device-close-button::before {
|
||||
background-image: url("chrome://devtools/skin/images/close.svg");
|
||||
margin: -6px 0 0 -6px;
|
||||
}
|
||||
|
||||
.device-type {
|
||||
|
@ -360,7 +518,6 @@ body,
|
|||
}
|
||||
|
||||
.device-label {
|
||||
color: var(--theme-body-color);
|
||||
padding-bottom: 3px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
@ -376,8 +533,15 @@ body,
|
|||
flex: 1;
|
||||
}
|
||||
|
||||
.device-remove-button,
|
||||
.device-remove-button:empty::before {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
.device-remove-button:empty::before {
|
||||
background-image: url("chrome://devtools/skin/images/close.svg");
|
||||
margin: -6px 0 0 -6px;
|
||||
}
|
||||
|
||||
#device-submit-button {
|
||||
|
@ -445,23 +609,6 @@ body,
|
|||
margin: 0;
|
||||
}
|
||||
|
||||
#device-adder label > .viewport-dimension {
|
||||
border-bottom: 1px solid transparent;
|
||||
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 {
|
||||
background: transparent;
|
||||
border: 1px solid transparent;
|
||||
|
|
|
@ -13,6 +13,7 @@ const { require } = BrowserLoader({
|
|||
window
|
||||
});
|
||||
const Telemetry = require("devtools/client/shared/telemetry");
|
||||
const { loadAgentSheet } = require("./utils/css");
|
||||
|
||||
const { createFactory, createElement } =
|
||||
require("devtools/client/shared/vendor/react");
|
||||
|
@ -20,7 +21,7 @@ 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("./components/App"));
|
||||
const App = createFactory(require("./app"));
|
||||
const Store = require("./store");
|
||||
const { loadDevices } = require("./actions/devices");
|
||||
const { changeDisplayPixelRatio } = require("./actions/display-pixel-ratio");
|
||||
|
@ -38,6 +39,13 @@ const bootstrap = {
|
|||
store: null,
|
||||
|
||||
async init() {
|
||||
// Load a special UA stylesheet to reset certain styles such as dropdown
|
||||
// lists.
|
||||
loadAgentSheet(
|
||||
window,
|
||||
"resource://devtools/client/responsive.html/responsive-ua.css"
|
||||
);
|
||||
|
||||
this.telemetry.toolOpened("responsive");
|
||||
|
||||
const store = this.store = Store();
|
||||
|
@ -129,12 +137,7 @@ window.addInitialViewport = ({ uri, userContextId }) => {
|
|||
* Called by manager.js when tests want to check the viewport size.
|
||||
*/
|
||||
window.getViewportSize = () => {
|
||||
const { viewports } = bootstrap.store.getState();
|
||||
if (!viewports.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { width, height } = viewports[0];
|
||||
const { width, height } = bootstrap.store.getState().viewports[0];
|
||||
return { width, height };
|
||||
};
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
<script type="application/javascript"
|
||||
src="resource://devtools/client/responsive.html/index.js"></script>
|
||||
</head>
|
||||
<body class="theme-toolbar" role="application">
|
||||
<body class="theme-body" role="application">
|
||||
<div id="root"/>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -14,7 +14,6 @@ const TOOL_URL = "chrome://devtools/content/responsive.html/index.xhtml";
|
|||
loader.lazyRequireGetter(this, "DebuggerClient", "devtools/shared/client/debugger-client", true);
|
||||
loader.lazyRequireGetter(this, "DebuggerServer", "devtools/server/main", true);
|
||||
loader.lazyRequireGetter(this, "throttlingProfiles", "devtools/client/shared/components/throttling/profiles");
|
||||
loader.lazyRequireGetter(this, "SettingOnboardingTooltip", "devtools/client/responsive.html/setting-onboarding-tooltip");
|
||||
loader.lazyRequireGetter(this, "swapToInnerBrowser", "devtools/client/responsive.html/browser/swap", true);
|
||||
loader.lazyRequireGetter(this, "startup", "devtools/client/responsive.html/utils/window", true);
|
||||
loader.lazyRequireGetter(this, "message", "devtools/client/responsive.html/utils/message");
|
||||
|
@ -28,7 +27,6 @@ loader.lazyRequireGetter(this, "Telemetry", "devtools/client/shared/telemetry");
|
|||
|
||||
const RELOAD_CONDITION_PREF_PREFIX = "devtools.responsive.reloadConditions.";
|
||||
const RELOAD_NOTIFICATION_PREF = "devtools.responsive.reloadNotification.enabled";
|
||||
const SHOW_SETTING_TOOLTIP_PREF = "devtools.responsive.show-setting-tooltip";
|
||||
|
||||
function debug(msg) {
|
||||
// console.log(`RDM manager: ${msg}`);
|
||||
|
@ -379,12 +377,6 @@ ResponsiveUI.prototype = {
|
|||
debug("Wait until RDP server connect");
|
||||
await this.connectToServer();
|
||||
|
||||
// Show the settings onboarding tooltip
|
||||
if (Services.prefs.getBoolPref(SHOW_SETTING_TOOLTIP_PREF)) {
|
||||
this.settingOnboardingTooltip =
|
||||
new SettingOnboardingTooltip(ui.toolWindow.document);
|
||||
}
|
||||
|
||||
// Non-blocking message to tool UI to start any delayed init activities
|
||||
message.post(this.toolWindow, "post-init");
|
||||
|
||||
|
@ -444,11 +436,6 @@ ResponsiveUI.prototype = {
|
|||
}
|
||||
}
|
||||
|
||||
if (this.settingOnboardingTooltip) {
|
||||
this.settingOnboardingTooltip.destroy();
|
||||
this.settingOnboardingTooltip = null;
|
||||
}
|
||||
|
||||
// Destroy local state
|
||||
const swap = this.swap;
|
||||
this.browserWindow = null;
|
||||
|
|
|
@ -14,13 +14,14 @@ DIRS += [
|
|||
]
|
||||
|
||||
DevToolsModules(
|
||||
'app.js',
|
||||
'commands.js',
|
||||
'constants.js',
|
||||
'index.css',
|
||||
'index.js',
|
||||
'manager.js',
|
||||
'reducers.js',
|
||||
'setting-onboarding-tooltip.js',
|
||||
'responsive-ua.css',
|
||||
'store.js',
|
||||
'types.js',
|
||||
)
|
||||
|
|
|
@ -11,5 +11,4 @@ exports.networkThrottling = require("devtools/client/shared/components/throttlin
|
|||
exports.reloadConditions = require("./reducers/reload-conditions");
|
||||
exports.screenshot = require("./reducers/screenshot");
|
||||
exports.touchSimulation = require("./reducers/touch-simulation");
|
||||
exports.ui = require("./reducers/ui");
|
||||
exports.viewports = require("./reducers/viewports");
|
||||
|
|
|
@ -11,6 +11,5 @@ DevToolsModules(
|
|||
'reload-conditions.js',
|
||||
'screenshot.js',
|
||||
'touch-simulation.js',
|
||||
'ui.js',
|
||||
'viewports.js',
|
||||
)
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
/* 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 {
|
||||
TOGGLE_LEFT_ALIGNMENT,
|
||||
} = require("../actions/index");
|
||||
|
||||
const LEFT_ALIGNMENT_ENABLED = "devtools.responsive.leftAlignViewport.enabled";
|
||||
|
||||
const INITIAL_UI = {
|
||||
// Whether or not the viewports are left aligned.
|
||||
leftAlignmentEnabled: Services.prefs.getBoolPref(LEFT_ALIGNMENT_ENABLED),
|
||||
};
|
||||
|
||||
const reducers = {
|
||||
|
||||
[TOGGLE_LEFT_ALIGNMENT](ui, { enabled }) {
|
||||
const leftAlignmentEnabled = enabled !== undefined ?
|
||||
enabled : !ui.leftAlignmentEnabled;
|
||||
|
||||
Services.prefs.setBoolPref(LEFT_ALIGNMENT_ENABLED, leftAlignmentEnabled);
|
||||
|
||||
return Object.assign({}, ui, {
|
||||
leftAlignmentEnabled,
|
||||
});
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
module.exports = function(ui = INITIAL_UI, action) {
|
||||
const reducer = reducers[action.type];
|
||||
if (!reducer) {
|
||||
return ui;
|
||||
}
|
||||
return reducer(ui, action);
|
||||
};
|
|
@ -0,0 +1,6 @@
|
|||
@namespace url(http://www.w3.org/1999/xhtml);
|
||||
|
||||
/* Reset default UA styles for dropdown options */
|
||||
*|*::-moz-dropdown-list {
|
||||
border: 0 !important;
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
/* 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 { HTMLTooltip } = require("devtools/client/shared/widgets/tooltip/HTMLTooltip");
|
||||
|
||||
const { getStr } = require("./utils/l10n");
|
||||
|
||||
const SHOW_SETTING_TOOLTIP_PREF = "devtools.responsive.show-setting-tooltip";
|
||||
|
||||
const CONTAINER_WIDTH = 270;
|
||||
|
||||
/**
|
||||
* Setting onboarding tooltip that is shown on the setting menu button in the RDM toolbar
|
||||
* when the pref is on.
|
||||
*/
|
||||
class SettingOnboardingTooltip {
|
||||
constructor(doc) {
|
||||
this.doc = doc;
|
||||
this.tooltip = new HTMLTooltip(this.doc, { type: "arrow" });
|
||||
|
||||
this.onCloseButtonClick = this.onCloseButtonClick.bind(this);
|
||||
|
||||
const container = doc.createElement("div");
|
||||
container.className = "onboarding-container";
|
||||
|
||||
const icon = doc.createElement("span");
|
||||
icon.className = "onboarding-icon";
|
||||
container.appendChild(icon);
|
||||
|
||||
const content = doc.createElement("div");
|
||||
content.className = "onboarding-content";
|
||||
content.textContent = getStr("responsive.settingOnboarding.content");
|
||||
container.appendChild(content);
|
||||
|
||||
this.closeButton = doc.createElement("button");
|
||||
this.closeButton.className = "onboarding-close-button devtools-button";
|
||||
container.appendChild(this.closeButton);
|
||||
|
||||
this.closeButton.addEventListener("click", this.onCloseButtonClick);
|
||||
|
||||
this.tooltip.setContent(container, { width: CONTAINER_WIDTH });
|
||||
this.tooltip.show(this.doc.getElementById("settings-button"), {
|
||||
position: "bottom",
|
||||
});
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.closeButton.removeEventListener("click", this.onCloseButtonClick);
|
||||
|
||||
this.tooltip.destroy();
|
||||
|
||||
this.closeButton = null;
|
||||
this.doc = null;
|
||||
this.tooltip = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for the "click" event on the close button. Hides the onboarding tooltip
|
||||
* and sets the show three pane onboarding tooltip pref to false.
|
||||
*/
|
||||
onCloseButtonClick() {
|
||||
Services.prefs.setBoolPref(SHOW_SETTING_TOOLTIP_PREF, false);
|
||||
this.tooltip.hide();
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = SettingOnboardingTooltip;
|
|
@ -43,7 +43,7 @@ addRDMTask(TEST_URL, async function({ ui }) {
|
|||
await testUserAgent(ui, DEFAULT_UA);
|
||||
await testDevicePixelRatio(ui, DEFAULT_DPPX);
|
||||
await testTouchEventsOverride(ui, false);
|
||||
testViewportDeviceMenuLabel(ui, "Responsive");
|
||||
testViewportDeviceSelectLabel(ui, "no device selected");
|
||||
|
||||
// Test device with custom properties
|
||||
let reloaded = waitForViewportLoad(ui);
|
||||
|
@ -65,7 +65,7 @@ addRDMTask(TEST_URL, async function({ ui }) {
|
|||
await testUserAgent(ui, DEFAULT_UA);
|
||||
await testDevicePixelRatio(ui, DEFAULT_DPPX);
|
||||
await testTouchEventsOverride(ui, false);
|
||||
testViewportDeviceMenuLabel(ui, "Responsive");
|
||||
testViewportDeviceSelectLabel(ui, "no device selected");
|
||||
|
||||
// Test device with generic properties
|
||||
await selectDevice(ui, "Laptop (1366 x 768)");
|
||||
|
|
|
@ -34,10 +34,13 @@ addRDMTask(TEST_URL, async function({ ui }) {
|
|||
await waitUntilState(store, state => state.viewports.length == 1
|
||||
&& state.devices.listState == Types.loadableState.LOADED);
|
||||
|
||||
await openDeviceModal(ui);
|
||||
const deviceSelector = document.querySelector(".viewport-device-selector");
|
||||
const submitButton = document.querySelector("#device-submit-button");
|
||||
|
||||
openDeviceModal(ui);
|
||||
|
||||
info("Reveal device adder form, check that defaults match the viewport");
|
||||
const adderShow = document.getElementById("device-adder-show");
|
||||
const adderShow = document.querySelector("#device-adder-show");
|
||||
adderShow.click();
|
||||
testDeviceAdder(ui, {
|
||||
name: "Custom Device",
|
||||
|
@ -55,17 +58,14 @@ addRDMTask(TEST_URL, async function({ ui }) {
|
|||
const deviceCb = [...document.querySelectorAll(".device-input-checkbox")].find(cb => {
|
||||
return cb.value == device.name;
|
||||
});
|
||||
const submitButton = document.getElementById("device-submit-button");
|
||||
ok(deviceCb, "Custom device checkbox added to modal");
|
||||
ok(deviceCb.checked, "Custom device enabled");
|
||||
submitButton.click();
|
||||
|
||||
info("Look for custom device in device selector");
|
||||
const deviceSelector = document.getElementById("device-selector");
|
||||
await testMenuItems(toolWindow, deviceSelector, items => {
|
||||
const menuItem = items.find(item => item.getAttribute("label") === device.name);
|
||||
ok(menuItem, "Custom device menu item added to device selector");
|
||||
});
|
||||
const selectorOption =
|
||||
[...deviceSelector.options].find(opt => opt.value == device.name);
|
||||
ok(selectorOption, "Custom device option added to device selector");
|
||||
});
|
||||
|
||||
addRDMTask(TEST_URL, async function({ ui }) {
|
||||
|
@ -76,13 +76,16 @@ addRDMTask(TEST_URL, async function({ ui }) {
|
|||
await waitUntilState(store, state => state.viewports.length == 1
|
||||
&& state.devices.listState == Types.loadableState.LOADED);
|
||||
|
||||
const deviceSelector = document.querySelector(".viewport-device-selector");
|
||||
const submitButton = document.querySelector("#device-submit-button");
|
||||
|
||||
info("Select existing device from the selector");
|
||||
await selectDevice(ui, "Test Device");
|
||||
|
||||
await openDeviceModal(ui);
|
||||
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.querySelector("#device-adder-show");
|
||||
adderShow.click();
|
||||
testDeviceAdder(ui, Object.assign({}, device, {
|
||||
name: "Test Device (Custom)",
|
||||
|
@ -90,7 +93,6 @@ addRDMTask(TEST_URL, async function({ ui }) {
|
|||
|
||||
info("Remove previously added custom device");
|
||||
const deviceRemoveButton = document.querySelector(".device-remove-button");
|
||||
const submitButton = document.getElementById("device-submit-button");
|
||||
const removed = Promise.all([
|
||||
waitUntilState(store, state => state.devices.custom.length == 0),
|
||||
once(ui, "device-association-removed")
|
||||
|
@ -101,15 +103,10 @@ addRDMTask(TEST_URL, async function({ ui }) {
|
|||
|
||||
info("Ensure custom device was removed from device selector");
|
||||
await waitUntilState(store, state => state.viewports[0].device == "");
|
||||
const deviceSelectorTitle = document.querySelector("#device-selector .title");
|
||||
is(deviceSelectorTitle.textContent, "Responsive", "Device selector reset to no device");
|
||||
|
||||
info("Look for custom device in device selector");
|
||||
const deviceSelector = document.getElementById("device-selector");
|
||||
await testMenuItems(toolWindow, deviceSelector, menuItems => {
|
||||
const menuItem = menuItems.find(item => item.getAttribute("label") === device.name);
|
||||
ok(!menuItem, "Custom device option removed from device selector");
|
||||
});
|
||||
is(deviceSelector.value, "", "Device selector reset to no device");
|
||||
const selectorOption =
|
||||
[...deviceSelector.options].find(opt => opt.value == device.name);
|
||||
ok(!selectorOption, "Custom device option removed from device selector");
|
||||
|
||||
info("Ensure device properties like UA have been reset");
|
||||
await testUserAgent(ui, navigator.userAgent);
|
||||
|
@ -123,7 +120,10 @@ addRDMTask(TEST_URL, async function({ ui }) {
|
|||
await waitUntilState(store, state => state.viewports.length == 1
|
||||
&& state.devices.listState == Types.loadableState.LOADED);
|
||||
|
||||
await openDeviceModal(ui);
|
||||
const deviceSelector = document.querySelector(".viewport-device-selector");
|
||||
const submitButton = document.querySelector("#device-submit-button");
|
||||
|
||||
openDeviceModal(ui);
|
||||
|
||||
info("Reveal device adder form");
|
||||
const adderShow = document.querySelector("#device-adder-show");
|
||||
|
@ -136,17 +136,14 @@ addRDMTask(TEST_URL, async function({ ui }) {
|
|||
const deviceCb = [...document.querySelectorAll(".device-input-checkbox")].find(cb => {
|
||||
return cb.value == unicodeDevice.name;
|
||||
});
|
||||
const submitButton = document.getElementById("device-submit-button");
|
||||
ok(deviceCb, "Custom unicode device checkbox added to modal");
|
||||
ok(deviceCb.checked, "Custom unicode device enabled");
|
||||
submitButton.click();
|
||||
|
||||
info("Look for custom unicode device in device selector");
|
||||
const deviceSelector = document.getElementById("device-selector");
|
||||
await testMenuItems(toolWindow, deviceSelector, items => {
|
||||
const menuItem = items.find(i => i.getAttribute("label") === unicodeDevice.name);
|
||||
ok(menuItem, "Custom unicode device option added to device selector");
|
||||
});
|
||||
const selectorOption = [...deviceSelector.options].find(opt =>
|
||||
opt.value == unicodeDevice.name);
|
||||
ok(selectorOption, "Custom unicode device option added to device selector");
|
||||
});
|
||||
|
||||
addRDMTask(TEST_URL, async function({ ui }) {
|
||||
|
@ -157,15 +154,15 @@ addRDMTask(TEST_URL, async function({ ui }) {
|
|||
await waitUntilState(store, state => state.viewports.length == 1
|
||||
&& state.devices.listState == Types.loadableState.LOADED);
|
||||
|
||||
const deviceSelector = document.querySelector(".viewport-device-selector");
|
||||
|
||||
// Check if the unicode custom device is present in the list of device options since
|
||||
// we want to ensure that unicode device names are not forgotten after restarting RDM
|
||||
// see bug 1379687
|
||||
info("Look for custom unicode device in device selector");
|
||||
const deviceSelector = document.getElementById("device-selector");
|
||||
await testMenuItems(toolWindow, deviceSelector, items => {
|
||||
const menuItem = items.find(i => i.getAttribute("label") === unicodeDevice.name);
|
||||
ok(menuItem, "Custom unicode device option present in device selector");
|
||||
});
|
||||
const selectorOption = [...deviceSelector.options].find(opt =>
|
||||
opt.value == unicodeDevice.name);
|
||||
ok(selectorOption, "Custom unicode device option present in device selector");
|
||||
});
|
||||
|
||||
function testDeviceAdder(ui, expected) {
|
||||
|
|
|
@ -34,9 +34,10 @@ addRDMTask(TEST_URL, async function({ ui }) {
|
|||
await waitUntilState(store, state => state.viewports.length == 1
|
||||
&& state.devices.listState == Types.loadableState.LOADED);
|
||||
|
||||
const deviceSelector = document.getElementById("device-selector");
|
||||
const deviceSelector = document.querySelector(".viewport-device-selector");
|
||||
const submitButton = document.querySelector("#device-submit-button");
|
||||
|
||||
await openDeviceModal(ui);
|
||||
openDeviceModal(ui);
|
||||
|
||||
info("Reveal device adder form");
|
||||
let adderShow = document.querySelector("#device-adder-show");
|
||||
|
@ -53,7 +54,6 @@ addRDMTask(TEST_URL, async function({ ui }) {
|
|||
await addDeviceInModal(ui, device2);
|
||||
|
||||
info("Verify all custom devices default to enabled in modal");
|
||||
const submitButton = document.getElementById("device-submit-button");
|
||||
const deviceCbs =
|
||||
[...document.querySelectorAll(".device-type-custom .device-input-checkbox")];
|
||||
is(deviceCbs.length, 2, "Both devices have a checkbox in modal");
|
||||
|
@ -62,16 +62,15 @@ addRDMTask(TEST_URL, async function({ ui }) {
|
|||
}
|
||||
submitButton.click();
|
||||
|
||||
info("Look for device 1 and 2 in device selector");
|
||||
info("Look for device 1 in device selector");
|
||||
let deviceOption1 = [...deviceSelector.options].find(opt => opt.value == device1.name);
|
||||
ok(deviceOption1, "Test device 1 option added to device selector");
|
||||
|
||||
await testMenuItems(toolWindow, deviceSelector, menuItems => {
|
||||
const deviceItem1 = menuItems.find(i => i.getAttribute("label") === device1.name);
|
||||
const deviceItem2 = menuItems.find(i => i.getAttribute("label") === device2.name);
|
||||
ok(deviceItem1, "Test device 1 menu item added to device selector");
|
||||
ok(deviceItem2, "Test device 2 menu item added to device selector");
|
||||
});
|
||||
info("Look for device 2 in device selector");
|
||||
let deviceOption2 = [...deviceSelector.options].find(opt => opt.value == device2.name);
|
||||
ok(deviceOption2, "Test device 2 option added to device selector");
|
||||
|
||||
await openDeviceModal(ui);
|
||||
openDeviceModal(ui);
|
||||
|
||||
info("Remove device 2");
|
||||
const deviceRemoveButtons = [...document.querySelectorAll(".device-remove-button")];
|
||||
|
@ -81,13 +80,13 @@ addRDMTask(TEST_URL, async function({ ui }) {
|
|||
await removed;
|
||||
submitButton.click();
|
||||
|
||||
info("Ensure device 1 is still in device selector");
|
||||
deviceOption1 = [...deviceSelector.options].find(opt => opt.value == device1.name);
|
||||
ok(deviceOption1, "Test device 1 option exists");
|
||||
|
||||
info("Ensure device 2 is no longer in device selector");
|
||||
await testMenuItems(toolWindow, deviceSelector, menuItems => {
|
||||
const deviceItem1 = menuItems.find(i => i.getAttribute("label") === device1.name);
|
||||
const deviceItem2 = menuItems.find(i => i.getAttribute("label") === device2.name);
|
||||
ok(deviceItem1, "Test device 1 menu item exists");
|
||||
ok(!deviceItem2, "Test device 2 menu item removed");
|
||||
});
|
||||
deviceOption2 = [...deviceSelector.options].find(opt => opt.value == device2.name);
|
||||
ok(!deviceOption2, "Test device 2 option removed");
|
||||
});
|
||||
|
||||
addRDMTask(TEST_URL, async function({ ui }) {
|
||||
|
@ -98,17 +97,19 @@ addRDMTask(TEST_URL, async function({ ui }) {
|
|||
await waitUntilState(store, state => state.viewports.length == 1
|
||||
&& state.devices.listState == Types.loadableState.LOADED);
|
||||
|
||||
const deviceSelector = document.getElementById("device-selector");
|
||||
const deviceSelector = document.querySelector(".viewport-device-selector");
|
||||
|
||||
info("Ensure device 1 is still in device selector");
|
||||
await testMenuItems(toolWindow, deviceSelector, menuItems => {
|
||||
const deviceItem1 = menuItems.find(i => i.getAttribute("label") === device1.name);
|
||||
const deviceItem2 = menuItems.find(i => i.getAttribute("label") === device2.name);
|
||||
ok(deviceItem1, "Test device 1 menu item exists");
|
||||
ok(!deviceItem2, "Test device 2 option removed");
|
||||
});
|
||||
const deviceOption1 =
|
||||
[...deviceSelector.options].find(opt => opt.value == device1.name);
|
||||
ok(deviceOption1, "Test device 1 option exists");
|
||||
|
||||
await openDeviceModal(ui);
|
||||
info("Ensure device 2 is no longer in device selector");
|
||||
const deviceOption2 =
|
||||
[...deviceSelector.options].find(opt => opt.value == device2.name);
|
||||
ok(!deviceOption2, "Test device 2 option removed");
|
||||
|
||||
openDeviceModal(ui);
|
||||
|
||||
info("Ensure device 1 is still in device modal");
|
||||
const deviceCbs =
|
||||
|
|
|
@ -7,6 +7,7 @@ http://creativecommons.org/publicdomain/zero/1.0/ */
|
|||
|
||||
const TEST_URL = "data:text/html;charset=utf-8,";
|
||||
const Types = require("devtools/client/responsive.html/types");
|
||||
const { getStr } = require("devtools/client/responsive.html/utils/l10n");
|
||||
|
||||
// Set a wrong URL for the device list file
|
||||
add_task(async function() {
|
||||
|
@ -17,13 +18,18 @@ add_task(async function() {
|
|||
|
||||
addRDMTask(TEST_URL, async function({ ui }) {
|
||||
const { store, document } = ui.toolWindow;
|
||||
const button = document.getElementById("device-selector");
|
||||
const select = document.querySelector(".viewport-device-selector");
|
||||
|
||||
// Wait until the viewport has been added and the device list state indicates
|
||||
// an error
|
||||
await waitUntilState(store, state => state.viewports.length == 1
|
||||
&& state.devices.listState == Types.loadableState.ERROR);
|
||||
|
||||
// The device selector placeholder should be set accordingly
|
||||
const placeholder = select.options[select.selectedIndex].innerHTML;
|
||||
ok(placeholder == getStr("responsive.deviceListError"),
|
||||
"Device selector indicates an error");
|
||||
|
||||
// The device selector should be disabled
|
||||
ok(button.disabled, "Device selector is disabled");
|
||||
ok(select.disabled, "Device selector is disabled");
|
||||
});
|
||||
|
|
|
@ -17,7 +17,7 @@ addRDMTask(TEST_URL, async function({ ui }) {
|
|||
await waitUntilState(store, state => state.viewports.length == 1
|
||||
&& state.devices.listState == Types.loadableState.LOADED);
|
||||
|
||||
await openDeviceModal(ui);
|
||||
openDeviceModal(ui);
|
||||
|
||||
const preferredDevicesBefore = _loadPreferredDevices();
|
||||
|
||||
|
|
|
@ -22,17 +22,16 @@ const TEST_URL = "data:text/html;charset=utf-8,";
|
|||
const Types = require("devtools/client/responsive.html/types");
|
||||
|
||||
addRDMTask(TEST_URL, async function({ ui }) {
|
||||
const { toolWindow } = ui;
|
||||
const { store, document } = toolWindow;
|
||||
const deviceSelector = document.getElementById("device-selector");
|
||||
const modal = document.getElementById("device-modal-wrapper");
|
||||
const submitButton = document.getElementById("device-submit-button");
|
||||
const { store, document } = ui.toolWindow;
|
||||
const modal = document.querySelector("#device-modal-wrapper");
|
||||
const select = document.querySelector(".viewport-device-selector");
|
||||
const submitButton = document.querySelector("#device-submit-button");
|
||||
|
||||
// Wait until the viewport has been added and the device list has been loaded
|
||||
await waitUntilState(store, state => state.viewports.length == 1
|
||||
&& state.devices.listState == Types.loadableState.LOADED);
|
||||
|
||||
await openDeviceModal(ui);
|
||||
openDeviceModal(ui);
|
||||
|
||||
info("Checking displayed device checkboxes are checked in the device modal.");
|
||||
const checkedCbs = [...document.querySelectorAll(".device-input-checkbox")]
|
||||
|
@ -70,16 +69,14 @@ addRDMTask(TEST_URL, async function({ ui }) {
|
|||
ok(preferredDevices.added.has(value), value + " in user added list.");
|
||||
|
||||
info("Checking new device is added to the device selector.");
|
||||
await testMenuItems(toolWindow, deviceSelector, menuItems => {
|
||||
is(menuItems.length - 2, featuredCount + 1,
|
||||
"Got expected number of devices in device selector.");
|
||||
|
||||
const menuItem = menuItems.find(item => item.getAttribute("label") === name);
|
||||
ok(menuItem, value + " added to the device selector.");
|
||||
});
|
||||
let options = [...select.options];
|
||||
is(options.length - 2, featuredCount + 1,
|
||||
"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");
|
||||
await openDeviceModal(ui);
|
||||
openDeviceModal(ui);
|
||||
ok([...document.querySelectorAll(".device-input-checkbox")]
|
||||
.filter(cb => cb.checked && cb.value === value)[0],
|
||||
value + " is checked in the device modal.");
|
||||
|
@ -97,16 +94,14 @@ addRDMTask(TEST_URL, async function({ ui }) {
|
|||
ok(preferredDevices.removed.has(checkedVal), checkedVal + " in removed list");
|
||||
|
||||
info("Checking that the device is not in the device selector.");
|
||||
await testMenuItems(toolWindow, deviceSelector, menuItems => {
|
||||
is(menuItems.length - 2, featuredCount,
|
||||
"Got expected number of devices in device selector.");
|
||||
|
||||
const menuItem = menuItems.find(item => item.getAttribute("label") === checkedVal);
|
||||
ok(!menuItem, checkedVal + " removed from the device selector.");
|
||||
});
|
||||
options = [...select.options];
|
||||
is(options.length - 2, featuredCount,
|
||||
"Got expected number of devices in device selector.");
|
||||
ok(!options.filter(o => o.value === checkedVal)[0],
|
||||
checkedVal + " removed from the device selector.");
|
||||
|
||||
info("Reopen device modal and check device is correctly unchecked");
|
||||
await openDeviceModal(ui);
|
||||
openDeviceModal(ui);
|
||||
ok([...document.querySelectorAll(".device-input-checkbox")]
|
||||
.filter(cb => !cb.checked && cb.value === checkedVal)[0],
|
||||
checkedVal + " is unchecked in the device modal.");
|
||||
|
@ -116,14 +111,14 @@ addRDMTask(TEST_URL, async function({ ui }) {
|
|||
});
|
||||
|
||||
addRDMTask(TEST_URL, async function({ ui }) {
|
||||
const { toolWindow } = ui;
|
||||
const { store, document } = toolWindow;
|
||||
const { store, document } = ui.toolWindow;
|
||||
const select = document.querySelector(".viewport-device-selector");
|
||||
|
||||
// Wait until the viewport has been added and the device list has been loaded
|
||||
await waitUntilState(store, state => state.viewports.length == 1
|
||||
&& state.devices.listState == Types.loadableState.LOADED);
|
||||
|
||||
await openDeviceModal(ui);
|
||||
openDeviceModal(ui);
|
||||
|
||||
const remoteList = await getDevices();
|
||||
const featuredCount = remoteList.TYPES.reduce((total, type) => {
|
||||
|
@ -135,23 +130,17 @@ addRDMTask(TEST_URL, async function({ ui }) {
|
|||
|
||||
// Tests to prove that reloading the RDM didn't break our device list
|
||||
info("Checking new featured device appears in the device selector.");
|
||||
const deviceSelector = document.getElementById("device-selector");
|
||||
await testMenuItems(toolWindow, deviceSelector, items => {
|
||||
is(items.length - 2, featuredCount
|
||||
- preferredDevices.removed.size + preferredDevices.added.size,
|
||||
"Got expected number of devices in device selector.");
|
||||
const options = [...select.options];
|
||||
is(options.length - 2, featuredCount
|
||||
- preferredDevices.removed.size + preferredDevices.added.size,
|
||||
"Got expected number of devices in device selector.");
|
||||
|
||||
const added = items.find(i => i.getAttribute("label") === addedDevice.name);
|
||||
ok(added, "Dummy device added to the device selector.");
|
||||
ok(options.filter(o => o.value === addedDevice.name)[0],
|
||||
"dummy device added to the device selector.");
|
||||
|
||||
for (const name of preferredDevices.added.keys()) {
|
||||
const menuItem = items.find(item => item.getAttribute("label") === name);
|
||||
ok(menuItem, "Device added by user still in the device selector.");
|
||||
}
|
||||
ok(options.filter(o => preferredDevices.added.has(o.value))[0],
|
||||
"device added by user still in the device selector.");
|
||||
|
||||
for (const name of preferredDevices.removed.keys()) {
|
||||
const menuItem = items.find(item => item.getAttribute("label") === name);
|
||||
ok(!menuItem, "Device removed by user not in the device selector.");
|
||||
}
|
||||
});
|
||||
ok(!options.filter(o => preferredDevices.removed.has(o.value))[0],
|
||||
"device removed by user not in the device selector.");
|
||||
});
|
||||
|
|
|
@ -4,10 +4,9 @@ http://creativecommons.org/publicdomain/zero/1.0/ */
|
|||
"use strict";
|
||||
|
||||
// Tests changing viewport device pixel ratio
|
||||
|
||||
const TEST_URL = "data:text/html;charset=utf-8,DevicePixelRatio list test";
|
||||
const DEFAULT_DPPX = window.devicePixelRatio;
|
||||
const VIEWPORT_DPPX = DEFAULT_DPPX + 1;
|
||||
const VIEWPORT_DPPX = DEFAULT_DPPX + 2;
|
||||
const Types = require("devtools/client/responsive.html/types");
|
||||
|
||||
const testDevice = {
|
||||
|
@ -51,7 +50,7 @@ async function testDefaults(ui) {
|
|||
value: DEFAULT_DPPX,
|
||||
disabled: false,
|
||||
});
|
||||
testViewportDeviceMenuLabel(ui, "Responsive");
|
||||
testViewportDeviceSelectLabel(ui, "no device selected");
|
||||
}
|
||||
|
||||
async function testChangingDevice(ui) {
|
||||
|
@ -65,7 +64,7 @@ async function testChangingDevice(ui) {
|
|||
value: testDevice.pixelRatio,
|
||||
disabled: true,
|
||||
});
|
||||
testViewportDeviceMenuLabel(ui, testDevice.name);
|
||||
testViewportDeviceSelectLabel(ui, testDevice.name);
|
||||
}
|
||||
|
||||
async function testResetWhenResizingViewport(ui) {
|
||||
|
@ -83,7 +82,7 @@ async function testResetWhenResizingViewport(ui) {
|
|||
value: DEFAULT_DPPX,
|
||||
disabled: false,
|
||||
});
|
||||
testViewportDeviceMenuLabel(ui, "Responsive");
|
||||
testViewportDeviceSelectLabel(ui, "no device selected");
|
||||
}
|
||||
|
||||
async function testChangingDevicePixelRatio(ui) {
|
||||
|
@ -96,17 +95,17 @@ async function testChangingDevicePixelRatio(ui) {
|
|||
value: VIEWPORT_DPPX,
|
||||
disabled: false,
|
||||
});
|
||||
testViewportDeviceMenuLabel(ui, "Responsive");
|
||||
testViewportDeviceSelectLabel(ui, "no device selected");
|
||||
}
|
||||
|
||||
function testViewportDevicePixelRatioSelect(ui, expected) {
|
||||
info("Test viewport's DevicePixelRatio Select");
|
||||
|
||||
const button = ui.toolWindow.document.getElementById("device-pixel-ratio-menu");
|
||||
const title = ui.toolWindow.document.querySelector("#device-pixel-ratio-menu .title");
|
||||
is(title.textContent, `DPR: ${expected.value}`,
|
||||
const select =
|
||||
ui.toolWindow.document.querySelector("#global-device-pixel-ratio-selector");
|
||||
is(select.value, expected.value,
|
||||
`DevicePixelRatio Select value should be: ${expected.value}`);
|
||||
is(button.disabled, expected.disabled,
|
||||
is(select.disabled, expected.disabled,
|
||||
`DevicePixelRatio Select should be ${expected.disabled ? "disabled" : "enabled"}.`);
|
||||
}
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ async function waitBootstrap(ui) {
|
|||
async function testExitButton({ui, manager}) {
|
||||
await waitBootstrap(ui);
|
||||
|
||||
const exitButton = ui.toolWindow.document.getElementById("exit-button");
|
||||
const exitButton = ui.toolWindow.document.getElementById("global-exit-button");
|
||||
|
||||
ok(manager.isActiveForTab(ui.tab),
|
||||
"Responsive Design Mode active for the tab");
|
||||
|
|
|
@ -31,8 +31,10 @@ addRDMTask(TEST_URL, async function({ ui, manager }) {
|
|||
});
|
||||
|
||||
function testNetworkThrottlingSelectorLabel(ui, expected) {
|
||||
const title = ui.toolWindow.document.querySelector("#network-throttling-menu .title");
|
||||
is(title.textContent, expected, `Button title should be changed to ${expected}`);
|
||||
const selector = "#global-network-throttling-selector";
|
||||
const select = ui.toolWindow.document.querySelector(selector);
|
||||
is(select.selectedOptions[0].textContent, expected,
|
||||
`Select label should be changed to ${expected}`);
|
||||
}
|
||||
|
||||
var testNetworkThrottlingState = async function(ui, expected) {
|
||||
|
|
|
@ -34,7 +34,7 @@ addRDMTask(TEST_URL, async function({ ui: {toolWindow} }) {
|
|||
await waitUntilState(store, state => state.viewports.length == 1);
|
||||
|
||||
info("Click the screenshot button");
|
||||
const screenshotButton = document.getElementById("screenshot-button");
|
||||
const screenshotButton = document.getElementById("global-screenshot-button");
|
||||
screenshotButton.click();
|
||||
|
||||
const whenScreenshotSucceeded = waitUntilScreenshot();
|
||||
|
|
|
@ -49,7 +49,7 @@ async function testDefaults(ui) {
|
|||
info("Test Defaults");
|
||||
|
||||
await testTouchEventsOverride(ui, false);
|
||||
testViewportDeviceMenuLabel(ui, "Responsive");
|
||||
testViewportDeviceSelectLabel(ui, "no device selected");
|
||||
}
|
||||
|
||||
async function testChangingDevice(ui) {
|
||||
|
@ -58,7 +58,7 @@ async function testChangingDevice(ui) {
|
|||
await selectDevice(ui, testDevice.name);
|
||||
await waitForViewportResizeTo(ui, testDevice.width, testDevice.height);
|
||||
await testTouchEventsOverride(ui, true);
|
||||
testViewportDeviceMenuLabel(ui, testDevice.name);
|
||||
testViewportDeviceSelectLabel(ui, testDevice.name);
|
||||
}
|
||||
|
||||
async function testResizingViewport(ui, device, touch) {
|
||||
|
@ -74,7 +74,7 @@ async function testResizingViewport(ui, device, touch) {
|
|||
await deviceRemoved;
|
||||
}
|
||||
await testTouchEventsOverride(ui, touch);
|
||||
testViewportDeviceMenuLabel(ui, "Responsive");
|
||||
testViewportDeviceSelectLabel(ui, "no device selected");
|
||||
}
|
||||
|
||||
async function testEnableTouchSimulation(ui) {
|
||||
|
|
|
@ -164,7 +164,7 @@ async function testWithMetaViewportDisabled(ui) {
|
|||
|
||||
function testTouchButton(ui) {
|
||||
const { document } = ui.toolWindow;
|
||||
const touchButton = document.getElementById("touch-simulation-button");
|
||||
const touchButton = document.querySelector("#global-touch-simulation-button");
|
||||
|
||||
ok(touchButton.classList.contains("checked"),
|
||||
"Touch simulation is active at end of test.");
|
||||
|
|
|
@ -31,18 +31,15 @@ Services.scriptloader.loadSubScript(
|
|||
"chrome://mochitests/content/browser/devtools/client/inspector/test/shared-head.js",
|
||||
this);
|
||||
|
||||
const { _loadPreferredDevices } = require("devtools/client/responsive.html/actions/devices");
|
||||
const { getStr } = require("devtools/client/responsive.html/utils/l10n");
|
||||
const { getTopLevelWindow } = require("devtools/client/responsive.html/utils/window");
|
||||
const { addDevice, removeDevice, removeLocalDevices } = require("devtools/client/shared/devices");
|
||||
const asyncStorage = require("devtools/shared/async-storage");
|
||||
|
||||
loader.lazyRequireGetter(this, "ResponsiveUIManager", "devtools/client/responsive.html/manager", true);
|
||||
|
||||
const E10S_MULTI_ENABLED = Services.prefs.getIntPref("dom.ipc.processCount") > 1;
|
||||
const TEST_URI_ROOT = "http://example.com/browser/devtools/client/responsive.html/test/browser/";
|
||||
const OPEN_DEVICE_MODAL_VALUE = "OPEN_DEVICE_MODAL";
|
||||
const RELOAD_CONDITION_PREF_PREFIX = "devtools.responsive.reloadConditions.";
|
||||
|
||||
const { _loadPreferredDevices } = require("devtools/client/responsive.html/actions/devices");
|
||||
const asyncStorage = require("devtools/shared/async-storage");
|
||||
const { addDevice, removeDevice, removeLocalDevices } = require("devtools/client/shared/devices");
|
||||
|
||||
SimpleTest.requestCompleteLog();
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
|
@ -55,8 +52,6 @@ Services.prefs.setCharPref("devtools.devices.url", TEST_URI_ROOT + "devices.json
|
|||
// The appearance of this notification causes intermittent behavior in some tests that
|
||||
// send mouse events, since it causes the content to shift when it appears.
|
||||
Services.prefs.setBoolPref("devtools.responsive.reloadNotification.enabled", false);
|
||||
// Don't show the setting onboarding tooltip in the test suites.
|
||||
Services.prefs.setBoolPref("devtools.responsive.show-setting-tooltip", false);
|
||||
|
||||
registerCleanupFunction(async () => {
|
||||
Services.prefs.clearUserPref("devtools.devices.url");
|
||||
|
@ -64,11 +59,12 @@ registerCleanupFunction(async () => {
|
|||
Services.prefs.clearUserPref("devtools.responsive.html.displayedDeviceList");
|
||||
Services.prefs.clearUserPref("devtools.responsive.reloadConditions.touchSimulation");
|
||||
Services.prefs.clearUserPref("devtools.responsive.reloadConditions.userAgent");
|
||||
Services.prefs.clearUserPref("devtools.responsive.show-setting-tooltip");
|
||||
await asyncStorage.removeItem("devtools.devices.url_cache");
|
||||
await removeLocalDevices();
|
||||
});
|
||||
|
||||
loader.lazyRequireGetter(this, "ResponsiveUIManager", "devtools/client/responsive.html/manager", true);
|
||||
|
||||
/**
|
||||
* Open responsive design mode for the given tab.
|
||||
*/
|
||||
|
@ -233,78 +229,51 @@ async function testViewportResize(ui, selector, moveBy,
|
|||
`The y move of ${selector} is as expected`);
|
||||
}
|
||||
|
||||
async function openDeviceModal(ui) {
|
||||
const { document } = ui.toolWindow;
|
||||
const modal = document.getElementById("device-modal-wrapper");
|
||||
function openDeviceModal({ toolWindow }) {
|
||||
const { document } = toolWindow;
|
||||
const { Simulate } = toolWindow.require("devtools/client/shared/vendor/react-dom-test-utils");
|
||||
const select = document.querySelector(".viewport-device-selector");
|
||||
const modal = document.querySelector("#device-modal-wrapper");
|
||||
|
||||
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.");
|
||||
await selectMenuItem(ui, "#device-selector", getStr("responsive.editDeviceList2"));
|
||||
|
||||
select.value = OPEN_DEVICE_MODAL_VALUE;
|
||||
Simulate.change(select);
|
||||
ok(modal.classList.contains("opened") && !modal.classList.contains("closed"),
|
||||
"The device modal is displayed.");
|
||||
}
|
||||
|
||||
async function selectMenuItem({ toolWindow }, selector, value) {
|
||||
function changeSelectValue({ toolWindow }, selector, value) {
|
||||
const { document } = toolWindow;
|
||||
|
||||
const button = document.querySelector(selector);
|
||||
isnot(button, null, `Selector "${selector}" should match an existing element.`);
|
||||
const { Simulate } =
|
||||
toolWindow.require("devtools/client/shared/vendor/react-dom-test-utils");
|
||||
|
||||
info(`Selecting ${value} in ${selector}.`);
|
||||
|
||||
await testMenuItems(toolWindow, button, items => {
|
||||
const menuItem = items.find(item => item.getAttribute("label") === value);
|
||||
isnot(menuItem, undefined, `Value "${value}" should match an existing menu item.`);
|
||||
menuItem.click();
|
||||
});
|
||||
}
|
||||
const select = document.querySelector(selector);
|
||||
isnot(select, null, `selector "${selector}" should match an existing element.`);
|
||||
|
||||
/**
|
||||
* Runs the menu items from the button's context menu against a test function.
|
||||
*
|
||||
* @param {Window} toolWindow
|
||||
* A window reference.
|
||||
* @param {Element} button
|
||||
* The button that will show a context menu when clicked.
|
||||
* @param {Function} testFn
|
||||
* A test function that will be ran with the found menu item in the context menu
|
||||
* as an argument.
|
||||
*/
|
||||
function testMenuItems(toolWindow, button, testFn) {
|
||||
// The context menu appears only in the top level window, which is different from
|
||||
// the inner toolWindow.
|
||||
const win = getTopLevelWindow(toolWindow);
|
||||
const option = [...select.options].find(o => o.value === String(value));
|
||||
isnot(option, undefined, `value "${value}" should match an existing option.`);
|
||||
|
||||
return new Promise(resolve => {
|
||||
win.document.addEventListener("popupshown", () => {
|
||||
const popup = win.document.querySelector("menupopup[menu-api=\"true\"]");
|
||||
const menuItems = [...popup.children];
|
||||
|
||||
testFn(menuItems);
|
||||
|
||||
popup.hidePopup();
|
||||
resolve();
|
||||
}, { once: true });
|
||||
|
||||
button.click();
|
||||
});
|
||||
select.value = value;
|
||||
Simulate.change(select);
|
||||
}
|
||||
|
||||
const selectDevice = (ui, value) => Promise.all([
|
||||
once(ui, "device-changed"),
|
||||
selectMenuItem(ui, "#device-selector", value)
|
||||
changeSelectValue(ui, ".viewport-device-selector", value)
|
||||
]);
|
||||
|
||||
const selectDevicePixelRatio = (ui, value) =>
|
||||
selectMenuItem(ui, "#device-pixel-ratio-menu", `DPR: ${value}`);
|
||||
changeSelectValue(ui, "#global-device-pixel-ratio-selector", value);
|
||||
|
||||
const selectNetworkThrottling = (ui, value) => Promise.all([
|
||||
once(ui, "network-throttling-changed"),
|
||||
selectMenuItem(ui, "#network-throttling-menu", value)
|
||||
changeSelectValue(ui, "#global-network-throttling-selector", value)
|
||||
]);
|
||||
|
||||
function getSessionHistory(browser) {
|
||||
|
@ -377,7 +346,7 @@ async function waitForClientClose(ui) {
|
|||
|
||||
async function testTouchEventsOverride(ui, expected) {
|
||||
const { document } = ui.toolWindow;
|
||||
const touchButton = document.getElementById("touch-simulation-button");
|
||||
const touchButton = document.querySelector("#global-touch-simulation-button");
|
||||
|
||||
const flag = await ui.emulationFront.getTouchEventsOverride();
|
||||
is(flag === Ci.nsIDocShell.TOUCHEVENTS_OVERRIDE_ENABLED, expected,
|
||||
|
@ -386,16 +355,17 @@ async function testTouchEventsOverride(ui, expected) {
|
|||
`Touch simulation button should be ${expected ? "" : "in"}active.`);
|
||||
}
|
||||
|
||||
function testViewportDeviceMenuLabel(ui, expected) {
|
||||
function testViewportDeviceSelectLabel(ui, expected) {
|
||||
info("Test viewport's device select label");
|
||||
|
||||
const label = ui.toolWindow.document.querySelector("#device-selector .title");
|
||||
is(label.textContent, expected, `Device Select value should be: ${expected}`);
|
||||
const select = ui.toolWindow.document.querySelector(".viewport-device-selector");
|
||||
is(select.selectedOptions[0].textContent, expected,
|
||||
`Device Select value should be: ${expected}`);
|
||||
}
|
||||
|
||||
async function toggleTouchSimulation(ui) {
|
||||
const { document } = ui.toolWindow;
|
||||
const touchButton = document.getElementById("touch-simulation-button");
|
||||
const touchButton = document.querySelector("#global-touch-simulation-button");
|
||||
const changed = once(ui, "touch-simulation-changed");
|
||||
const loaded = waitForViewportLoad(ui);
|
||||
touchButton.click();
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
/* 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 { getDOMWindowUtils } = require("./window");
|
||||
|
||||
/**
|
||||
* Synchronously loads an agent style sheet from `uri` and adds it to the list of
|
||||
* additional style sheets of the document. The sheets added takes effect immediately,
|
||||
* and only on the document of the `window` given.
|
||||
*/
|
||||
function loadAgentSheet(window, url) {
|
||||
const winUtils = getDOMWindowUtils(window);
|
||||
winUtils.loadSheetUsingURIString(url, winUtils.AGENT_SHEET);
|
||||
}
|
||||
exports.loadAgentSheet = loadAgentSheet;
|
|
@ -5,6 +5,7 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
DevToolsModules(
|
||||
'css.js',
|
||||
'e10s.js',
|
||||
'key.js',
|
||||
'l10n.js',
|
||||
|
|
|
@ -9,10 +9,10 @@ const Services = require("Services");
|
|||
/**
|
||||
* Returns the `nsIDOMWindow` toplevel window for any child/inner window
|
||||
*/
|
||||
function getTopLevelWindow(window) {
|
||||
function getToplevelWindow(window) {
|
||||
return window.docShell.rootTreeItem.domWindow;
|
||||
}
|
||||
exports.getTopLevelWindow = getTopLevelWindow;
|
||||
exports.getToplevelWindow = getToplevelWindow;
|
||||
|
||||
function getDOMWindowUtils(window) {
|
||||
return window.windowUtils;
|
||||
|
|
|
@ -5,8 +5,7 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
DevToolsModules(
|
||||
'MenuButton.js',
|
||||
'MenuItem.js',
|
||||
'MenuList.js',
|
||||
'utils.js',
|
||||
'MenuButton.js',
|
||||
'MenuItem.js',
|
||||
'MenuList.js',
|
||||
)
|
||||
|
|
|
@ -1,93 +0,0 @@
|
|||
/* 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 { 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 throttlingProfiles = require("./profiles");
|
||||
const Types = require("./types");
|
||||
|
||||
// Localization
|
||||
const { LocalizationHelper } = require("devtools/shared/l10n");
|
||||
const L10N = new LocalizationHelper(
|
||||
"devtools/client/locales/network-throttling.properties");
|
||||
const NO_THROTTLING_LABEL = L10N.getStr("responsive.noThrottling");
|
||||
|
||||
loader.lazyRequireGetter(this, "showMenu", "devtools/client/shared/components/menu/utils", true);
|
||||
|
||||
/**
|
||||
* This component represents selector button that can be used
|
||||
* to throttle network bandwidth.
|
||||
*/
|
||||
class NetworkThrottlingMenu extends PureComponent {
|
||||
static get propTypes() {
|
||||
return {
|
||||
networkThrottling: PropTypes.shape(Types.networkThrottling).isRequired,
|
||||
onChangeNetworkThrottling: PropTypes.func.isRequired,
|
||||
useTopLevelWindow: PropTypes.bool,
|
||||
};
|
||||
}
|
||||
|
||||
static get defaultProps() {
|
||||
return {
|
||||
useTopLevelWindow: false,
|
||||
};
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.onShowThrottlingMenu = this.onShowThrottlingMenu.bind(this);
|
||||
}
|
||||
|
||||
onShowThrottlingMenu(event) {
|
||||
const {
|
||||
networkThrottling,
|
||||
onChangeNetworkThrottling,
|
||||
useTopLevelWindow,
|
||||
} = this.props;
|
||||
|
||||
const menuItems = throttlingProfiles.map(profile => {
|
||||
return {
|
||||
label: profile.id,
|
||||
type: "checkbox",
|
||||
checked: networkThrottling.enabled && profile.id == networkThrottling.profile,
|
||||
click: () => onChangeNetworkThrottling(true, profile.id),
|
||||
};
|
||||
});
|
||||
|
||||
menuItems.unshift("-");
|
||||
|
||||
menuItems.unshift({
|
||||
label: NO_THROTTLING_LABEL,
|
||||
type: "checkbox",
|
||||
checked: !networkThrottling.enabled,
|
||||
click: () => onChangeNetworkThrottling(false, ""),
|
||||
});
|
||||
|
||||
showMenu(menuItems, { button: event.target, useTopLevelWindow });
|
||||
}
|
||||
|
||||
render() {
|
||||
const { networkThrottling } = this.props;
|
||||
const selectedProfile = networkThrottling.enabled ?
|
||||
networkThrottling.profile : NO_THROTTLING_LABEL;
|
||||
|
||||
return (
|
||||
dom.button(
|
||||
{
|
||||
id: "network-throttling-menu",
|
||||
className: "devtools-button devtools-dropdown-button",
|
||||
title: selectedProfile,
|
||||
onClick: this.onShowThrottlingMenu,
|
||||
},
|
||||
dom.span({ className: "title" }, selectedProfile)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = NetworkThrottlingMenu;
|
|
@ -0,0 +1,112 @@
|
|||
/* 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 { PureComponent } = require("devtools/client/shared/vendor/react");
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
|
||||
const Types = require("./types");
|
||||
const throttlingProfiles = require("./profiles");
|
||||
|
||||
// Localization
|
||||
const { LocalizationHelper } = require("devtools/shared/l10n");
|
||||
const L10N = new LocalizationHelper(
|
||||
"devtools/client/locales/network-throttling.properties");
|
||||
|
||||
/**
|
||||
* This component represents selector button that can be used
|
||||
* to throttle network bandwidth.
|
||||
*/
|
||||
class NetworkThrottlingSelector extends PureComponent {
|
||||
static get propTypes() {
|
||||
return {
|
||||
className: PropTypes.string,
|
||||
networkThrottling: PropTypes.shape(Types.networkThrottling).isRequired,
|
||||
onChangeNetworkThrottling: PropTypes.func.isRequired,
|
||||
};
|
||||
}
|
||||
|
||||
static get defaultProps() {
|
||||
return {
|
||||
className: "",
|
||||
};
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.onSelectChange = this.onSelectChange.bind(this);
|
||||
}
|
||||
|
||||
onSelectChange({ target }) {
|
||||
const {
|
||||
onChangeNetworkThrottling,
|
||||
} = this.props;
|
||||
|
||||
if (target.value == L10N.getStr("responsive.noThrottling")) {
|
||||
onChangeNetworkThrottling(false, "");
|
||||
return;
|
||||
}
|
||||
|
||||
for (const profile of throttlingProfiles) {
|
||||
if (profile.id === target.value) {
|
||||
onChangeNetworkThrottling(true, profile.id);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const {
|
||||
className,
|
||||
networkThrottling,
|
||||
} = this.props;
|
||||
|
||||
let selectClass = className + " toolbar-dropdown";
|
||||
let selectedProfile;
|
||||
if (networkThrottling.enabled) {
|
||||
selectClass += " selected";
|
||||
selectedProfile = networkThrottling.profile;
|
||||
} else {
|
||||
selectedProfile = L10N.getStr("responsive.noThrottling");
|
||||
}
|
||||
|
||||
const listContent = [
|
||||
dom.option(
|
||||
{
|
||||
key: "disabled",
|
||||
},
|
||||
L10N.getStr("responsive.noThrottling")
|
||||
),
|
||||
dom.option(
|
||||
{
|
||||
key: "divider",
|
||||
className: "divider",
|
||||
disabled: true,
|
||||
}
|
||||
),
|
||||
throttlingProfiles.map(profile => {
|
||||
return dom.option(
|
||||
{
|
||||
key: profile.id,
|
||||
},
|
||||
profile.id
|
||||
);
|
||||
}),
|
||||
];
|
||||
|
||||
return dom.select(
|
||||
{
|
||||
id: "global-network-throttling-selector",
|
||||
className: selectClass,
|
||||
value: selectedProfile,
|
||||
onChange: this.onSelectChange,
|
||||
},
|
||||
...listContent
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = NetworkThrottlingSelector;
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
DevToolsModules(
|
||||
'actions.js',
|
||||
'NetworkThrottlingMenu.js',
|
||||
'NetworkThrottlingSelector.js',
|
||||
'profiles.js',
|
||||
'reducer.js',
|
||||
'types.js',
|
||||
|
|
|
@ -352,7 +352,7 @@ checkbox:-moz-focusring {
|
|||
.devtools-button:empty:not(:disabled):-moz-any(:hover:active,.checked),
|
||||
.devtools-toolbarbutton:not([label]):-moz-any([checked],[open],:hover:active),
|
||||
.devtools-button[aria-haspopup="menu"][aria-expanded="true"] {
|
||||
background-color: var(--toolbarbutton-hover-background);
|
||||
background: var(--toolbarbutton-hover-background);
|
||||
border-color: var(--toolbarbutton-hover-border-color);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
<!-- 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/. -->
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fill="context-fill" fill-rule="evenodd" clip-rule="evenodd" d="M12 22a1 1 0 0 1-1-1v-3.083a5.966 5.966 0 0 1-2.477-1.026l-2.18 2.18a1 1 0 0 1-1.414-1.414l2.18-2.18A5.967 5.967 0 0 1 6.083 13H3a1 1 0 1 1 0-2h3.083a5.968 5.968 0 0 1 1.026-2.477l-2.18-2.18A1 1 0 0 1 6.343 4.93l2.18 2.18A5.968 5.968 0 0 1 11 6.083V3a1 1 0 1 1 2 0v3.083a5.967 5.967 0 0 1 2.476 1.026l2.18-2.18a1 1 0 1 1 1.415 1.414l-2.18 2.18A5.966 5.966 0 0 1 17.917 11H21a1 1 0 1 1 0 2h-3.083a5.966 5.966 0 0 1-1.026 2.476l2.18 2.18a1 1 0 0 1-1.414 1.415l-2.18-2.18A5.966 5.966 0 0 1 13 17.917V21a1 1 0 0 1-1 1zM8 12a4 4 0 1 1 8 0 4 4 0 0 1-8 0z"></path>
|
||||
</svg>
|
До Ширина: | Высота: | Размер: 932 B |
|
@ -202,37 +202,3 @@ splitter.devtools-horizontal-splitter,
|
|||
.devtools-side-splitter {
|
||||
background-color: var(--theme-splitter-color);
|
||||
}
|
||||
|
||||
/* Dropdown Menu Button */
|
||||
.devtools-dropdown-button {
|
||||
background-image: url("chrome://devtools/skin/images/select-arrow.svg") !important;
|
||||
background-repeat: no-repeat !important;
|
||||
overflow: hidden;
|
||||
fill: var(--theme-toolbar-photon-icon-color);
|
||||
-moz-context-properties: fill;
|
||||
}
|
||||
|
||||
.devtools-dropdown-button:not(:hover) {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
/* Style for title holder inside the dropdown menu button */
|
||||
.devtools-dropdown-button .title {
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
padding-top: 0.15em;
|
||||
text-align: center;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
#network-throttling-menu {
|
||||
background-position: right 4px center;
|
||||
padding-left: 0;
|
||||
width: 92px;
|
||||
}
|
||||
|
||||
/* Make sure spacing between text and icon is uniform */
|
||||
#network-throttling-menu .title {
|
||||
width: 85%;
|
||||
}
|
||||
|
|
|
@ -563,9 +563,9 @@
|
|||
padding: 7px;
|
||||
}
|
||||
|
||||
/* Tooltip: Onboarding Tooltip */
|
||||
/* Tooltip: 3 Pane Inspecot Onboarding Tooltip */
|
||||
|
||||
.onboarding-container {
|
||||
.three-pane-onboarding-container {
|
||||
align-items: center;
|
||||
background-color: var(--theme-toolbar-background);
|
||||
box-sizing: border-box;
|
||||
|
@ -577,7 +577,7 @@
|
|||
-moz-user-select: none;
|
||||
}
|
||||
|
||||
.onboarding-icon {
|
||||
.three-pane-onboarding-icon {
|
||||
display: inline-block;
|
||||
background-size: 21px;
|
||||
width: 21px;
|
||||
|
@ -586,29 +586,29 @@
|
|||
background-image: url("chrome://devtools/skin/images/fox-smiling.svg");
|
||||
}
|
||||
|
||||
.onboarding-content {
|
||||
.three-pane-onboarding-content {
|
||||
flex: 1;
|
||||
padding-inline-start: 5px;
|
||||
}
|
||||
|
||||
.onboarding-link {
|
||||
.three-pane-onboarding-link {
|
||||
color: var(--onboarding-link-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.onboarding-link:hover {
|
||||
.three-pane-onboarding-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.onboarding-link:active {
|
||||
.three-pane-onboarding-link:active {
|
||||
color: var(--onboarding-link-active-color);
|
||||
}
|
||||
|
||||
.onboarding-close-button {
|
||||
.three-pane-onboarding-close-button {
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
.onboarding-close-button::before {
|
||||
.three-pane-onboarding-close-button::before {
|
||||
background-image: url("chrome://devtools/skin/images/close.svg");
|
||||
margin: -6px 0 0 -6px;
|
||||
}
|
||||
|
|
|
@ -224,7 +224,7 @@
|
|||
|
||||
--toolbarbutton-background: var(--theme-toolbar-hover);
|
||||
--toolbarbutton-border-color: transparent;
|
||||
--toolbarbutton-hover-background: var(--theme-toolbar-hover);
|
||||
--toolbarbutton-hover-background: rgba(110,120,130,0.2);
|
||||
--toolbarbutton-hover-border-color: var(--toolbarbutton-border-color);
|
||||
--toolbarbutton-focus-background: var(--theme-selection-focus-background);
|
||||
--toolbarbutton-focus-color: var(--theme-selection-focus-color);
|
||||
|
|
Загрузка…
Ссылка в новой задаче