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 osString
= Services
.appinfo
.OS
;
14 require("resource://devtools/client/framework/toolbox-options.js")
20 () => require("resource://devtools/client/inspector/panel.js").InspectorPanel
26 require("resource://devtools/client/webconsole/panel.js").WebConsolePanel
31 () => require("resource://devtools/client/debugger/panel.js").DebuggerPanel
37 require("resource://devtools/client/styleeditor/panel.js").StyleEditorPanel
42 () => require("resource://devtools/client/memory/panel.js").MemoryPanel
46 "NewPerformancePanel",
48 require("resource://devtools/client/performance-new/panel/panel.js")
55 require("resource://devtools/client/netmonitor/panel.js").NetMonitorPanel
60 () => require("resource://devtools/client/storage/panel.js").StoragePanel
65 () => require("resource://devtools/client/dom/panel.js").DomPanel
71 require("resource://devtools/client/accessibility/panel.js")
78 require("resource://devtools/client/application/panel.js").ApplicationPanel
82 loader
.lazyRequireGetter(
84 "ResponsiveUIManager",
85 "resource://devtools/client/responsive/manager.js"
87 loader
.lazyRequireGetter(
90 "resource://devtools/shared/specs/tracer.js",
95 ChromeUtils
.defineESModuleGetters(lazy
, {
96 AppConstants
: "resource://gre/modules/AppConstants.sys.mjs",
98 loader
.lazyRequireGetter(
100 "DevToolsExperimentalPrefs",
101 "resource://devtools/client/devtools-experimental-prefs.js"
103 loader
.lazyRequireGetter(
105 "captureAndSaveScreenshot",
106 "resource://devtools/client/shared/screenshot.js",
109 loader
.lazyRequireGetter(
112 "resource://devtools/client/framework/menu.js"
114 loader
.lazyRequireGetter(
117 "resource://devtools/client/framework/menu-item.js"
120 const { TYPES
: HIGHLIGHTER_TYPES
} = ChromeUtils
.importESModule(
121 "resource://devtools/shared/highlighters.mjs"
124 const { LocalizationHelper
} = require("resource://devtools/shared/l10n.js");
125 const L10N
= new LocalizationHelper(
126 "devtools/client/locales/startup.properties"
128 const CommandKeys
= new Localization(
129 ["devtools/startup/key-shortcuts.ftl"],
134 exports
.Tools
= Tools
;
140 url
: "chrome://devtools/content/framework/toolbox-options.html",
141 icon
: "chrome://devtools/skin/images/settings.svg",
142 bgTheme
: "theme-body",
143 label
: l10n("options.label"),
145 panelLabel
: l10n("options.panelLabel"),
146 tooltip
: l10n("optionsButton.tooltip"),
153 build(iframeWindow
, toolbox
, commands
) {
154 return new OptionsPanel(iframeWindow
, toolbox
, commands
);
160 accesskey
: l10n("inspector.accesskey"),
162 icon
: "chrome://devtools/skin/images/tool-inspector.svg",
163 url
: "chrome://devtools/content/inspector/index.xhtml",
164 label
: l10n("inspector.label"),
165 panelLabel
: l10n("inspector.panelLabel"),
167 const key
= commandkey("devtools-commandkey-inspector");
168 if (osString
== "Darwin") {
169 const cmdShiftC
= "Cmd+Shift+" + key
;
170 const cmdOptC
= "Cmd+Opt+" + key
;
171 return l10n("inspector.mac.tooltip", cmdShiftC
, cmdOptC
);
174 const ctrlShiftC
= "Ctrl+Shift+" + key
;
175 return l10n("inspector.tooltip2", ctrlShiftC
);
179 preventClosingOnKey
: true,
180 // preventRaisingOnKey is used to keep the focus on the content window for shortcuts
181 // that trigger the element picker.
182 preventRaisingOnKey
: true,
183 onkey(panel
, toolbox
) {
185 Services
.prefs
.getBoolPref("devtools.command-button-pick.enabled", false)
187 toolbox
.nodePicker
.togglePicker();
191 isToolSupported(toolbox
) {
192 return toolbox
.target
.hasActor("inspector");
195 build(iframeWindow
, toolbox
, commands
) {
196 return new InspectorPanel(iframeWindow
, toolbox
, commands
);
201 accesskey
: l10n("webConsoleCmd.accesskey"),
203 url
: "chrome://devtools/content/webconsole/index.html",
204 icon
: "chrome://devtools/skin/images/tool-webconsole.svg",
205 label
: l10n("ToolboxTabWebconsole.label"),
206 menuLabel
: l10n("MenuWebconsole.label"),
207 panelLabel
: l10n("ToolboxWebConsole.panelLabel"),
210 "ToolboxWebconsole.tooltip2",
211 (osString
== "Darwin" ? "Cmd+Opt+" : "Ctrl+Shift+") +
212 commandkey("devtools-commandkey-webconsole")
217 preventClosingOnKey
: true,
218 onkey(panel
, toolbox
) {
219 if (toolbox
.splitConsole
) {
220 return toolbox
.focusConsoleInput();
230 build(iframeWindow
, toolbox
, commands
) {
231 return new WebConsolePanel(iframeWindow
, toolbox
, commands
);
237 accesskey
: l10n("debuggerMenu.accesskey"),
239 icon
: "chrome://devtools/skin/images/tool-debugger.svg",
240 url
: "chrome://devtools/content/debugger/index.html",
241 label
: l10n("ToolboxDebugger.label"),
242 panelLabel
: l10n("ToolboxDebugger.panelLabel"),
245 "ToolboxDebugger.tooltip4",
246 (osString
== "Darwin" ? "Cmd+Opt+" : "Ctrl+Shift+") +
247 commandkey("devtools-commandkey-jsdebugger")
254 build(iframeWindow
, toolbox
, commands
) {
255 return new DebuggerPanel(iframeWindow
, toolbox
, commands
);
259 Tools
.styleEditor
= {
262 visibilityswitch
: "devtools.styleeditor.enabled",
263 accesskey
: l10n("open.accesskey"),
264 icon
: "chrome://devtools/skin/images/tool-styleeditor.svg",
265 url
: "chrome://devtools/content/styleeditor/index.xhtml",
266 label
: l10n("ToolboxStyleEditor.label"),
267 panelLabel
: l10n("ToolboxStyleEditor.panelLabel"),
270 "ToolboxStyleEditor.tooltip3",
271 "Shift+" + functionkey(commandkey("devtools-commandkey-styleeditor"))
275 isToolSupported(toolbox
) {
276 return toolbox
.target
.hasActor("styleSheets");
279 build(iframeWindow
, toolbox
, commands
) {
280 return new StyleEditorPanel(iframeWindow
, toolbox
, commands
);
284 Tools
.performance
= {
287 icon
: "chrome://devtools/skin/images/tool-profiler.svg",
288 url
: "chrome://devtools/content/performance-new/panel/index.xhtml",
289 visibilityswitch
: "devtools.performance.enabled",
290 label
: l10n("performance.label"),
291 panelLabel
: l10n("performance.panelLabel"),
294 "performance.tooltip",
295 "Shift+" + functionkey(commandkey("devtools-commandkey-performance"))
298 accesskey
: l10n("performance.accesskey"),
300 isToolSupported(toolbox
) {
301 // Only use the new performance panel on local tab toolboxes, as they are guaranteed
302 // to have a performance actor.
303 // Remote tab toolboxes (eg about:devtools-toolbox from about:debugging) should not
304 // use the performance panel; about:debugging provides a "Profile performance" button
305 // which can be used instead, without having the overhead of starting a remote toolbox.
306 // Also accept the Browser Toolbox, so that we can profile its process via a second browser toolbox.
308 toolbox
.commands
.descriptorFront
.isLocalTab
|| toolbox
.isBrowserToolbox
311 build(frame
, toolbox
, commands
) {
312 return new NewPerformancePanel(frame
, toolbox
, commands
);
319 icon
: "chrome://devtools/skin/images/tool-memory.svg",
320 url
: "chrome://devtools/content/memory/index.xhtml",
321 visibilityswitch
: "devtools.memory.enabled",
322 label
: l10n("memory.label"),
323 panelLabel
: l10n("memory.panelLabel"),
324 tooltip
: l10n("memory.tooltip"),
326 isToolSupported(toolbox
) {
327 const { descriptorFront
} = toolbox
.commands
;
329 !descriptorFront
.isWebExtensionDescriptor
&&
330 !descriptorFront
.isWorkerDescriptor
334 build(frame
, toolbox
, commands
) {
335 return new MemoryPanel(frame
, toolbox
, commands
);
341 accesskey
: l10n("netmonitor.accesskey"),
343 visibilityswitch
: "devtools.netmonitor.enabled",
344 icon
: "chrome://devtools/skin/images/tool-network.svg",
345 url
: "chrome://devtools/content/netmonitor/index.html",
346 label
: l10n("netmonitor.label"),
347 panelLabel
: l10n("netmonitor.panelLabel"),
350 "netmonitor.tooltip2",
351 (osString
== "Darwin" ? "Cmd+Opt+" : "Ctrl+Shift+") +
352 commandkey("devtools-commandkey-netmonitor")
357 isToolSupported(toolbox
) {
359 toolbox
.target
.getTrait("networkMonitor") &&
360 !toolbox
.target
.isWorkerTarget
364 build(iframeWindow
, toolbox
, commands
) {
365 return new NetMonitorPanel(iframeWindow
, toolbox
, commands
);
372 accesskey
: l10n("storage.accesskey"),
373 visibilityswitch
: "devtools.storage.enabled",
374 icon
: "chrome://devtools/skin/images/tool-storage.svg",
375 url
: "chrome://devtools/content/storage/index.xhtml",
376 label
: l10n("storage.label"),
377 menuLabel
: l10n("storage.menuLabel"),
378 panelLabel
: l10n("storage.panelLabel"),
382 "Shift+" + functionkey(commandkey("devtools-commandkey-storage"))
387 isToolSupported(toolbox
) {
388 const { descriptorFront
} = toolbox
.commands
;
389 // Storage is available on all contexts debugging a BrowsingContext.
390 // As of today, this is all but worker toolboxes.
392 descriptorFront
.isTabDescriptor
||
393 descriptorFront
.isParentProcessDescriptor
||
394 descriptorFront
.isWebExtensionDescriptor
398 build(iframeWindow
, toolbox
, commands
) {
399 return new StoragePanel(iframeWindow
, toolbox
, commands
);
405 accesskey
: l10n("dom.accesskey"),
407 visibilityswitch
: "devtools.dom.enabled",
408 icon
: "chrome://devtools/skin/images/tool-dom.svg",
409 url
: "chrome://devtools/content/dom/index.html",
410 label
: l10n("dom.label"),
411 panelLabel
: l10n("dom.panelLabel"),
415 (osString
== "Darwin" ? "Cmd+Opt+" : "Ctrl+Shift+") +
416 commandkey("devtools-commandkey-dom")
425 build(iframeWindow
, toolbox
, commands
) {
426 return new DomPanel(iframeWindow
, toolbox
, commands
);
430 Tools
.accessibility
= {
432 accesskey
: l10n("accessibility.accesskey"),
434 modifiers
: osString
== "Darwin" ? "accel,alt" : "accel,shift",
435 visibilityswitch
: "devtools.accessibility.enabled",
436 icon
: "chrome://devtools/skin/images/tool-accessibility.svg",
437 url
: "chrome://devtools/content/accessibility/index.html",
438 label
: l10n("accessibility.label"),
439 panelLabel
: l10n("accessibility.panelLabel"),
442 "accessibility.tooltip3",
444 functionkey(commandkey("devtools-commandkey-accessibility-f12"))
449 isToolSupported(toolbox
) {
450 return toolbox
.target
.hasActor("accessibility");
453 build(iframeWindow
, toolbox
, commands
) {
454 return new AccessibilityPanel(iframeWindow
, toolbox
, commands
);
458 Tools
.application
= {
461 visibilityswitch
: "devtools.application.enabled",
462 icon
: "chrome://devtools/skin/images/tool-application.svg",
463 url
: "chrome://devtools/content/application/index.html",
464 label
: l10n("application.label"),
465 panelLabel
: l10n("application.panelLabel"),
466 tooltip
: l10n("application.tooltip"),
469 isToolSupported(toolbox
) {
470 return toolbox
.target
.hasActor("manifest");
473 build(iframeWindow
, toolbox
, commands
) {
474 return new ApplicationPanel(iframeWindow
, toolbox
, commands
);
493 exports
.defaultTools
= defaultTools
;
497 label
: l10n("options.darkTheme.label2"),
499 stylesheets
: ["chrome://devtools/skin/dark-theme.css"],
500 classList
: ["theme-dark"],
505 label
: l10n("options.lightTheme.label2"),
507 stylesheets
: ["chrome://devtools/skin/light-theme.css"],
508 classList
: ["theme-light"],
511 exports
.defaultThemes
= [Tools
.darkTheme
, Tools
.lightTheme
];
513 // List buttons that can be toggled to prevent adding prefs for
514 // addons that have manually inserted toolbarbuttons into DOM.
515 // (By default, supported target is only local tab)
516 exports
.ToolboxButtons
= [
518 id
: "command-button-experimental-prefs",
519 description
: "DevTools Experimental preferences",
520 isToolSupported
: () => !lazy
.AppConstants
.MOZILLA_OFFICIAL
,
521 onClick
: (event
, toolbox
) => DevToolsExperimentalPrefs
.showTooltip(toolbox
),
522 isChecked
: () => DevToolsExperimentalPrefs
.isAnyPreferenceEnabled(),
525 id
: "command-button-responsive",
527 "toolbox.buttons.responsive",
528 osString
== "Darwin" ? "Cmd+Opt+M" : "Ctrl+Shift+M"
530 isToolSupported
: toolbox
=> toolbox
.commands
.descriptorFront
.isLocalTab
,
531 onClick(event
, toolbox
) {
532 const { localTab
} = toolbox
.commands
.descriptorFront
;
533 const browserWindow
= localTab
.ownerDocument
.defaultView
;
534 ResponsiveUIManager
.toggle(browserWindow
, localTab
, {
539 const { localTab
} = toolbox
.commands
.descriptorFront
;
543 return ResponsiveUIManager
.isActiveForTab(localTab
);
546 setup(toolbox
, onChange
) {
547 ResponsiveUIManager
.on("on", onChange
);
548 ResponsiveUIManager
.on("off", onChange
);
550 teardown(toolbox
, onChange
) {
551 ResponsiveUIManager
.off("on", onChange
);
552 ResponsiveUIManager
.off("off", onChange
);
556 id
: "command-button-screenshot",
557 description
: l10n("toolbox.buttons.screenshot"),
558 isToolSupported
: toolbox
=> {
560 // @backward-compat { version 87 } We need to check for the screenshot actor as well
561 // when connecting to older server that does not have the screenshotContentActor
562 toolbox
.target
.hasActor("screenshotContent") ||
563 toolbox
.target
.hasActor("screenshot")
566 async
onClick(event
, toolbox
) {
567 // Special case for screenshot button to check for clipboard preference
568 const clipboardEnabled
= Services
.prefs
.getBoolPref(
569 "devtools.screenshot.clipboard.enabled"
572 // When screenshot to clipboard is enabled disabling saving to file
575 file
: !clipboardEnabled
,
576 clipboard
: clipboardEnabled
,
579 const messages
= await
captureAndSaveScreenshot(
584 const notificationBox
= toolbox
.getNotificationBox();
585 const priorityMap
= {
586 error
: notificationBox
.PRIORITY_CRITICAL_HIGH
,
587 warn
: notificationBox
.PRIORITY_WARNING_HIGH
,
589 for (const { text
, level
} of messages
) {
590 // captureAndSaveScreenshot returns "saved" messages, that indicate where the
591 // screenshot was saved. In regular toolbox, we don't want to display them as
592 // the download UI can be used to open them.
593 // But in the browser toolbox, we can't see the download UI, so we'll display the
594 // saved message so the user knows there the file was saved.
596 !toolbox
.isBrowserToolbox
&&
602 notificationBox
.appendNotification(
606 priorityMap
[level
] || notificationBox
.PRIORITY_INFO_MEDIUM
611 createHighlightButton(
612 [HIGHLIGHTER_TYPES
.RULERS
, HIGHLIGHTER_TYPES
.VIEWPORT_SIZE
],
615 createHighlightButton([HIGHLIGHTER_TYPES
.MEASURING
], "measure"),
617 id
: "command-button-jstracer",
619 "toolbox.buttons.jstracer",
620 osString
== "Darwin" ? "Cmd+Shift+5" : "Ctrl+Shift+5"
622 isToolSupported
: () =>
623 Services
.prefs
.getBoolPref(
624 "devtools.debugger.features.javascript-tracing",
627 async
onClick(event
, toolbox
) {
628 await toolbox
.commands
.tracerCommand
.toggle();
631 const { tracerCommand
} = toolbox
.commands
;
632 const button
= toolbox
.doc
.getElementById("command-button-jstracer");
634 button
.classList
.toggle(
636 tracerCommand
.isTracingEnabled
&& !tracerCommand
.isTracingActive
639 return tracerCommand
.isTracingEnabled
;
642 setup(toolbox
, onChange
) {
643 toolbox
.commands
.tracerCommand
.on("toggle", onChange
);
645 teardown(toolbox
, onChange
) {
646 toolbox
.commands
.tracerCommand
.off("toggle", onChange
);
648 getContextMenu(toolbox
) {
649 const menu
= new Menu();
650 const options
= toolbox
.commands
.tracerCommand
.getTracingOptions();
651 const { logMethod
} = options
;
654 id
: "jstracer-menu-item-debugger-sidebar",
656 "toolbox.buttons.jstracer.menu-item.trace-to-debugger-sidebar"
658 checked
: logMethod
== TRACER_LOG_METHODS
.DEBUGGER_SIDEBAR
,
661 Services
.prefs
.setStringPref(
662 "devtools.debugger.javascript-tracing-log-method",
663 TRACER_LOG_METHODS
.DEBUGGER_SIDEBAR
670 id
: "jstracer-menu-item-console",
671 label
: l10n("traceInWebConsole"),
672 checked
: logMethod
== TRACER_LOG_METHODS
.CONSOLE
,
675 Services
.prefs
.setStringPref(
676 "devtools.debugger.javascript-tracing-log-method",
677 TRACER_LOG_METHODS
.CONSOLE
684 id
: "jstracer-menu-item-profiler",
685 label
: l10n("traceInProfiler"),
686 checked
: logMethod
== TRACER_LOG_METHODS
.PROFILER
,
689 Services
.prefs
.setStringPref(
690 "devtools.debugger.javascript-tracing-log-method",
691 TRACER_LOG_METHODS
.PROFILER
698 id
: "jstracer-menu-item-stdout",
699 label
: l10n("traceInStdout"),
701 checked
: logMethod
== TRACER_LOG_METHODS
.STDOUT
,
703 Services
.prefs
.setStringPref(
704 "devtools.debugger.javascript-tracing-log-method",
705 TRACER_LOG_METHODS
.STDOUT
710 menu
.append(new MenuItem({ type
: "separator" }));
713 id
: "jstracer-menu-item-next-interaction",
714 label
: l10n("traceOnNextInteraction"),
716 checked
: options
.traceOnNextInteraction
,
718 Services
.prefs
.setBoolPref(
719 "devtools.debugger.javascript-tracing-on-next-interaction",
720 !options
.traceOnNextInteraction
727 id
: "jstracer-menu-item-next-load",
728 label
: l10n("traceOnNextLoad"),
730 checked
: options
.traceOnNextLoad
,
732 Services
.prefs
.setBoolPref(
733 "devtools.debugger.javascript-tracing-on-next-load",
734 !options
.traceOnNextLoad
739 menu
.append(new MenuItem({ type
: "separator" }));
742 id
: "jstracer-menu-item-log-values",
743 label
: l10n("traceValues"),
745 checked
: options
.traceValues
,
747 Services
.prefs
.setBoolPref(
748 "devtools.debugger.javascript-tracing-values",
756 id
: "jstracer-menu-item-function-return",
757 label
: l10n("traceFunctionReturn"),
759 checked
: options
.traceFunctionReturn
,
761 Services
.prefs
.setBoolPref(
762 "devtools.debugger.javascript-tracing-function-return",
763 !options
.traceFunctionReturn
773 function createHighlightButton(highlighters
, id
) {
775 id
: `command-button-${id}`,
776 description
: l10n(`toolbox.buttons.${id}`),
777 isToolSupported
: toolbox
=>
778 toolbox
.commands
.descriptorFront
.isTabDescriptor
,
779 async
onClick(event
, toolbox
) {
780 const inspectorFront
= await toolbox
.target
.getFront("inspector");
783 highlighters
.map(async name
=> {
785 await inspectorFront
.getOrCreateHighlighterByType(name
);
787 if (highlighter
.isShown()) {
788 await highlighter
.hide();
790 await highlighter
.show();
796 // if the inspector doesn't exist, then the highlighter has not yet been connected
798 const inspectorFront
= toolbox
.target
.getCachedFront("inspector");
799 if (!inspectorFront
) {
800 // initialize the inspector front asyncronously. There is a potential for buggy
801 // behavior here, but we need to change how the buttons get data (have them
802 // consume data from reducers rather than writing our own version) in order to
803 // fix this properly.
807 return highlighters
.every(name
=>
808 inspectorFront
.getKnownHighlighter(name
)?.isShown()
816 * Lookup l10n string from a string bundle.
818 * @param {string} name
820 * @param {...string} args
821 * Optional format argument.
822 * @returns A localized version of the given key.
824 function l10n(name
, ...args
) {
826 return args
? L10N
.getFormatStr(name
, ...args
) : L10N
.getStr(name
);
828 console
.log("Error reading '" + name
+ "'");
829 throw new Error("l10n error with " + name
);
833 function commandkey(name
) {
835 return CommandKeys
.formatValueSync(name
);
837 console
.log("Error reading '" + name
+ "'");
838 throw new Error("l10n error with " + name
);
842 function functionkey(shortkey
) {
843 return shortkey
.split("_")[1];