new file mode 100644
--- /dev/null
+++ b/devtools/client/framework/components/MeatballMenu.js
@@ -0,0 +1,197 @@
+/* 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 { createFactory } = require("devtools/client/shared/vendor/react");
+const MenuItem = createFactory(
+ require("devtools/client/shared/components/menu/MenuItem")
+);
+const MenuList = createFactory(
+ require("devtools/client/shared/components/menu/MenuList")
+);
+const dom = require("devtools/client/shared/vendor/react-dom-factories");
+const { hr } = dom;
+const { openDocLink } = require("devtools/client/shared/link");
+
+class MeatballMenu extends PureComponent {
+ static get propTypes() {
+ return {
+ // The id of the currently selected tool, e.g. "inspector"
+ currentToolId: PropTypes.string,
+
+ // List of possible docking options.
+ hostTypes: PropTypes.arrayOf(
+ PropTypes.shape({
+ position: PropTypes.string.isRequired,
+ switchHost: PropTypes.func.isRequired,
+ })
+ ),
+
+ // Current docking type. Typically one of the position values in
+ // |hostTypes| but this is not always the case (e.g. when it is "custom").
+ currentHostType: PropTypes.string,
+
+ // Is the split console currently visible?
+ isSplitConsoleActive: PropTypes.bool,
+
+ // Are we disabling the behavior where pop-ups are automatically closed
+ // when clicking outside them?
+ //
+ // This is a tri-state value that may be true/false or undefined where
+ // undefined means that the option is not relevant in this context
+ // (i.e. we're not in a browser toolbox).
+ disableAutohide: PropTypes.bool,
+
+ // Function to turn the options panel on / off.
+ toggleOptions: PropTypes.func.isRequired,
+
+ // Function to turn the split console on / off.
+ toggleSplitConsole: PropTypes.func,
+
+ // Function to turn the disable pop-up autohide behavior on / off.
+ toggleNoAutohide: PropTypes.func,
+
+ // Localization interface.
+ L10N: PropTypes.object.isRequired,
+
+ // Callback function that will be invoked any time the component contents
+ // update in such a way that its bounding box might change.
+ onResize: PropTypes.func,
+ };
+ }
+
+ componentDidUpdate(prevProps) {
+ if (!this.props.onResize) {
+ return;
+ }
+
+ // We are only expecting the following kinds of dynamic changes when a popup
+ // is showing:
+ //
+ // - The "Disable pop-up autohide" menu item being added after the Browser
+ // Toolbox is connected.
+ // - The split console label changing between "Show split console" and "Hide
+ // split console".
+ // - The "Show/Hide split console" entry being added removed or removed.
+ //
+ // The latter two cases are only likely to be noticed when "Disable pop-up
+ // autohide" is active, but for completeness we handle them here.
+ const didChange =
+ typeof this.props.disableAutohide !== typeof prevProps.disableAutohide ||
+ this.props.currentToolId !== prevProps.currentToolId ||
+ this.props.isSplitConsoleActive !== prevProps.isSplitConsoleActive;
+
+ if (didChange) {
+ this.props.onResize();
+ }
+ }
+
+ render() {
+ const items = [];
+
+ // Dock options
+ for (const hostType of this.props.hostTypes) {
+ const l10nkey =
+ hostType.position === "window" ? "separateWindow" : hostType.position;
+ items.push(
+ MenuItem({
+ id: `toolbox-meatball-menu-dock-${hostType.position}`,
+ label: this.props.L10N.getStr(
+ `toolbox.meatballMenu.dock.${l10nkey}.label`
+ ),
+ onClick: () => hostType.switchHost(),
+ checked: hostType.position === this.props.currentHostType,
+ className: "iconic",
+ })
+ );
+ }
+
+ if (items.length) {
+ items.push(hr());
+ }
+
+ // Split console
+ if (this.props.currentToolId !== "webconsole") {
+ items.push(
+ MenuItem({
+ id: "toolbox-meatball-menu-splitconsole",
+ label: this.props.L10N.getStr(
+ `toolbox.meatballMenu.${
+ this.props.isSplitConsoleActive ? "hideconsole" : "splitconsole"
+ }.label`
+ ),
+ accelerator: "Esc",
+ onClick: this.props.toggleSplitConsole,
+ className: "iconic",
+ })
+ );
+ }
+
+ // Disable pop-up autohide
+ //
+ // If |disableAutohide| is undefined, it means this feature is not available
+ // in this context.
+ if (typeof this.props.disableAutohide !== "undefined") {
+ items.push(
+ MenuItem({
+ id: "toolbox-meatball-menu-noautohide",
+ label: this.props.L10N.getStr(
+ "toolbox.meatballMenu.noautohide.label"
+ ),
+ type: "checkbox",
+ checked: this.props.disableAutohide,
+ onClick: this.props.toggleNoAutohide,
+ className: "iconic",
+ })
+ );
+ }
+
+ // Settings
+ items.push(
+ MenuItem({
+ id: "toolbox-meatball-menu-settings",
+ label: this.props.L10N.getStr("toolbox.meatballMenu.settings.label"),
+ accelerator: this.props.L10N.getStr("toolbox.help.key"),
+ onClick: () => this.props.toggleOptions(),
+ className: "iconic",
+ })
+ );
+
+ items.push(hr());
+
+ // Getting started
+ items.push(
+ MenuItem({
+ id: "toolbox-meatball-menu-documentation",
+ label: this.props.L10N.getStr(
+ "toolbox.meatballMenu.documentation.label"
+ ),
+ onClick: () => {
+ openDocLink(
+ "https://developer.mozilla.org/docs/Tools?utm_source=devtools&utm_medium=tabbar-menu"
+ );
+ },
+ })
+ );
+
+ // Give feedback
+ items.push(
+ MenuItem({
+ id: "toolbox-meatball-menu-community",
+ label: this.props.L10N.getStr("toolbox.meatballMenu.community.label"),
+ onClick: () => {
+ openDocLink(
+ "https://discourse.mozilla.org/c/devtools?utm_source=devtools&utm_medium=tabbar-menu"
+ );
+ },
+ })
+ );
+
+ return MenuList({ id: "toolbox-meatball-menu" }, items);
+ }
+}
+
+module.exports = MeatballMenu;
--- a/devtools/client/framework/components/ToolboxToolbar.js
+++ b/devtools/client/framework/components/ToolboxToolbar.js
@@ -2,20 +2,19 @@
* 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 dom = require("devtools/client/shared/vendor/react-dom-factories");
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
const {div, button} = dom;
-const {openDocLink} = require("devtools/client/shared/link");
-const Menu = require("devtools/client/framework/menu");
-const MenuItem = require("devtools/client/framework/menu-item");
+const MeatballMenu = createFactory(require("devtools/client/framework/components/MeatballMenu"));
+const MenuButton = createFactory(require("devtools/client/shared/components/menu/MenuButton"));
const ToolboxTabs = createFactory(require("devtools/client/framework/components/ToolboxTabs"));
/**
* This is the overall component for the toolbox toolbar. It is designed to not know how
* the state is being managed, and attempts to be as pure as possible. The
* ToolboxController component controls the changing state, and passes in everything as
* props.
*/
@@ -104,17 +103,17 @@ class ToolboxToolbar extends Component {
? (
div(
{
className: classnames.join(" ")
},
startButtons,
ToolboxTabs(this.props),
endButtons,
- renderToolboxControls(this.props)
+ renderToolboxControls(this.props, this.refs)
)
)
: div({ className: classnames.join(" ") });
}
}
module.exports = ToolboxToolbar;
@@ -219,80 +218,94 @@ function renderToolboxButtons({focusedBu
*/
function renderSeparator() {
return div({className: "devtools-separator"});
}
/**
* Render the toolbox control buttons. The following props are expected:
*
- * @param {string} focusedButton
+ * @param {string} props.focusedButton
* The id of the focused button.
- * @param {Object[]} hostTypes
+ * @param {string} props.currentToolId
+ * The id of the currently selected tool, e.g. "inspector".
+ * @param {Object[]} props.hostTypes
* Array of host type objects.
- * @param {string} hostTypes[].position
+ * @param {string} props.hostTypes[].position
* Position name.
- * @param {Function} hostTypes[].switchHost
+ * @param {Function} props.hostTypes[].switchHost
* Function to switch the host.
- * @param {string} currentHostType
+ * @param {string} props.currentHostType
* The current docking configuration.
- * @param {boolean} areDockOptionsEnabled
+ * @param {boolean} props.areDockOptionsEnabled
* They are not enabled in certain situations like when they are in the
* WebIDE.
- * @param {boolean} canCloseToolbox
+ * @param {boolean} props.canCloseToolbox
* Do we need to add UI for closing the toolbox? We don't when the
* toolbox is undocked, for example.
- * @param {boolean} isSplitConsoleActive
+ * @param {boolean} props.isSplitConsoleActive
* Is the split console currently visible?
* toolbox is undocked, for example.
- * @param {boolean|undefined} disableAutohide
+ * @param {boolean|undefined} props.disableAutohide
* Are we disabling the behavior where pop-ups are automatically
* closed when clicking outside them?
* (Only defined for the browser toolbox.)
- * @param {Function} selectTool
+ * @param {Function} props.selectTool
* Function to select a tool based on its id.
- * @param {Function} toggleOptions
+ * @param {Function} props.toggleOptions
* Function to turn the options panel on / off.
- * @param {Function} toggleSplitConsole
+ * @param {Function} props.toggleSplitConsole
* Function to turn the split console on / off.
- * @param {Function} toggleNoAutohide
+ * @param {Function} props.toggleNoAutohide
* Function to turn the disable pop-up autohide behavior on / off.
- * @param {Function} closeToolbox
+ * @param {Function} props.closeToolbox
* Completely close the toolbox.
- * @param {Function} focusButton
+ * @param {Function} props.focusButton
* Keep a record of the currently focused button.
- * @param {Object} L10N
+ * @param {Object} props.L10N
* Localization interface.
+ * @param {Object} props.toolbox
+ * The devtools toolbox. Used by the MenuButton component to display
+ * the menu popup.
+ * @param {Object} refs
+ * The components refs object. Used to keep a reference to the MenuButton
+ * for the meatball menu so that we can tell it to resize its contents
+ * when they change.
*/
-function renderToolboxControls(props) {
+function renderToolboxControls(props, refs) {
const {
focusedButton,
+ canCloseToolbox,
closeToolbox,
- hostTypes,
focusButton,
L10N,
- areDockOptionsEnabled,
- canCloseToolbox,
+ toolbox,
} = props;
const meatballMenuButtonId = "toolbox-meatball-menu-button";
- const meatballMenuButton = button({
- id: meatballMenuButtonId,
- onFocus: () => focusButton(meatballMenuButtonId),
- className: "devtools-button",
- title: L10N.getStr("toolbox.meatballMenu.button.tooltip"),
- onClick: evt => {
- showMeatballMenu(evt.target, {
- ...props,
- hostTypes: areDockOptionsEnabled ? hostTypes : [],
- });
+ const meatballMenuButton = MenuButton(
+ {
+ id: meatballMenuButtonId,
+ menuId: meatballMenuButtonId + "-panel",
+ doc: toolbox.doc,
+ onFocus: () => focusButton(meatballMenuButtonId),
+ className: "devtools-button",
+ title: L10N.getStr("toolbox.meatballMenu.button.tooltip"),
+ tabIndex: focusedButton === meatballMenuButtonId ? "0" : "-1",
+ ref: "meatballMenuButton",
},
- tabIndex: focusedButton === meatballMenuButtonId ? "0" : "-1",
- });
+ MeatballMenu({
+ ...props,
+ hostTypes: props.areDockOptionsEnabled ? props.hostTypes : [],
+ onResize: () => {
+ refs.meatballMenuButton.resizeContent();
+ },
+ })
+ );
const closeButtonId = "toolbox-close";
const closeButton = canCloseToolbox
? button({
id: closeButtonId,
onFocus: () => focusButton(closeButtonId),
className: "devtools-button",
@@ -304,154 +317,8 @@ function renderToolboxControls(props) {
})
: null;
return div({id: "toolbox-controls"},
meatballMenuButton,
closeButton
);
}
-
-/**
- * Display the "..." menu (affectionately known as the meatball menu).
- *
- * @param {Object} menuButton
- * The <button> element from which the menu should pop out. The geometry
- * of this element is used to position the menu.
- * @param {Object} props
- * Properties as described below.
- * @param {string} props.currentToolId
- * The id of the currently selected tool.
- * @param {Object[]} props.hostTypes
- * Array of host type objects.
- * This array will be empty if we shouldn't shouldn't show any dock
- * options.
- * @param {string} props.hostTypes[].position
- * Position name.
- * @param {Function} props.hostTypes[].switchHost
- * Function to switch the host.
- * @param {string} props.currentHostType
- * The current docking configuration.
- * @param {boolean} isSplitConsoleActive
- * Is the split console currently visible?
- * @param {boolean|undefined} disableAutohide
- * Are we disabling the behavior where pop-ups are automatically
- * closed when clicking outside them.
- * (Only defined for the browser toolbox.)
- * @param {Function} selectTool
- * Function to select a tool based on its id.
- * @param {Function} toggleOptions
- * Function to turn the options panel on / off.
- * @param {Function} toggleSplitConsole
- * Function to turn the split console on / off.
- * @param {Function} toggleNoAutohide
- * Function to turn the disable pop-up autohide behavior on / off.
- * @param {Object} props.L10N
- * Localization interface.
- * @param {Object} props.toolbox
- * The devtools toolbox. Used by the Menu component to determine which
- * document to use.
- */
-function showMeatballMenu(
- menuButton,
- {
- currentToolId,
- hostTypes,
- currentHostType,
- isSplitConsoleActive,
- disableAutohide,
- toggleOptions,
- toggleSplitConsole,
- toggleNoAutohide,
- L10N,
- toolbox,
- }
-) {
- const menu = new Menu({ id: "toolbox-meatball-menu" });
-
- // Dock options
- for (const hostType of hostTypes) {
- const l10nkey =
- hostType.position === "window"
- ? "separateWindow"
- : hostType.position;
- menu.append(
- new MenuItem({
- id: `toolbox-meatball-menu-dock-${hostType.position}`,
- label: L10N.getStr(`toolbox.meatballMenu.dock.${l10nkey}.label`),
- click: () => hostType.switchHost(),
- type: "checkbox",
- checked: hostType.position === currentHostType,
- })
- );
- }
-
- if (menu.items.length) {
- menu.append(new MenuItem({ type: "separator" }));
- }
-
- // Split console
- if (currentToolId !== "webconsole") {
- menu.append(new MenuItem({
- id: "toolbox-meatball-menu-splitconsole",
- label: L10N.getStr(
- `toolbox.meatballMenu.${
- isSplitConsoleActive ? "hideconsole" : "splitconsole"
- }.label`
- ),
- accelerator: "Esc",
- click: toggleSplitConsole,
- }));
- }
-
- // Disable pop-up autohide
- //
- // If |disableAutohide| is undefined, it means this feature is not available
- // in this context.
- if (typeof disableAutohide !== "undefined") {
- menu.append(new MenuItem({
- id: "toolbox-meatball-menu-noautohide",
- label: L10N.getStr("toolbox.meatballMenu.noautohide.label"),
- type: "checkbox",
- checked: disableAutohide,
- click: toggleNoAutohide,
- }));
- }
-
- // Settings
- menu.append(new MenuItem({
- id: "toolbox-meatball-menu-settings",
- label: L10N.getStr("toolbox.meatballMenu.settings.label"),
- accelerator: L10N.getStr("toolbox.help.key"),
- click: () => toggleOptions(),
- }));
-
- if (menu.items.length) {
- menu.append(new MenuItem({ type: "separator" }));
- }
-
- // Getting started
- menu.append(new MenuItem({
- id: "toolbox-meatball-menu-documentation",
- label: L10N.getStr("toolbox.meatballMenu.documentation.label"),
- click: () => {
- openDocLink(
- "https://developer.mozilla.org/docs/Tools?utm_source=devtools&utm_medium=tabbar-menu");
- },
- }));
-
- // Give feedback
- menu.append(new MenuItem({
- id: "toolbox-meatball-menu-community",
- label: L10N.getStr("toolbox.meatballMenu.community.label"),
- click: () => {
- openDocLink(
- "https://discourse.mozilla.org/c/devtools?utm_source=devtools&utm_medium=tabbar-menu");
- },
- }));
-
- const rect = menuButton.getBoundingClientRect();
- const screenX = menuButton.ownerDocument.defaultView.mozInnerScreenX;
- const screenY = menuButton.ownerDocument.defaultView.mozInnerScreenY;
-
- // Display the popup below the button.
- menu.popupWithZoom(rect.left + screenX, rect.bottom + screenY, toolbox);
-}
--- a/devtools/client/framework/components/moz.build
+++ b/devtools/client/framework/components/moz.build
@@ -1,13 +1,14 @@
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DevToolsModules(
+ 'MeatballMenu.js',
'ToolboxController.js',
'ToolboxTab.js',
'ToolboxTabs.js',
'ToolboxToolbar.js',
)
--- a/devtools/client/jar.mn
+++ b/devtools/client/jar.mn
@@ -129,19 +129,21 @@ devtools.jar:
skin/images/alerticon-warning@2x.png (themes/images/alerticon-warning@2x.png)
skin/rules.css (themes/rules.css)
skin/images/command-paintflashing.svg (themes/images/command-paintflashing.svg)
skin/images/command-screenshot.svg (themes/images/command-screenshot.svg)
skin/images/command-responsivemode.svg (themes/images/command-responsivemode.svg)
skin/images/command-pick.svg (themes/images/command-pick.svg)
skin/images/command-pick-accessibility.svg (themes/images/command-pick-accessibility.svg)
skin/images/command-frames.svg (themes/images/command-frames.svg)
+ skin/images/command-console.svg (themes/images/command-console.svg)
skin/images/command-eyedropper.svg (themes/images/command-eyedropper.svg)
skin/images/command-rulers.svg (themes/images/command-rulers.svg)
skin/images/command-measure.svg (themes/images/command-measure.svg)
+ skin/images/command-noautohide.svg (themes/images/command-noautohide.svg)
skin/images/command-chevron.svg (themes/images/command-chevron.svg)
skin/markup.css (themes/markup.css)
skin/images/editor-error.png (themes/images/editor-error.png)
skin/images/breakpoint.svg (themes/images/breakpoint.svg)
skin/webconsole.css (themes/webconsole.css)
skin/images/webconsole.svg (themes/images/webconsole.svg)
skin/images/breadcrumbs-scrollbutton.svg (themes/images/breadcrumbs-scrollbutton.svg)
skin/animation.css (themes/animation.css)
@@ -173,30 +175,35 @@ devtools.jar:
skin/images/more.svg (themes/images/more.svg)
skin/images/pause.svg (themes/images/pause.svg)
skin/images/play.svg (themes/images/play.svg)
skin/images/rewind.svg (themes/images/rewind.svg)
skin/images/debugger-step-in.svg (themes/images/debugger-step-in.svg)
skin/images/debugger-step-out.svg (themes/images/debugger-step-out.svg)
skin/images/debugger-step-over.svg (themes/images/debugger-step-over.svg)
skin/images/debugger-toggleBreakpoints.svg (themes/images/debugger-toggleBreakpoints.svg)
+ skin/images/dock-bottom.svg (themes/images/dock-bottom.svg)
+ skin/images/dock-side-left.svg (themes/images/dock-side-left.svg)
+ skin/images/dock-side-right.svg (themes/images/dock-side-right.svg)
+ skin/images/dock-undock.svg (themes/images/dock-undock.svg)
skin/images/jump-definition.svg (themes/images/jump-definition.svg)
skin/images/tracer-icon.png (themes/images/tracer-icon.png)
skin/images/tracer-icon@2x.png (themes/images/tracer-icon@2x.png)
skin/floating-scrollbars-dark-theme.css (themes/floating-scrollbars-dark-theme.css)
skin/floating-scrollbars-responsive-design.css (themes/floating-scrollbars-responsive-design.css)
skin/inspector.css (themes/inspector.css)
skin/images/profiler-stopwatch.svg (themes/images/profiler-stopwatch.svg)
skin/images/debugging-addons.svg (themes/images/debugging-addons.svg)
skin/images/debugging-tabs.svg (themes/images/debugging-tabs.svg)
skin/images/debugging-workers.svg (themes/images/debugging-workers.svg)
skin/images/globe.svg (themes/images/globe.svg)
skin/images/sad-face.svg (themes/images/sad-face.svg)
skin/images/shape-swatch.svg (themes/images/shape-swatch.svg)
skin/images/tool-options.svg (themes/images/tool-options.svg)
+ skin/images/tool-options-photon.svg (themes/images/tool-options-photon.svg)
skin/images/tool-webconsole.svg (themes/images/tool-webconsole.svg)
skin/images/tool-canvas.svg (themes/images/tool-canvas.svg)
skin/images/tool-debugger.svg (themes/images/tool-debugger.svg)
skin/images/tool-inspector.svg (themes/images/tool-inspector.svg)
skin/images/tool-shadereditor.svg (themes/images/tool-shadereditor.svg)
skin/images/tool-styleeditor.svg (themes/images/tool-styleeditor.svg)
skin/images/tool-storage.svg (themes/images/tool-storage.svg)
skin/images/tool-profiler.svg (themes/images/tool-profiler.svg)
new file mode 100644
--- /dev/null
+++ b/devtools/client/themes/images/command-console.svg
@@ -0,0 +1,11 @@
+<!-- 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 xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="context-fill #0b0b0b">
+ <path d="
+ M13 1a3 3 0 0 1 3 3v8a3 3 0 0 1-3 3h-10a3 3 0 0 1-3-3v-8a3 3 0 0 1 3-3h10z
+ M13 3h-10a1 1 0 0 0-1 1v1h12v-1a1 1 0 0 0-1-1z
+ M14 6h-12v6a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1z"/>
+ <path d="M4.5 7.5l2 2l-2 2" stroke="context-fill" stroke-width="1"
+ stroke-linecap="round" stroke-linejoin="round" fill="none"/>
+</svg>
new file mode 100644
--- /dev/null
+++ b/devtools/client/themes/images/command-noautohide.svg
@@ -0,0 +1,9 @@
+<!-- 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 xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" fill="context-fill #0b0b0b">
+ <path d="M1 5a2 2 0 0 1 2-2h1l2-2 2 2h5a2 2 0 0 1 2 2v8
+ a2 2 0 0 1-2 2h-10a2 2 0 0 1-2-2z"
+ stroke-width="2" stroke="context-fill"
+ stroke-linejoin="round" stroke-linecap="round" fill="none"/>
+</svg>
new file mode 100644
--- /dev/null
+++ b/devtools/client/themes/images/dock-bottom.svg
@@ -0,0 +1,10 @@
+<!-- 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 viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"
+ fill="context-fill #0b0b0b">
+ <path d="
+ M12 0a3 3 0 0 1 3 3v10a3 3 0 0 1-3 3h-8a3 3 0 0 1-3-3v-10a3 3 0 0 1 3-3h8z
+ M12 2h-8a1 1 0 0 0-1 1v7h10v-7a1 1 0 0 0-1-1z
+ M13 11h-10v2a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1z"/>
+</svg>
new file mode 100644
--- /dev/null
+++ b/devtools/client/themes/images/dock-side-left.svg
@@ -0,0 +1,10 @@
+<!-- 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 viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"
+ fill="context-fill #0b0b0b">
+ <path d="
+ M0 4a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v8a3 3 0 0 1-3 3h-10a3 3 0 0 1-3-3z
+ M2 4v8a1 1 0 0 0 1 1h2v-10h-2a1 1 0 0 0-1 1z
+ M6 3v10h7a1 1 0 0 0 1-1v-8a1 1 0 0 0-1-1z"/>
+</svg>
new file mode 100644
--- /dev/null
+++ b/devtools/client/themes/images/dock-side-right.svg
@@ -0,0 +1,10 @@
+<!-- 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 viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"
+ fill="context-fill #0b0b0b">
+ <path d="
+ M0 4a3 3 0 0 1 3-3h10a3 3 0 0 1 3 3v8a3 3 0 0 1-3 3h-10a3 3 0 0 1-3-3z
+ M2 4v8a1 1 0 0 0 1 1h7v-10h-7a1 1 0 0 0-1 1z
+ M11 3v10h2a1 1 0 0 0 1-1v-8a1 1 0 0 0-1-1z"/>
+</svg>
new file mode 100644
--- /dev/null
+++ b/devtools/client/themes/images/dock-undock.svg
@@ -0,0 +1,12 @@
+<!-- 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 viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"
+ fill="context-fill #0b0b0b">
+ <path d="
+ M13 0a3 3 0 0 1 3 3v5a3 3 0 0 1-3 3h-5a3 3 0 0 1-3-3v-5a3 3 0 0 1 3-3z
+ M13 2h-5a1 1 0 0 0-1 1v5a1 1 0 0 0 1 1h5a1 1 0 0 0 1-1v-5a1 1 0 0 0-1-1z"/>
+ <path d="M9 13v-1h2v1a3 3 0 0 1-3 3
+ h-5a3 3 0 0 1-3-3v-5a3 3 0 0 1 3-3h1v2h-1a1 1 0 0 0-1 1v5
+ a1 1 0 0 0 1 1h5a1 1 0 0 0 1-1z"/>
+</svg>
new file mode 100644
--- /dev/null
+++ b/devtools/client/themes/images/tool-options-photon.svg
@@ -0,0 +1,9 @@
+<!-- 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 xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"
+ fill="context-fill #0b0b0b">
+ <path d="M7.45 15.95a1.86 1.86 0 0 1-1.86-1.86v-.89c-.3-.14-.6-.3-.89-.5l-.77.43a1.87 1.87 0 0 1-2.54-.68l-.55-.96c-.51-.88-.21-2.02.68-2.54l.77-.44a5.8 5.8 0 0 1 0-1.02l-.77-.45A1.87 1.87 0 0 1 .84 4.5l.55-.95a1.87 1.87 0 0 1 2.54-.69l.77.45c.28-.2.58-.37.89-.52v-.88C5.58.88 6.42.05 7.45.05h1.1c1.03 0 1.86.83 1.86 1.86v.89c.3.14.6.3.89.5l.77-.44a1.86 1.86 0 0 1 2.54.69l.55.95c.52.9.21 2.03-.68 2.55l-.77.44c.03.34.03.68 0 1.02l.77.44c.89.52 1.2 1.66.68 2.55l-.55.95a1.87 1.87 0 0 1-2.54.69l-.77-.45c-.29.2-.58.38-.88.52v.88c0 1.03-.84 1.86-1.87 1.86h-1.1zM5.49 11.4c.26.2.53.35.82.48l.78.34v1.87c0 .2.17.35.36.35h1.1c.2 0 .36-.16.36-.35v-1.87l.78-.34c.3-.13.57-.29.82-.48l.69-.5 1.62.93a.36.36 0 0 0 .48-.13l.56-.96a.36.36 0 0 0-.13-.48l-1.62-.94.1-.85c.03-.31.03-.63 0-.95l-.1-.85 1.62-.93c.17-.1.22-.32.13-.49l-.56-.95a.36.36 0 0 0-.48-.13l-1.62.94-.69-.51a4.27 4.27 0 0 0-.82-.48l-.78-.34V1.91c0-.2-.16-.35-.36-.35h-1.1c-.2 0-.36.16-.36.35v1.87l-.78.34c-.3.13-.57.29-.82.48l-.69.5-1.62-.93a.36.36 0 0 0-.48.13l-.56.96c-.1.16-.03.38.13.48l1.62.94-.1.85c-.03.31-.03.63 0 .95l.1.84-1.62.94a.36.36 0 0 0-.13.48l.56.96c.06.1.18.18.3.18.07 0 .13-.02.18-.05l1.62-.94.69.51z"/>
+ <circle cx="8" cy="8" r="1.5" stroke-width="1"
+ stroke="context-fill" fill="none"/>
+</svg>
--- a/devtools/client/themes/toolbox.css
+++ b/devtools/client/themes/toolbox.css
@@ -1,17 +1,24 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* 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/. */
:root {
--close-button-image: url(chrome://devtools/skin/images/close.svg);
+ --dock-bottom-image: url(chrome://devtools/skin/images/dock-bottom.svg);
+ --dock-side-right-image: url(chrome://devtools/skin/images/dock-side-right.svg);
+ --dock-side-left-image: url(chrome://devtools/skin/images/dock-side-left.svg);
+ --dock-undock-image: url(chrome://devtools/skin/images/dock-undock.svg);
--more-button-image: url(chrome://devtools/skin/images/more.svg);
+ --settings-image: url(chrome://devtools/skin/images/tool-options-photon.svg);
+ --command-noautohide-image: url(images/command-noautohide.svg);
+ --command-console-image: url(images/command-console.svg);
--command-paintflashing-image: url(images/command-paintflashing.svg);
--command-screenshot-image: url(images/command-screenshot.svg);
--command-responsive-image: url(images/command-responsivemode.svg);
--command-scratchpad-image: url(images/tool-scratchpad.svg);
--command-pick-image: url(images/command-pick.svg);
--command-pick-accessibility-image: url(images/command-pick-accessibility.svg);
--command-frames-image: url(images/command-frames.svg);
--command-rulers-image: url(images/command-rulers.svg);
@@ -214,16 +221,38 @@
min-width: 24px;
}
#toolbox-meatball-menu-button::before {
fill: var(--theme-toolbar-photon-icon-color);
background-image: var(--more-button-image);
}
+#toolbox-meatball-menu-dock-bottom > .label::before {
+ background-image: var(--dock-bottom-image);
+}
+#toolbox-meatball-menu-dock-left > .label::before {
+ background-image: var(--dock-side-left-image);
+}
+#toolbox-meatball-menu-dock-right > .label::before {
+ background-image: var(--dock-side-right-image);
+}
+#toolbox-meatball-menu-dock-window > .label::before {
+ background-image: var(--dock-undock-image);
+}
+#toolbox-meatball-menu-splitconsole > .label::before {
+ background-image: var(--command-console-image);
+}
+#toolbox-meatball-menu-noautohide > .label::before {
+ background-image: var(--command-noautohide-image);
+}
+#toolbox-meatball-menu-settings > .label::before {
+ background-image: var(--settings-image);
+}
+
/* Command buttons */
.command-button,
#toolbox-controls > button {
/* !important is needed to override .devtools-button rules in common.css */
padding: 0 !important;
margin: 0 !important;
border: none !important;
--- a/devtools/client/webconsole/test/mochitest/browser_webconsole_split.js
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_split.js
@@ -99,19 +99,19 @@ add_task(async function() {
EventUtils.sendMouseEvent({ type: "click" }, button);
toolbox.doc.addEventListener("popupshown", () => {
const menuItem =
toolbox.doc.getElementById("toolbox-meatball-menu-splitconsole");
// Return undefined if the menu item is not available
let label;
- if (menuItem) {
+ if (menuItem && menuItem.querySelector(".label")) {
label =
- menuItem.label ===
+ menuItem.querySelector(".label").textContent ===
L10N.getStr("toolbox.meatballMenu.hideconsole.label")
? "hide"
: "split";
}
// Wait for menu to close
toolbox.doc.addEventListener("popuphidden", () => {
resolve(label);
--- a/devtools/client/webconsole/test/mochitest/browser_webconsole_split_persist.js
+++ b/devtools/client/webconsole/test/mochitest/browser_webconsole_split_persist.js
@@ -92,17 +92,18 @@ function doesMenuSayHide(toolbox) {
EventUtils.sendMouseEvent({ type: "click" }, button);
toolbox.doc.addEventListener("popupshown", () => {
const menuItem =
toolbox.doc.getElementById("toolbox-meatball-menu-splitconsole");
const result =
menuItem &&
- menuItem.label ===
+ menuItem.querySelector(".label") &&
+ menuItem.querySelector(".label").textContent ===
L10N.getStr("toolbox.meatballMenu.hideconsole.label");
toolbox.doc.addEventListener("popuphidden", () => {
resolve(result);
},
{ once: true });
EventUtils.synthesizeKey("KEY_Escape");
},