309 lines
9.5 KiB
JavaScript
309 lines
9.5 KiB
JavaScript
/* 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 SPLITCONSOLE_ENABLED_PREF = "devtools.toolbox.splitconsole.enabled";
|
|
|
|
const {
|
|
PureComponent,
|
|
createFactory,
|
|
} = require("resource://devtools/client/shared/vendor/react.mjs");
|
|
const PropTypes = require("resource://devtools/client/shared/vendor/react-prop-types.mjs");
|
|
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 = () => {
|
|
openDocLink("https://firefox-source-docs.mozilla.org/devtools-user/");
|
|
};
|
|
|
|
const openCommunityLink = () => {
|
|
openDocLink(
|
|
"https://discourse.mozilla.org/c/devtools?utm_source=devtools&utm_medium=tabbar-menu"
|
|
);
|
|
};
|
|
|
|
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.
|
|
// https://firefox-source-docs.mozilla.org/l10n/fluent/tutorial.html#manually-testing-ui-with-pseudolocalization
|
|
disablePseudoLocale: PropTypes.func,
|
|
enableAccentedPseudoLocale: PropTypes.func,
|
|
enableBidiPseudoLocale: PropTypes.func,
|
|
|
|
// Bug 1709191 - The help shortcut key is localized without Fluent, and still needs
|
|
// 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",
|
|
// Bug 1709191 - The help key is localized without Fluent, and still needs to
|
|
// 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;
|