Bug 1580545 - Convert ResponsiveUI and ResponsiveUIManager to ES6 classes. r=mtigley
[gecko.git] / devtools / client / definitions.js
blobe0ecb02511e66bef3e8dee56fb1cc9429074f81d
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/. */
5 "use strict";
7 const Services = require("Services");
8 const osString = Services.appinfo.OS;
10 // Panels
11 loader.lazyGetter(
12   this,
13   "OptionsPanel",
14   () => require("devtools/client/framework/toolbox-options").OptionsPanel
16 loader.lazyGetter(
17   this,
18   "InspectorPanel",
19   () => require("devtools/client/inspector/panel").InspectorPanel
21 loader.lazyGetter(
22   this,
23   "WebConsolePanel",
24   () => require("devtools/client/webconsole/panel").WebConsolePanel
26 loader.lazyGetter(
27   this,
28   "DebuggerPanel",
29   () => require("devtools/client/debugger/panel").DebuggerPanel
31 loader.lazyGetter(
32   this,
33   "StyleEditorPanel",
34   () => require("devtools/client/styleeditor/panel").StyleEditorPanel
36 loader.lazyGetter(
37   this,
38   "MemoryPanel",
39   () => require("devtools/client/memory/panel").MemoryPanel
41 loader.lazyGetter(
42   this,
43   "PerformancePanel",
44   () => require("devtools/client/performance/panel").PerformancePanel
46 loader.lazyGetter(
47   this,
48   "NewPerformancePanel",
49   () => require("devtools/client/performance-new/panel").PerformancePanel
51 loader.lazyGetter(
52   this,
53   "NetMonitorPanel",
54   () => require("devtools/client/netmonitor/panel").NetMonitorPanel
56 loader.lazyGetter(
57   this,
58   "StoragePanel",
59   () => require("devtools/client/storage/panel").StoragePanel
61 loader.lazyGetter(
62   this,
63   "ScratchpadPanel",
64   () => require("devtools/client/scratchpad/panel").ScratchpadPanel
66 loader.lazyGetter(
67   this,
68   "DomPanel",
69   () => require("devtools/client/dom/panel").DomPanel
71 loader.lazyGetter(
72   this,
73   "AccessibilityPanel",
74   () => require("devtools/client/accessibility/panel").AccessibilityPanel
76 loader.lazyGetter(
77   this,
78   "ApplicationPanel",
79   () => require("devtools/client/application/panel").ApplicationPanel
81 loader.lazyGetter(
82   this,
83   "reloadAndRecordTab",
84   () => require("devtools/client/webreplay/menu.js").reloadAndRecordTab
86 loader.lazyGetter(
87   this,
88   "reloadAndStopRecordingTab",
89   () => require("devtools/client/webreplay/menu.js").reloadAndStopRecordingTab
92 // Other dependencies
93 loader.lazyRequireGetter(
94   this,
95   "AccessibilityStartup",
96   "devtools/client/accessibility/accessibility-startup",
97   true
99 loader.lazyRequireGetter(
100   this,
101   "ResponsiveUIManager",
102   "devtools/client/responsive/manager"
104 loader.lazyImporter(
105   this,
106   "ScratchpadManager",
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";
120 var Tools = {};
121 exports.Tools = Tools;
123 // Definitions
124 Tools.options = {
125   id: "options",
126   ordinal: 0,
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"),
131   iconOnly: true,
132   panelLabel: l10n("options.panelLabel"),
133   tooltip: l10n("optionsButton.tooltip"),
134   inMenu: false,
136   isTargetSupported: function() {
137     return true;
138   },
140   build: function(iframeWindow, toolbox) {
141     return new OptionsPanel(iframeWindow, toolbox);
142   },
145 Tools.inspector = {
146   id: "inspector",
147   accesskey: l10n("inspector.accesskey"),
148   ordinal: 1,
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"),
153   get tooltip() {
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);
158     }
160     const ctrlShiftC = "Ctrl+Shift+" + l10n("inspector.commandkey");
161     return l10n("inspector.tooltip2", ctrlShiftC);
162   },
163   inMenu: true,
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();
171   },
173   isTargetSupported: function(target) {
174     return target.hasActor("inspector");
175   },
177   build: function(iframeWindow, toolbox) {
178     return new InspectorPanel(iframeWindow, toolbox);
179   },
181 Tools.webConsole = {
182   id: "webconsole",
183   accesskey: l10n("webConsoleCmd.accesskey"),
184   ordinal: 2,
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"),
190   get tooltip() {
191     return l10n(
192       "ToolboxWebconsole.tooltip2",
193       (osString == "Darwin" ? "Cmd+Opt+" : "Ctrl+Shift+") +
194         l10n("webconsole.commandkey")
195     );
196   },
197   inMenu: true,
199   preventClosingOnKey: true,
200   onkey: function(panel, toolbox) {
201     if (toolbox.splitConsole) {
202       return toolbox.focusConsoleInput();
203     }
205     panel.focusInput();
206     return undefined;
207   },
209   isTargetSupported: function() {
210     return true;
211   },
212   build: function(iframeWindow, toolbox) {
213     return new WebConsolePanel(iframeWindow, toolbox);
214   },
217 Tools.jsdebugger = {
218   id: "jsdebugger",
219   accesskey: l10n("debuggerMenu.accesskey"),
220   ordinal: 3,
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"),
225   get tooltip() {
226     return l10n(
227       "ToolboxDebugger.tooltip4",
228       (osString == "Darwin" ? "Cmd+Opt+" : "Ctrl+Shift+") +
229         l10n("jsdebugger.commandkey")
230     );
231   },
232   inMenu: true,
233   isTargetSupported: function() {
234     return true;
235   },
236   build: function(iframeWindow, toolbox) {
237     return new DebuggerPanel(iframeWindow, toolbox);
238   },
241 Tools.styleEditor = {
242   id: "styleeditor",
243   ordinal: 5,
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"),
250   get tooltip() {
251     return l10n(
252       "ToolboxStyleEditor.tooltip3",
253       "Shift+" + functionkey(l10n("styleeditor.commandkey"))
254     );
255   },
256   inMenu: true,
257   isTargetSupported: function(target) {
258     return target.hasActor("styleSheets");
259   },
261   build: function(iframeWindow, toolbox) {
262     return new StyleEditorPanel(iframeWindow, toolbox);
263   },
266 Tools.performance = {
267   id: "performance",
268   ordinal: 6,
269   icon: "chrome://devtools/skin/images/tool-profiler.svg",
270   visibilityswitch: "devtools.performance.enabled",
271   label: l10n("performance.label"),
272   panelLabel: l10n("performance.panelLabel"),
273   get tooltip() {
274     return l10n(
275       "performance.tooltip",
276       "Shift+" + functionkey(l10n("performance.commandkey"))
277     );
278   },
279   accesskey: l10n("performance.accesskey"),
280   inMenu: true,
283 function switchPerformancePanel() {
284   if (
285     Services.prefs.getBoolPref("devtools.performance.new-panel-enabled", false)
286   ) {
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);
291     };
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
295       // the actor yet.
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;
300     };
301   } else {
302     Tools.performance.url = "chrome://devtools/content/performance/index.xul";
303     Tools.performance.build = function(frame, target) {
304       return new PerformancePanel(frame, target);
305     };
306     Tools.performance.isTargetSupported = function(target) {
307       return target.hasActor("performance");
308     };
309   }
311 switchPerformancePanel();
313 Services.prefs.addObserver("devtools.performance.new-panel-enabled", {
314   observe: switchPerformancePanel,
317 Tools.memory = {
318   id: "memory",
319   ordinal: 7,
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) {
328     return (
329       target.getTrait("heapSnapshots") &&
330       !target.isAddon &&
331       !target.isWorkerTarget
332     );
333   },
335   build: function(frame, target) {
336     return new MemoryPanel(frame, target);
337   },
340 Tools.netMonitor = {
341   id: "netmonitor",
342   accesskey: l10n("netmonitor.accesskey"),
343   ordinal: 4,
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"),
349   get tooltip() {
350     return l10n(
351       "netmonitor.tooltip2",
352       (osString == "Darwin" ? "Cmd+Opt+" : "Ctrl+Shift+") +
353         l10n("netmonitor.commandkey")
354     );
355   },
356   inMenu: true,
358   isTargetSupported: function(target) {
359     return target.getTrait("networkMonitor") && !target.isWorkerTarget;
360   },
362   build: function(iframeWindow, toolbox) {
363     return new NetMonitorPanel(iframeWindow, toolbox);
364   },
367 Tools.storage = {
368   id: "storage",
369   ordinal: 8,
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"),
377   get tooltip() {
378     return l10n(
379       "storage.tooltip3",
380       "Shift+" + functionkey(l10n("storage.commandkey"))
381     );
382   },
383   inMenu: true,
385   isTargetSupported: function(target) {
386     return (
387       target.isLocalTab ||
388       (target.hasActor("storage") && target.getTrait("storageInspector"))
389     );
390   },
392   build: function(iframeWindow, toolbox) {
393     return new StoragePanel(iframeWindow, toolbox);
394   },
397 Tools.scratchpad = {
398   id: "scratchpad",
399   deprecated: true,
400   deprecationURL: `${DEPRECATION_URL}#Scratchpad`,
401   ordinal: 12,
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"),
408   inMenu: false,
409   isTargetSupported: function(target) {
410     return target.hasActor("console");
411   },
412   build: function(iframeWindow, toolbox) {
413     return new ScratchpadPanel(iframeWindow, toolbox);
414   },
417 Tools.dom = {
418   id: "dom",
419   accesskey: l10n("dom.accesskey"),
420   ordinal: 11,
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"),
426   get tooltip() {
427     return l10n(
428       "dom.tooltip",
429       (osString == "Darwin" ? "Cmd+Opt+" : "Ctrl+Shift+") +
430         l10n("dom.commandkey")
431     );
432   },
433   inMenu: true,
435   isTargetSupported: function(target) {
436     return target.getTrait("webConsoleCommands");
437   },
439   build: function(iframeWindow, toolbox) {
440     return new DomPanel(iframeWindow, toolbox);
441   },
444 Tools.accessibility = {
445   id: "accessibility",
446   accesskey: l10n("accessibility.accesskey"),
447   ordinal: 9,
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"),
454   get tooltip() {
455     return l10n(
456       "accessibility.tooltip3",
457       "Shift+" + functionkey(l10n("accessibilityF12.commandkey"))
458     );
459   },
460   inMenu: true,
462   isTargetSupported(target) {
463     return target.hasActor("accessibility");
464   },
466   build(iframeWindow, toolbox) {
467     const startup = toolbox.getToolStartup("accessibility");
468     return new AccessibilityPanel(iframeWindow, toolbox, startup);
469   },
471   buildToolStartup(toolbox) {
472     return new AccessibilityStartup(toolbox);
473   },
476 Tools.application = {
477   id: "application",
478   ordinal: 10,
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"),
485   inMenu: false,
486   hiddenInOptions: true,
488   isTargetSupported: function(target) {
489     return target.isLocalTab;
490   },
492   build: function(iframeWindow, toolbox) {
493     return new ApplicationPanel(iframeWindow, toolbox);
494   },
497 var defaultTools = [
498   Tools.options,
499   Tools.webConsole,
500   Tools.inspector,
501   Tools.jsdebugger,
502   Tools.styleEditor,
503   Tools.performance,
504   Tools.netMonitor,
505   Tools.storage,
506   Tools.scratchpad,
507   Tools.memory,
508   Tools.dom,
509   Tools.accessibility,
510   Tools.application,
513 exports.defaultTools = defaultTools;
515 Tools.darkTheme = {
516   id: "dark",
517   label: l10n("options.darkTheme.label2"),
518   ordinal: 1,
519   stylesheets: ["chrome://devtools/skin/dark-theme.css"],
520   classList: ["theme-dark"],
523 Tools.lightTheme = {
524   id: "light",
525   label: l10n("options.lightTheme.label2"),
526   ordinal: 2,
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 = [
537   {
538     id: "command-button-paintflashing",
539     description: l10n("toolbox.buttons.paintflashing"),
540     isTargetSupported: target => target.isLocalTab,
541     onClick(event, toolbox) {
542       toolbox.togglePaintFlashing();
543     },
544     isChecked(toolbox) {
545       return toolbox.isPaintFlashing;
546     },
547   },
548   {
549     id: "command-button-scratchpad",
550     description: l10n("toolbox.buttons.scratchpad"),
551     isTargetSupported: target => target.isLocalTab,
552     onClick(event, toolbox) {
553       ScratchpadManager.openScratchpad();
554     },
555   },
556   {
557     id: "command-button-replay",
558     description: l10n("toolbox.buttons.replay"),
559     isTargetSupported: target =>
560       Services.prefs.getBoolPref("devtools.recordreplay.mvp.enabled") &&
561       !target.canRewind &&
562       target.isLocalTab,
563     onClick: () => reloadAndRecordTab(),
564     isChecked: () => false,
565   },
566   {
567     id: "command-button-stop-replay",
568     description: l10n("toolbox.buttons.stopReplay"),
569     isTargetSupported: target =>
570       Services.prefs.getBoolPref("devtools.recordreplay.mvp.enabled") &&
571       target.canRewind &&
572       target.isLocalTab,
573     onClick: () => reloadAndStopRecordingTab(),
574     isChecked: () => true,
575   },
576   {
577     id: "command-button-responsive",
578     description: l10n(
579       "toolbox.buttons.responsive",
580       osString == "Darwin" ? "Cmd+Opt+M" : "Ctrl+Shift+M"
581     ),
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" });
587     },
588     isChecked(toolbox) {
589       if (!toolbox.target.tab) {
590         return false;
591       }
592       return ResponsiveUIManager.isActiveForTab(toolbox.target.tab);
593     },
594     setup(toolbox, onChange) {
595       ResponsiveUIManager.on("on", onChange);
596       ResponsiveUIManager.on("off", onChange);
597     },
598     teardown(toolbox, onChange) {
599       ResponsiveUIManager.off("on", onChange);
600       ResponsiveUIManager.off("off", onChange);
601     },
602   },
603   {
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"
612       );
613       const args = { fullpage: true, file: true };
614       if (clipboardEnabled) {
615         args.clipboard = true;
616       }
617       const screenshotFront = await toolbox.target.getFront("screenshot");
618       await screenshotFront.captureAndSave(toolbox.win, args);
619     },
620   },
621   createHighlightButton("RulersHighlighter", "rulers"),
622   createHighlightButton("MeasuringToolHighlighter", "measure"),
625 function createHighlightButton(highlighterName, id) {
626   return {
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(
633         highlighterName
634       );
635       if (highlighter.isShown()) {
636         return highlighter.hide();
637       }
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
640       // servers.
641       return highlighter.show({});
642     },
643     isChecked(toolbox) {
644       // if the inspector doesn't exist, then the highlighter has not yet been connected
645       // to the front end.
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.
652         return false;
653       }
654       const highlighter = inspectorFront.getKnownHighlighter(highlighterName);
655       return highlighter && highlighter.isShown();
656     },
657   };
661  * Lookup l10n string from a string bundle.
663  * @param {string} name
664  *        The key to lookup.
665  * @param {...string} args
666  *        Optional format argument.
667  * @returns A localized version of the given key.
668  */
669 function l10n(name, ...args) {
670   try {
671     return args ? L10N.getFormatStr(name, ...args) : L10N.getStr(name);
672   } catch (ex) {
673     console.log("Error reading '" + name + "'");
674     throw new Error("l10n error with " + name);
675   }
678 function functionkey(shortkey) {
679   return shortkey.split("_")[1];