Source code
Revision control
Copy as Markdown
Other Tools
/* 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,
"use strict";
const SPLITCONSOLE_ENABLED_PREF = "devtools.toolbox.splitconsole.enabled";
const {
PureComponent,
createFactory,
} = require("resource://devtools/client/shared/vendor/react.js");
const PropTypes = require("resource://devtools/client/shared/vendor/react-prop-types.js");
const dom = require("resource://devtools/client/shared/vendor/react-dom-factories.js");
const { hr } = dom;
loader.lazyGetter(this, "MenuItem", function () {
return createFactory(
require("resource://devtools/client/shared/components/menu/MenuItem.js")
);
});
loader.lazyGetter(this, "MenuList", function () {
return createFactory(
require("resource://devtools/client/shared/components/menu/MenuList.js")
);
});
loader.lazyRequireGetter(
this,
"openDocLink",
"resource://devtools/client/shared/link.js",
true
);
loader.lazyRequireGetter(
this,
"assert",
"resource://devtools/shared/DevToolsUtils.js",
true
);
const openDevToolsDocsLink = () => {
};
const openCommunityLink = () => {
openDocLink(
);
};
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. for "browsertoolbox").
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,
// Apply a pseudo-locale to the Firefox UI. This is only available in the browser
// toolbox. This value can be undefined, "accented", "bidi", "none".
pseudoLocale: PropTypes.string,
// 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,
// Manage the pseudo-localization for the Firefox UI.
disablePseudoLocale: PropTypes.func,
enableAccentedPseudoLocale: PropTypes.func,
enableBidiPseudoLocale: PropTypes.func,
// to be migrated. This is the only remaining use of the legacy L10N object.
// Everything else should prefer the Fluent API.
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 pseudo locale options 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.pseudoLocale !== prevProps.pseudoLocale ||
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) {
// This is more verbose than it needs to be but lets us easily search for
// l10n entities.
let l10nID;
switch (hostType.position) {
case "window":
l10nID = "toolbox-meatball-menu-dock-separate-window-label";
break;
case "bottom":
l10nID = "toolbox-meatball-menu-dock-bottom-label";
break;
case "left":
l10nID = "toolbox-meatball-menu-dock-left-label";
break;
case "right":
l10nID = "toolbox-meatball-menu-dock-right-label";
break;
default:
assert(false, `Unexpected hostType.position: ${hostType.position}`);
break;
}
items.push(
MenuItem({
id: `toolbox-meatball-menu-dock-${hostType.position}`,
key: `dock-${hostType.position}`,
l10nID,
onClick: hostType.switchHost,
checked: hostType.position === this.props.currentHostType,
className: "iconic",
})
);
}
if (items.length) {
items.push(hr({ key: "dock-separator" }));
}
// Split console
if (this.props.currentToolId !== "webconsole") {
const isSplitConsoleEnabled = Services.prefs.getBoolPref(
SPLITCONSOLE_ENABLED_PREF,
true
);
if (isSplitConsoleEnabled) {
const l10nID = this.props.isSplitConsoleActive
? "toolbox-meatball-menu-hideconsole-label"
: "toolbox-meatball-menu-splitconsole-label";
items.push(
MenuItem({
id: "toolbox-meatball-menu-splitconsole",
key: "splitconsole",
l10nID,
accelerator: "Esc",
onClick: this.props.toggleSplitConsole,
className: "iconic",
})
);
}
}
// Settings
items.push(
MenuItem({
id: "toolbox-meatball-menu-settings",
key: "settings",
l10nID: "toolbox-meatball-menu-settings-label",
// be migrated.
accelerator: this.props.L10N.getStr("toolbox.help.key"),
onClick: this.props.toggleOptions,
className: "iconic",
})
);
if (
typeof this.props.disableAutohide !== "undefined" ||
typeof this.props.pseudoLocale !== "undefined"
) {
items.push(hr({ key: "docs-separator-1" }));
}
// 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",
key: "noautohide",
l10nID: "toolbox-meatball-menu-noautohide-label",
type: "checkbox",
checked: this.props.disableAutohide,
onClick: this.props.toggleNoAutohide,
className: "iconic",
})
);
}
// Pseudo-locales.
if (typeof this.props.pseudoLocale !== "undefined") {
const {
pseudoLocale,
enableAccentedPseudoLocale,
enableBidiPseudoLocale,
disablePseudoLocale,
} = this.props;
items.push(
MenuItem({
id: "toolbox-meatball-menu-pseudo-locale-accented",
key: "pseudo-locale-accented",
l10nID: "toolbox-meatball-menu-pseudo-locale-accented",
type: "checkbox",
checked: pseudoLocale === "accented",
onClick:
pseudoLocale === "accented"
? disablePseudoLocale
: enableAccentedPseudoLocale,
className: "iconic",
}),
MenuItem({
id: "toolbox-meatball-menu-pseudo-locale-bidi",
key: "pseudo-locale-bidi",
l10nID: "toolbox-meatball-menu-pseudo-locale-bidi",
type: "checkbox",
checked: pseudoLocale === "bidi",
onClick:
pseudoLocale === "bidi"
? disablePseudoLocale
: enableBidiPseudoLocale,
className: "iconic",
})
);
}
items.push(hr({ key: "docs-separator-2" }));
// Getting started
items.push(
MenuItem({
id: "toolbox-meatball-menu-documentation",
key: "documentation",
l10nID: "toolbox-meatball-menu-documentation-label",
onClick: openDevToolsDocsLink,
})
);
// Give feedback
items.push(
MenuItem({
id: "toolbox-meatball-menu-community",
key: "community",
l10nID: "toolbox-meatball-menu-community-label",
onClick: openCommunityLink,
})
);
return MenuList({ id: "toolbox-meatball-menu" }, items);
}
}
module.exports = MeatballMenu;