1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 const Services = require("Services");
8 const osString = Services.appinfo.OS;
14 () => require("devtools/client/framework/toolbox-options").OptionsPanel
19 () => require("devtools/client/inspector/panel").InspectorPanel
24 () => require("devtools/client/webconsole/panel").WebConsolePanel
29 () => require("devtools/client/debugger/panel").DebuggerPanel
34 () => require("devtools/client/styleeditor/panel").StyleEditorPanel
39 () => require("devtools/client/memory/panel").MemoryPanel
44 () => require("devtools/client/performance/panel").PerformancePanel
48 "NewPerformancePanel",
49 () => require("devtools/client/performance-new/panel").PerformancePanel
54 () => require("devtools/client/netmonitor/panel").NetMonitorPanel
59 () => require("devtools/client/storage/panel").StoragePanel
64 () => require("devtools/client/scratchpad/panel").ScratchpadPanel
69 () => require("devtools/client/dom/panel").DomPanel
74 () => require("devtools/client/accessibility/panel").AccessibilityPanel
79 () => require("devtools/client/application/panel").ApplicationPanel
84 () => require("devtools/client/webreplay/menu.js").reloadAndRecordTab
88 "reloadAndStopRecordingTab",
89 () => require("devtools/client/webreplay/menu.js").reloadAndStopRecordingTab
93 loader.lazyRequireGetter(
95 "AccessibilityStartup",
96 "devtools/client/accessibility/accessibility-startup",
99 loader.lazyRequireGetter(
101 "ResponsiveUIManager",
102 "devtools/client/responsive/manager"
107 "resource://devtools/client/scratchpad/scratchpad-manager.jsm"
110 const { MultiLocalizationHelper } = require("devtools/shared/l10n");
111 const L10N = new MultiLocalizationHelper(
112 "devtools/client/locales/startup.properties",
113 "devtools/startup/locales/key-shortcuts.properties"
116 // URL to direct people to the deprecated tools panel
117 const DEPRECATION_URL =
118 "https://developer.mozilla.org/docs/Tools/Deprecated_tools";
121 exports.Tools = Tools;
127 url: "chrome://devtools/content/framework/toolbox-options.xhtml",
128 icon: "chrome://devtools/skin/images/settings.svg",
129 bgTheme: "theme-body",
130 label: l10n("options.label"),
132 panelLabel: l10n("options.panelLabel"),
133 tooltip: l10n("optionsButton.tooltip"),
136 isTargetSupported: function() {
140 build: function(iframeWindow, toolbox) {
141 return new OptionsPanel(iframeWindow, toolbox);
147 accesskey: l10n("inspector.accesskey"),
149 icon: "chrome://devtools/skin/images/tool-inspector.svg",
150 url: "chrome://devtools/content/inspector/index.xhtml",
151 label: l10n("inspector.label"),
152 panelLabel: l10n("inspector.panelLabel"),
154 if (osString == "Darwin") {
155 const cmdShiftC = "Cmd+Shift+" + l10n("inspector.commandkey");
156 const cmdOptC = "Cmd+Opt+" + l10n("inspector.commandkey");
157 return l10n("inspector.mac.tooltip", cmdShiftC, cmdOptC);
160 const ctrlShiftC = "Ctrl+Shift+" + l10n("inspector.commandkey");
161 return l10n("inspector.tooltip2", ctrlShiftC);
165 preventClosingOnKey: true,
166 // preventRaisingOnKey is used to keep the focus on the content window for shortcuts
167 // that trigger the element picker.
168 preventRaisingOnKey: true,
169 onkey: function(panel, toolbox) {
170 toolbox.nodePicker.togglePicker();
173 isTargetSupported: function(target) {
174 return target.hasActor("inspector");
177 build: function(iframeWindow, toolbox) {
178 return new InspectorPanel(iframeWindow, toolbox);
183 accesskey: l10n("webConsoleCmd.accesskey"),
185 url: "chrome://devtools/content/webconsole/index.html",
186 icon: "chrome://devtools/skin/images/tool-webconsole.svg",
187 label: l10n("ToolboxTabWebconsole.label"),
188 menuLabel: l10n("MenuWebconsole.label"),
189 panelLabel: l10n("ToolboxWebConsole.panelLabel"),
192 "ToolboxWebconsole.tooltip2",
193 (osString == "Darwin" ? "Cmd+Opt+" : "Ctrl+Shift+") +
194 l10n("webconsole.commandkey")
199 preventClosingOnKey: true,
200 onkey: function(panel, toolbox) {
201 if (toolbox.splitConsole) {
202 return toolbox.focusConsoleInput();
209 isTargetSupported: function() {
212 build: function(iframeWindow, toolbox) {
213 return new WebConsolePanel(iframeWindow, toolbox);
219 accesskey: l10n("debuggerMenu.accesskey"),
221 icon: "chrome://devtools/skin/images/tool-debugger.svg",
222 url: "chrome://devtools/content/debugger/index.html",
223 label: l10n("ToolboxDebugger.label"),
224 panelLabel: l10n("ToolboxDebugger.panelLabel"),
227 "ToolboxDebugger.tooltip4",
228 (osString == "Darwin" ? "Cmd+Opt+" : "Ctrl+Shift+") +
229 l10n("jsdebugger.commandkey")
233 isTargetSupported: function() {
236 build: function(iframeWindow, toolbox) {
237 return new DebuggerPanel(iframeWindow, toolbox);
241 Tools.styleEditor = {
244 visibilityswitch: "devtools.styleeditor.enabled",
245 accesskey: l10n("open.accesskey"),
246 icon: "chrome://devtools/skin/images/tool-styleeditor.svg",
247 url: "chrome://devtools/content/styleeditor/index.xul",
248 label: l10n("ToolboxStyleEditor.label"),
249 panelLabel: l10n("ToolboxStyleEditor.panelLabel"),
252 "ToolboxStyleEditor.tooltip3",
253 "Shift+" + functionkey(l10n("styleeditor.commandkey"))
257 isTargetSupported: function(target) {
258 return target.hasActor("styleSheets");
261 build: function(iframeWindow, toolbox) {
262 return new StyleEditorPanel(iframeWindow, toolbox);
266 Tools.performance = {
269 icon: "chrome://devtools/skin/images/tool-profiler.svg",
270 visibilityswitch: "devtools.performance.enabled",
271 label: l10n("performance.label"),
272 panelLabel: l10n("performance.panelLabel"),
275 "performance.tooltip",
276 "Shift+" + functionkey(l10n("performance.commandkey"))
279 accesskey: l10n("performance.accesskey"),
283 function switchPerformancePanel() {
285 Services.prefs.getBoolPref("devtools.performance.new-panel-enabled", false)
287 Tools.performance.url =
288 "chrome://devtools/content/performance-new/index.xhtml";
289 Tools.performance.build = function(frame, target) {
290 return new NewPerformancePanel(frame, target);
292 Tools.performance.isTargetSupported = function(target) {
293 // Root actors are lazily initialized, so we can't check if the target has
294 // the perf actor yet. Also this function is not async, so we can't initialize
296 // We don't display the new performance panel for remote context in the
297 // toolbox, because this has an overhead. Instead we should use WebIDE (or
298 // the coming about:debugging).
299 return target.isLocalTab;
302 Tools.performance.url = "chrome://devtools/content/performance/index.xul";
303 Tools.performance.build = function(frame, target) {
304 return new PerformancePanel(frame, target);
306 Tools.performance.isTargetSupported = function(target) {
307 return target.hasActor("performance");
311 switchPerformancePanel();
313 Services.prefs.addObserver("devtools.performance.new-panel-enabled", {
314 observe: switchPerformancePanel,
320 icon: "chrome://devtools/skin/images/tool-memory.svg",
321 url: "chrome://devtools/content/memory/index.xhtml",
322 visibilityswitch: "devtools.memory.enabled",
323 label: l10n("memory.label"),
324 panelLabel: l10n("memory.panelLabel"),
325 tooltip: l10n("memory.tooltip"),
327 isTargetSupported: function(target) {
329 target.getTrait("heapSnapshots") &&
331 !target.isWorkerTarget
335 build: function(frame, target) {
336 return new MemoryPanel(frame, target);
342 accesskey: l10n("netmonitor.accesskey"),
344 visibilityswitch: "devtools.netmonitor.enabled",
345 icon: "chrome://devtools/skin/images/tool-network.svg",
346 url: "chrome://devtools/content/netmonitor/index.html",
347 label: l10n("netmonitor.label"),
348 panelLabel: l10n("netmonitor.panelLabel"),
351 "netmonitor.tooltip2",
352 (osString == "Darwin" ? "Cmd+Opt+" : "Ctrl+Shift+") +
353 l10n("netmonitor.commandkey")
358 isTargetSupported: function(target) {
359 return target.getTrait("networkMonitor") && !target.isWorkerTarget;
362 build: function(iframeWindow, toolbox) {
363 return new NetMonitorPanel(iframeWindow, toolbox);
370 accesskey: l10n("storage.accesskey"),
371 visibilityswitch: "devtools.storage.enabled",
372 icon: "chrome://devtools/skin/images/tool-storage.svg",
373 url: "chrome://devtools/content/storage/index.xul",
374 label: l10n("storage.label"),
375 menuLabel: l10n("storage.menuLabel"),
376 panelLabel: l10n("storage.panelLabel"),
380 "Shift+" + functionkey(l10n("storage.commandkey"))
385 isTargetSupported: function(target) {
388 (target.hasActor("storage") && target.getTrait("storageInspector"))
392 build: function(iframeWindow, toolbox) {
393 return new StoragePanel(iframeWindow, toolbox);
400 deprecationURL: `${DEPRECATION_URL}#Scratchpad`,
402 visibilityswitch: "devtools.scratchpad.enabled",
403 icon: "chrome://devtools/skin/images/tool-scratchpad.svg",
404 url: "chrome://devtools/content/scratchpad/index.xul",
405 label: l10n("scratchpad.label"),
406 panelLabel: l10n("scratchpad.panelLabel"),
407 tooltip: l10n("scratchpad.tooltip"),
409 isTargetSupported: function(target) {
410 return target.hasActor("console");
412 build: function(iframeWindow, toolbox) {
413 return new ScratchpadPanel(iframeWindow, toolbox);
419 accesskey: l10n("dom.accesskey"),
421 visibilityswitch: "devtools.dom.enabled",
422 icon: "chrome://devtools/skin/images/tool-dom.svg",
423 url: "chrome://devtools/content/dom/index.html",
424 label: l10n("dom.label"),
425 panelLabel: l10n("dom.panelLabel"),
429 (osString == "Darwin" ? "Cmd+Opt+" : "Ctrl+Shift+") +
430 l10n("dom.commandkey")
435 isTargetSupported: function(target) {
436 return target.getTrait("webConsoleCommands");
439 build: function(iframeWindow, toolbox) {
440 return new DomPanel(iframeWindow, toolbox);
444 Tools.accessibility = {
446 accesskey: l10n("accessibility.accesskey"),
448 modifiers: osString == "Darwin" ? "accel,alt" : "accel,shift",
449 visibilityswitch: "devtools.accessibility.enabled",
450 icon: "chrome://devtools/skin/images/tool-accessibility.svg",
451 url: "chrome://devtools/content/accessibility/index.html",
452 label: l10n("accessibility.label"),
453 panelLabel: l10n("accessibility.panelLabel"),
456 "accessibility.tooltip3",
457 "Shift+" + functionkey(l10n("accessibilityF12.commandkey"))
462 isTargetSupported(target) {
463 return target.hasActor("accessibility");
466 build(iframeWindow, toolbox) {
467 const startup = toolbox.getToolStartup("accessibility");
468 return new AccessibilityPanel(iframeWindow, toolbox, startup);
471 buildToolStartup(toolbox) {
472 return new AccessibilityStartup(toolbox);
476 Tools.application = {
479 visibilityswitch: "devtools.application.enabled",
480 icon: "chrome://devtools/skin/images/tool-application.svg",
481 url: "chrome://devtools/content/application/index.html",
482 label: l10n("application.label"),
483 panelLabel: l10n("application.panellabel"),
484 tooltip: l10n("application.tooltip"),
486 hiddenInOptions: true,
488 isTargetSupported: function(target) {
489 return target.isLocalTab;
492 build: function(iframeWindow, toolbox) {
493 return new ApplicationPanel(iframeWindow, toolbox);
513 exports.defaultTools = defaultTools;
517 label: l10n("options.darkTheme.label2"),
519 stylesheets: ["chrome://devtools/skin/dark-theme.css"],
520 classList: ["theme-dark"],
525 label: l10n("options.lightTheme.label2"),
527 stylesheets: ["chrome://devtools/skin/light-theme.css"],
528 classList: ["theme-light"],
531 exports.defaultThemes = [Tools.darkTheme, Tools.lightTheme];
533 // White-list buttons that can be toggled to prevent adding prefs for
534 // addons that have manually inserted toolbarbuttons into DOM.
535 // (By default, supported target is only local tab)
536 exports.ToolboxButtons = [
538 id: "command-button-paintflashing",
539 description: l10n("toolbox.buttons.paintflashing"),
540 isTargetSupported: target => target.isLocalTab,
541 onClick(event, toolbox) {
542 toolbox.togglePaintFlashing();
545 return toolbox.isPaintFlashing;
549 id: "command-button-scratchpad",
550 description: l10n("toolbox.buttons.scratchpad"),
551 isTargetSupported: target => target.isLocalTab,
552 onClick(event, toolbox) {
553 ScratchpadManager.openScratchpad();
557 id: "command-button-replay",
558 description: l10n("toolbox.buttons.replay"),
559 isTargetSupported: target =>
560 Services.prefs.getBoolPref("devtools.recordreplay.mvp.enabled") &&
563 onClick: () => reloadAndRecordTab(),
564 isChecked: () => false,
567 id: "command-button-stop-replay",
568 description: l10n("toolbox.buttons.stopReplay"),
569 isTargetSupported: target =>
570 Services.prefs.getBoolPref("devtools.recordreplay.mvp.enabled") &&
573 onClick: () => reloadAndStopRecordingTab(),
574 isChecked: () => true,
577 id: "command-button-responsive",
579 "toolbox.buttons.responsive",
580 osString == "Darwin" ? "Cmd+Opt+M" : "Ctrl+Shift+M"
582 isTargetSupported: target => target.isLocalTab,
583 onClick(event, toolbox) {
584 const tab = toolbox.target.tab;
585 const browserWindow = tab.ownerDocument.defaultView;
586 ResponsiveUIManager.toggle(browserWindow, tab, { trigger: "toolbox" });
589 if (!toolbox.target.tab) {
592 return ResponsiveUIManager.isActiveForTab(toolbox.target.tab);
594 setup(toolbox, onChange) {
595 ResponsiveUIManager.on("on", onChange);
596 ResponsiveUIManager.on("off", onChange);
598 teardown(toolbox, onChange) {
599 ResponsiveUIManager.off("on", onChange);
600 ResponsiveUIManager.off("off", onChange);
604 id: "command-button-screenshot",
605 description: l10n("toolbox.buttons.screenshot"),
606 isTargetSupported: target =>
607 !target.chrome && target.hasActor("screenshot"),
608 async onClick(event, toolbox) {
609 // Special case for screenshot button to check for clipboard preference
610 const clipboardEnabled = Services.prefs.getBoolPref(
611 "devtools.screenshot.clipboard.enabled"
613 const args = { fullpage: true, file: true };
614 if (clipboardEnabled) {
615 args.clipboard = true;
617 const screenshotFront = await toolbox.target.getFront("screenshot");
618 await screenshotFront.captureAndSave(toolbox.win, args);
621 createHighlightButton("RulersHighlighter", "rulers"),
622 createHighlightButton("MeasuringToolHighlighter", "measure"),
625 function createHighlightButton(highlighterName, id) {
627 id: `command-button-${id}`,
628 description: l10n(`toolbox.buttons.${id}`),
629 isTargetSupported: target => !target.chrome,
630 async onClick(event, toolbox) {
631 const inspectorFront = await toolbox.target.getFront("inspector");
632 const highlighter = await inspectorFront.getOrCreateHighlighterByType(
635 if (highlighter.isShown()) {
636 return highlighter.hide();
638 // Starting with FF63, higlighter's spec accept a null first argument.
639 // Still pass an empty object to fake a domnode front in order to support old
641 return highlighter.show({});
644 // if the inspector doesn't exist, then the highlighter has not yet been connected
646 const inspectorFront = toolbox.target.getCachedFront("inspector");
647 if (!inspectorFront) {
648 // initialize the inspector front asyncronously. There is a potential for buggy
649 // behavior here, but we need to change how the buttons get data (have them
650 // consume data from reducers rather than writing our own version) in order to
651 // fix this properly.
654 const highlighter = inspectorFront.getKnownHighlighter(highlighterName);
655 return highlighter && highlighter.isShown();
661 * Lookup l10n string from a string bundle.
663 * @param {string} name
665 * @param {...string} args
666 * Optional format argument.
667 * @returns A localized version of the given key.
669 function l10n(name, ...args) {
671 return args ? L10N.getFormatStr(name, ...args) : L10N.getStr(name);
673 console.log("Error reading '" + name + "'");
674 throw new Error("l10n error with " + name);
678 function functionkey(shortkey) {
679 return shortkey.split("_")[1];