tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

definitions.js (25238B)


      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/. */
      4 
      5 "use strict";
      6 
      7 const osString = Services.appinfo.OS;
      8 
      9 // Panels
     10 loader.lazyGetter(
     11  this,
     12  "OptionsPanel",
     13  () =>
     14    require("resource://devtools/client/framework/toolbox-options.js")
     15      .OptionsPanel
     16 );
     17 loader.lazyGetter(
     18  this,
     19  "InspectorPanel",
     20  () => require("resource://devtools/client/inspector/panel.js").InspectorPanel
     21 );
     22 loader.lazyGetter(
     23  this,
     24  "WebConsolePanel",
     25  () =>
     26    require("resource://devtools/client/webconsole/panel.js").WebConsolePanel
     27 );
     28 loader.lazyGetter(
     29  this,
     30  "DebuggerPanel",
     31  () => require("resource://devtools/client/debugger/panel.js").DebuggerPanel
     32 );
     33 loader.lazyGetter(
     34  this,
     35  "StyleEditorPanel",
     36  () =>
     37    require("resource://devtools/client/styleeditor/panel.js").StyleEditorPanel
     38 );
     39 loader.lazyGetter(
     40  this,
     41  "MemoryPanel",
     42  () => require("resource://devtools/client/memory/panel.js").MemoryPanel
     43 );
     44 loader.lazyGetter(
     45  this,
     46  "NewPerformancePanel",
     47  () =>
     48    require("resource://devtools/client/performance-new/panel/panel.js")
     49      .PerformancePanel
     50 );
     51 loader.lazyGetter(
     52  this,
     53  "NetMonitorPanel",
     54  () =>
     55    require("resource://devtools/client/netmonitor/panel.js").NetMonitorPanel
     56 );
     57 loader.lazyGetter(
     58  this,
     59  "StoragePanel",
     60  () => require("resource://devtools/client/storage/panel.js").StoragePanel
     61 );
     62 loader.lazyGetter(
     63  this,
     64  "DomPanel",
     65  () => require("resource://devtools/client/dom/panel.js").DomPanel
     66 );
     67 loader.lazyGetter(
     68  this,
     69  "AccessibilityPanel",
     70  () =>
     71    require("resource://devtools/client/accessibility/panel.js")
     72      .AccessibilityPanel
     73 );
     74 loader.lazyGetter(
     75  this,
     76  "ApplicationPanel",
     77  () =>
     78    require("resource://devtools/client/application/panel.js").ApplicationPanel
     79 );
     80 loader.lazyGetter(
     81  this,
     82  "AntiTrackingPanel",
     83  () =>
     84    require("resource://devtools/client/anti-tracking/panel.js")
     85      .AntiTrackingPanel
     86 );
     87 
     88 // Other dependencies
     89 loader.lazyRequireGetter(
     90  this,
     91  "ResponsiveUIManager",
     92  "resource://devtools/client/responsive/manager.js"
     93 );
     94 loader.lazyRequireGetter(
     95  this,
     96  "TRACER_LOG_METHODS",
     97  "resource://devtools/shared/specs/tracer.js",
     98  true
     99 );
    100 
    101 const lazy = {};
    102 ChromeUtils.defineESModuleGetters(lazy, {
    103  AppConstants: "resource://gre/modules/AppConstants.sys.mjs",
    104 });
    105 loader.lazyRequireGetter(
    106  this,
    107  "DevToolsExperimentalPrefs",
    108  "resource://devtools/client/devtools-experimental-prefs.js"
    109 );
    110 loader.lazyRequireGetter(
    111  this,
    112  "captureAndSaveScreenshot",
    113  "resource://devtools/client/shared/screenshot.js",
    114  true
    115 );
    116 loader.lazyRequireGetter(
    117  this,
    118  "Menu",
    119  "resource://devtools/client/framework/menu.js"
    120 );
    121 loader.lazyRequireGetter(
    122  this,
    123  "MenuItem",
    124  "resource://devtools/client/framework/menu-item.js"
    125 );
    126 
    127 const { TYPES: HIGHLIGHTER_TYPES } = ChromeUtils.importESModule(
    128  "resource://devtools/shared/highlighters.mjs"
    129 );
    130 
    131 const { LocalizationHelper } = require("resource://devtools/shared/l10n.js");
    132 const L10N = new LocalizationHelper(
    133  "devtools/client/locales/startup.properties"
    134 );
    135 const CommandKeys = new Localization(
    136  ["devtools/startup/key-shortcuts.ftl"],
    137  true
    138 );
    139 
    140 var Tools = {};
    141 exports.Tools = Tools;
    142 
    143 // Definitions
    144 Tools.options = {
    145  id: "options",
    146  ordinal: 0,
    147  url: "chrome://devtools/content/framework/toolbox-options.html",
    148  icon: "chrome://devtools/skin/images/settings.svg",
    149  bgTheme: "theme-body",
    150  label: l10n("options.label"),
    151  iconOnly: true,
    152  panelLabel: l10n("options.panelLabel"),
    153  tooltip: l10n("optionsButton.tooltip"),
    154  inMenu: false,
    155 
    156  isToolSupported() {
    157    return true;
    158  },
    159 
    160  build(iframeWindow, toolbox, commands) {
    161    return new OptionsPanel(iframeWindow, toolbox, commands);
    162  },
    163 };
    164 
    165 Tools.inspector = {
    166  id: "inspector",
    167  accesskey: l10n("inspector.accesskey"),
    168  ordinal: 1,
    169  icon: "chrome://devtools/skin/images/tool-inspector.svg",
    170  url: "chrome://devtools/content/inspector/index.xhtml",
    171  label: l10n("inspector.label"),
    172  panelLabel: l10n("inspector.panelLabel"),
    173  get tooltip() {
    174    const key = commandkey("devtools-commandkey-inspector");
    175    if (osString == "Darwin") {
    176      const cmdShiftC = "Cmd+Shift+" + key;
    177      const cmdOptC = "Cmd+Opt+" + key;
    178      return l10n("inspector.mac.tooltip", cmdShiftC, cmdOptC);
    179    }
    180 
    181    const ctrlShiftC = "Ctrl+Shift+" + key;
    182    return l10n("inspector.tooltip2", ctrlShiftC);
    183  },
    184  inMenu: false,
    185 
    186  preventClosingOnKey: true,
    187  // preventRaisingOnKey is used to keep the focus on the content window for shortcuts
    188  // that trigger the element picker.
    189  preventRaisingOnKey: true,
    190  onkey(panel, toolbox) {
    191    if (
    192      Services.prefs.getBoolPref("devtools.command-button-pick.enabled", false)
    193    ) {
    194      toolbox.nodePicker.togglePicker();
    195    }
    196  },
    197 
    198  isToolSupported(toolbox) {
    199    return toolbox.target.hasActor("inspector");
    200  },
    201 
    202  build(iframeWindow, toolbox, commands) {
    203    return new InspectorPanel(iframeWindow, toolbox, commands);
    204  },
    205 };
    206 Tools.webConsole = {
    207  id: "webconsole",
    208  accesskey: l10n("webConsoleCmd.accesskey"),
    209  ordinal: 2,
    210  url: "chrome://devtools/content/webconsole/index.html",
    211  icon: "chrome://devtools/skin/images/tool-webconsole.svg",
    212  label: l10n("ToolboxTabWebconsole.label"),
    213  menuLabel: l10n("MenuWebconsole.label"),
    214  panelLabel: l10n("ToolboxWebConsole.panelLabel"),
    215  get tooltip() {
    216    return l10n(
    217      "ToolboxWebconsole.tooltip2",
    218      (osString == "Darwin" ? "Cmd+Opt+" : "Ctrl+Shift+") +
    219        commandkey("devtools-commandkey-webconsole")
    220    );
    221  },
    222  inMenu: false,
    223 
    224  preventClosingOnKey: true,
    225  onkey(panel, toolbox) {
    226    if (toolbox.splitConsole) {
    227      return toolbox.focusConsoleInput();
    228    }
    229 
    230    panel.focusInput();
    231    return undefined;
    232  },
    233 
    234  isToolSupported() {
    235    return true;
    236  },
    237  build(iframeWindow, toolbox, commands) {
    238    return new WebConsolePanel(iframeWindow, toolbox, commands);
    239  },
    240 };
    241 
    242 Tools.jsdebugger = {
    243  id: "jsdebugger",
    244  accesskey: l10n("debuggerMenu.accesskey"),
    245  ordinal: 3,
    246  icon: "chrome://devtools/skin/images/tool-debugger.svg",
    247  url: "chrome://devtools/content/debugger/index.html",
    248  label: l10n("ToolboxDebugger.label"),
    249  panelLabel: l10n("ToolboxDebugger.panelLabel"),
    250  get tooltip() {
    251    return l10n(
    252      "ToolboxDebugger.tooltip4",
    253      (osString == "Darwin" ? "Cmd+Opt+" : "Ctrl+Shift+") +
    254        commandkey("devtools-commandkey-jsdebugger")
    255    );
    256  },
    257  inMenu: false,
    258  isToolSupported() {
    259    return true;
    260  },
    261  build(iframeWindow, toolbox, commands) {
    262    return new DebuggerPanel(iframeWindow, toolbox, commands);
    263  },
    264 };
    265 
    266 Tools.styleEditor = {
    267  id: "styleeditor",
    268  ordinal: 5,
    269  visibilityswitch: "devtools.styleeditor.enabled",
    270  accesskey: l10n("open.accesskey"),
    271  icon: "chrome://devtools/skin/images/tool-styleeditor.svg",
    272  url: "chrome://devtools/content/styleeditor/index.xhtml",
    273  label: l10n("ToolboxStyleEditor.label"),
    274  panelLabel: l10n("ToolboxStyleEditor.panelLabel"),
    275  get tooltip() {
    276    return l10n(
    277      "ToolboxStyleEditor.tooltip3",
    278      "Shift+" + functionkey(commandkey("devtools-commandkey-styleeditor"))
    279    );
    280  },
    281  inMenu: false,
    282  isToolSupported(toolbox) {
    283    return toolbox.target.hasActor("styleSheets");
    284  },
    285 
    286  build(iframeWindow, toolbox, commands) {
    287    return new StyleEditorPanel(iframeWindow, toolbox, commands);
    288  },
    289 };
    290 
    291 Tools.performance = {
    292  id: "performance",
    293  ordinal: 6,
    294  icon: "chrome://devtools/skin/images/tool-profiler.svg",
    295  url: "chrome://devtools/content/performance-new/panel/index.xhtml",
    296  visibilityswitch: "devtools.performance.enabled",
    297  label: l10n("performance.label"),
    298  panelLabel: l10n("performance.panelLabel"),
    299  get tooltip() {
    300    return l10n(
    301      "performance.tooltip",
    302      "Shift+" + functionkey(commandkey("devtools-commandkey-performance"))
    303    );
    304  },
    305  accesskey: l10n("performance.accesskey"),
    306  inMenu: false,
    307  isToolSupported(toolbox) {
    308    // Only use the new performance panel on local tab toolboxes, as they are guaranteed
    309    // to have a performance actor.
    310    // Remote tab toolboxes (eg about:devtools-toolbox from about:debugging) should not
    311    // use the performance panel; about:debugging provides a "Profile performance" button
    312    // which can be used instead, without having the overhead of starting a remote toolbox.
    313    // Also accept the Browser Toolbox, so that we can profile its process via a second browser toolbox.
    314    return (
    315      toolbox.commands.descriptorFront.isLocalTab || toolbox.isBrowserToolbox
    316    );
    317  },
    318  build(frame, toolbox, commands) {
    319    return new NewPerformancePanel(frame, toolbox, commands);
    320  },
    321 };
    322 
    323 Tools.memory = {
    324  id: "memory",
    325  ordinal: 7,
    326  icon: "chrome://devtools/skin/images/tool-memory.svg",
    327  url: "chrome://devtools/content/memory/index.xhtml",
    328  visibilityswitch: "devtools.memory.enabled",
    329  label: l10n("memory.label"),
    330  panelLabel: l10n("memory.panelLabel"),
    331  tooltip: l10n("memory.tooltip"),
    332 
    333  isToolSupported(toolbox) {
    334    const { descriptorFront } = toolbox.commands;
    335    return (
    336      !descriptorFront.isWebExtensionDescriptor &&
    337      !descriptorFront.isWorkerDescriptor
    338    );
    339  },
    340 
    341  build(frame, toolbox, commands) {
    342    return new MemoryPanel(frame, toolbox, commands);
    343  },
    344 };
    345 
    346 Tools.netMonitor = {
    347  id: "netmonitor",
    348  accesskey: l10n("netmonitor.accesskey"),
    349  ordinal: 4,
    350  visibilityswitch: "devtools.netmonitor.enabled",
    351  icon: "chrome://devtools/skin/images/tool-network.svg",
    352  url: "chrome://devtools/content/netmonitor/index.html",
    353  label: l10n("netmonitor.label"),
    354  panelLabel: l10n("netmonitor.panelLabel"),
    355  get tooltip() {
    356    return l10n(
    357      "netmonitor.tooltip2",
    358      (osString == "Darwin" ? "Cmd+Opt+" : "Ctrl+Shift+") +
    359        commandkey("devtools-commandkey-netmonitor")
    360    );
    361  },
    362  inMenu: false,
    363 
    364  isToolSupported(toolbox) {
    365    return (
    366      toolbox.target.getTrait("networkMonitor") &&
    367      !toolbox.target.isWorkerTarget
    368    );
    369  },
    370 
    371  build(iframeWindow, toolbox, commands) {
    372    return new NetMonitorPanel(iframeWindow, toolbox, commands);
    373  },
    374 };
    375 
    376 Tools.storage = {
    377  id: "storage",
    378  ordinal: 8,
    379  accesskey: l10n("storage.accesskey"),
    380  visibilityswitch: "devtools.storage.enabled",
    381  icon: "chrome://devtools/skin/images/tool-storage.svg",
    382  url: "chrome://devtools/content/storage/index.xhtml",
    383  label: l10n("storage.label"),
    384  menuLabel: l10n("storage.menuLabel"),
    385  panelLabel: l10n("storage.panelLabel"),
    386  get tooltip() {
    387    return l10n(
    388      "storage.tooltip3",
    389      "Shift+" + functionkey(commandkey("devtools-commandkey-storage"))
    390    );
    391  },
    392  inMenu: false,
    393 
    394  isToolSupported(toolbox) {
    395    const { descriptorFront } = toolbox.commands;
    396    // Storage is available on all contexts debugging a BrowsingContext.
    397    // As of today, this is all but worker toolboxes.
    398    return (
    399      descriptorFront.isTabDescriptor ||
    400      descriptorFront.isParentProcessDescriptor ||
    401      descriptorFront.isWebExtensionDescriptor
    402    );
    403  },
    404 
    405  build(iframeWindow, toolbox, commands) {
    406    return new StoragePanel(iframeWindow, toolbox, commands);
    407  },
    408 };
    409 
    410 Tools.dom = {
    411  id: "dom",
    412  accesskey: l10n("dom.accesskey"),
    413  ordinal: 11,
    414  visibilityswitch: "devtools.dom.enabled",
    415  icon: "chrome://devtools/skin/images/tool-dom.svg",
    416  url: "chrome://devtools/content/dom/index.html",
    417  label: l10n("dom.label"),
    418  panelLabel: l10n("dom.panelLabel"),
    419  get tooltip() {
    420    return l10n(
    421      "dom.tooltip",
    422      (osString == "Darwin" ? "Cmd+Opt+" : "Ctrl+Shift+") +
    423        commandkey("devtools-commandkey-dom")
    424    );
    425  },
    426  inMenu: false,
    427 
    428  isToolSupported() {
    429    return true;
    430  },
    431 
    432  build(iframeWindow, toolbox, commands) {
    433    return new DomPanel(iframeWindow, toolbox, commands);
    434  },
    435 };
    436 
    437 Tools.accessibility = {
    438  id: "accessibility",
    439  accesskey: l10n("accessibility.accesskey"),
    440  ordinal: 9,
    441  modifiers: osString == "Darwin" ? "accel,alt" : "accel,shift",
    442  visibilityswitch: "devtools.accessibility.enabled",
    443  icon: "chrome://devtools/skin/images/tool-accessibility.svg",
    444  url: "chrome://devtools/content/accessibility/index.html",
    445  label: l10n("accessibility.label"),
    446  panelLabel: l10n("accessibility.panelLabel"),
    447  get tooltip() {
    448    return l10n(
    449      "accessibility.tooltip3",
    450      "Shift+" +
    451        functionkey(commandkey("devtools-commandkey-accessibility-f12"))
    452    );
    453  },
    454  inMenu: false,
    455 
    456  isToolSupported(toolbox) {
    457    return toolbox.target.hasActor("accessibility");
    458  },
    459 
    460  build(iframeWindow, toolbox, commands) {
    461    return new AccessibilityPanel(iframeWindow, toolbox, commands);
    462  },
    463 };
    464 
    465 Tools.application = {
    466  id: "application",
    467  ordinal: 10,
    468  visibilityswitch: "devtools.application.enabled",
    469  icon: "chrome://devtools/skin/images/tool-application.svg",
    470  url: "chrome://devtools/content/application/index.html",
    471  label: l10n("application.label"),
    472  panelLabel: l10n("application.panelLabel"),
    473  tooltip: l10n("application.tooltip"),
    474  inMenu: false,
    475 
    476  isToolSupported(toolbox) {
    477    return toolbox.target.hasActor("manifest");
    478  },
    479 
    480  build(iframeWindow, toolbox, commands) {
    481    return new ApplicationPanel(iframeWindow, toolbox, commands);
    482  },
    483 };
    484 
    485 Tools.antitracking = {
    486  id: "antitracking",
    487  ordinal: 11,
    488  visibilityswitch: "devtools.anti-tracking.enabled",
    489  icon: "chrome://browser/skin/tracking-protection.svg",
    490  url: "chrome://devtools/content/anti-tracking/index.html",
    491  label: "Anti tracking",
    492  panelLabel: "Anti tracking",
    493  tooltip: "Anti tracking",
    494  inMenu: false,
    495 
    496  isToolSupported() {
    497    return true;
    498  },
    499 
    500  build(iframeWindow, toolbox, commands) {
    501    return new AntiTrackingPanel(iframeWindow, toolbox, commands);
    502  },
    503 };
    504 
    505 var defaultTools = [
    506  Tools.options,
    507  Tools.webConsole,
    508  Tools.inspector,
    509  Tools.jsdebugger,
    510  Tools.styleEditor,
    511  Tools.performance,
    512  Tools.netMonitor,
    513  Tools.storage,
    514  Tools.memory,
    515  Tools.dom,
    516  Tools.accessibility,
    517  Tools.application,
    518 ];
    519 
    520 // The Anti tracking panel is an internal tool, to be enabled manually via about:config
    521 if (Services.prefs.getBoolPref("devtools.anti-tracking.enabled", false)) {
    522  defaultTools.push(Tools.antitracking);
    523 }
    524 
    525 exports.defaultTools = defaultTools;
    526 
    527 Tools.darkTheme = {
    528  id: "dark",
    529  label: l10n("options.darkTheme.label2"),
    530  ordinal: 1,
    531  stylesheets: ["chrome://devtools/skin/dark-theme.css"],
    532  classList: ["theme-dark"],
    533 };
    534 
    535 Tools.lightTheme = {
    536  id: "light",
    537  label: l10n("options.lightTheme.label2"),
    538  ordinal: 2,
    539  stylesheets: ["chrome://devtools/skin/light-theme.css"],
    540  classList: ["theme-light"],
    541 };
    542 
    543 exports.defaultThemes = [Tools.darkTheme, Tools.lightTheme];
    544 
    545 // List buttons that can be toggled to prevent adding prefs for
    546 // addons that have manually inserted toolbarbuttons into DOM.
    547 // (By default, supported target is only local tab)
    548 exports.ToolboxButtons = [
    549  {
    550    id: "command-button-experimental-prefs",
    551    description: "DevTools Experimental preferences",
    552    isToolSupported: () => !lazy.AppConstants.MOZILLA_OFFICIAL,
    553    onClick: (event, toolbox) => DevToolsExperimentalPrefs.showTooltip(toolbox),
    554    isChecked: () => DevToolsExperimentalPrefs.isAnyPreferenceEnabled(),
    555  },
    556  {
    557    id: "command-button-responsive",
    558    description: l10n(
    559      "toolbox.buttons.responsive",
    560      osString == "Darwin" ? "Cmd+Opt+M" : "Ctrl+Shift+M"
    561    ),
    562    isToolSupported: toolbox => toolbox.commands.descriptorFront.isLocalTab,
    563    onClick(event, toolbox) {
    564      const { localTab } = toolbox.commands.descriptorFront;
    565      const browserWindow = localTab.ownerDocument.defaultView;
    566      ResponsiveUIManager.toggle(browserWindow, localTab, {
    567        trigger: "toolbox",
    568      });
    569    },
    570    isChecked(toolbox) {
    571      const { localTab } = toolbox.commands.descriptorFront;
    572      if (!localTab) {
    573        return false;
    574      }
    575      return ResponsiveUIManager.isActiveForTab(localTab);
    576    },
    577    isToggle: true,
    578    setup(toolbox, onChange) {
    579      ResponsiveUIManager.on("on", onChange);
    580      ResponsiveUIManager.on("off", onChange);
    581    },
    582    teardown(toolbox, onChange) {
    583      ResponsiveUIManager.off("on", onChange);
    584      ResponsiveUIManager.off("off", onChange);
    585    },
    586  },
    587  {
    588    id: "command-button-screenshot",
    589    description: l10n("toolbox.buttons.screenshot"),
    590    isToolSupported: toolbox => {
    591      return (
    592        // @backward-compat { version 87 } We need to check for the screenshot actor as well
    593        // when connecting to older server that does not have the screenshotContentActor
    594        toolbox.target.hasActor("screenshotContent") ||
    595        toolbox.target.hasActor("screenshot")
    596      );
    597    },
    598    async onClick(event, toolbox) {
    599      // Special case for screenshot button to check for clipboard preference
    600      const clipboardEnabled = Services.prefs.getBoolPref(
    601        "devtools.screenshot.clipboard.enabled"
    602      );
    603 
    604      // When screenshot to clipboard is enabled disabling saving to file
    605      const args = {
    606        fullpage: true,
    607        file: !clipboardEnabled,
    608        clipboard: clipboardEnabled,
    609      };
    610 
    611      const messages = await captureAndSaveScreenshot(
    612        toolbox.target,
    613        toolbox.win,
    614        args
    615      );
    616      const notificationBox = toolbox.getNotificationBox();
    617      const priorityMap = {
    618        error: notificationBox.PRIORITY_CRITICAL_HIGH,
    619        warn: notificationBox.PRIORITY_WARNING_HIGH,
    620      };
    621      for (const { text, level } of messages) {
    622        // captureAndSaveScreenshot returns "saved" messages, that indicate where the
    623        // screenshot was saved. In regular toolbox, we don't want to display them as
    624        // the download UI can be used to open them.
    625        // But in the browser toolbox, we can't see the download UI, so we'll display the
    626        // saved message so the user knows there the file was saved.
    627        if (
    628          !toolbox.isBrowserToolbox &&
    629          level !== "warn" &&
    630          level !== "error"
    631        ) {
    632          continue;
    633        }
    634        notificationBox.appendNotification(
    635          text,
    636          null,
    637          null,
    638          priorityMap[level] || notificationBox.PRIORITY_INFO_MEDIUM
    639        );
    640      }
    641    },
    642  },
    643  createHighlightButton(
    644    [HIGHLIGHTER_TYPES.RULERS, HIGHLIGHTER_TYPES.VIEWPORT_SIZE],
    645    "rulers"
    646  ),
    647  createHighlightButton([HIGHLIGHTER_TYPES.MEASURING], "measure"),
    648  {
    649    id: "command-button-jstracer",
    650    description: l10n(
    651      "toolbox.buttons.jstracer",
    652      osString == "Darwin" ? "Cmd+Shift+5" : "Ctrl+Shift+5"
    653    ),
    654    isToolSupported: () =>
    655      Services.prefs.getBoolPref(
    656        "devtools.debugger.features.javascript-tracing",
    657        false
    658      ),
    659    async onClick(event, toolbox) {
    660      await toolbox.commands.tracerCommand.toggle();
    661    },
    662    isChecked(toolbox) {
    663      const { tracerCommand } = toolbox.commands;
    664      const button = toolbox.doc.getElementById("command-button-jstracer");
    665      if (button) {
    666        button.classList.toggle(
    667          "pending",
    668          tracerCommand.isTracingEnabled && !tracerCommand.isTracingActive
    669        );
    670      }
    671      return tracerCommand.isTracingEnabled;
    672    },
    673    isToggle: true,
    674    setup(toolbox, onChange) {
    675      toolbox.commands.tracerCommand.on("toggle", onChange);
    676    },
    677    teardown(toolbox, onChange) {
    678      toolbox.commands.tracerCommand.off("toggle", onChange);
    679    },
    680    getContextMenu(toolbox) {
    681      const menu = new Menu();
    682      const options = toolbox.commands.tracerCommand.getTracingOptions();
    683      const { logMethod } = options;
    684      menu.append(
    685        new MenuItem({
    686          id: "jstracer-menu-item-debugger-sidebar",
    687          label: l10n(
    688            "toolbox.buttons.jstracer.menu-item.trace-to-debugger-sidebar"
    689          ),
    690          checked: logMethod == TRACER_LOG_METHODS.DEBUGGER_SIDEBAR,
    691          type: "radio",
    692          click: () => {
    693            Services.prefs.setStringPref(
    694              "devtools.debugger.javascript-tracing-log-method",
    695              TRACER_LOG_METHODS.DEBUGGER_SIDEBAR
    696            );
    697          },
    698        })
    699      );
    700      menu.append(
    701        new MenuItem({
    702          id: "jstracer-menu-item-console",
    703          label: l10n("traceInWebConsole"),
    704          checked: logMethod == TRACER_LOG_METHODS.CONSOLE,
    705          type: "radio",
    706          click: () => {
    707            Services.prefs.setStringPref(
    708              "devtools.debugger.javascript-tracing-log-method",
    709              TRACER_LOG_METHODS.CONSOLE
    710            );
    711          },
    712        })
    713      );
    714      menu.append(
    715        new MenuItem({
    716          id: "jstracer-menu-item-profiler",
    717          label: l10n("traceInProfiler"),
    718          checked: logMethod == TRACER_LOG_METHODS.PROFILER,
    719          type: "radio",
    720          click: () => {
    721            Services.prefs.setStringPref(
    722              "devtools.debugger.javascript-tracing-log-method",
    723              TRACER_LOG_METHODS.PROFILER
    724            );
    725          },
    726        })
    727      );
    728      menu.append(
    729        new MenuItem({
    730          id: "jstracer-menu-item-stdout",
    731          label: l10n("traceInStdout"),
    732          type: "radio",
    733          checked: logMethod == TRACER_LOG_METHODS.STDOUT,
    734          click: () => {
    735            Services.prefs.setStringPref(
    736              "devtools.debugger.javascript-tracing-log-method",
    737              TRACER_LOG_METHODS.STDOUT
    738            );
    739          },
    740        })
    741      );
    742      menu.append(new MenuItem({ type: "separator" }));
    743      menu.append(
    744        new MenuItem({
    745          id: "jstracer-menu-item-next-interaction",
    746          label: l10n("traceOnNextInteraction"),
    747          type: "checkbox",
    748          checked: options.traceOnNextInteraction,
    749          click: () => {
    750            Services.prefs.setBoolPref(
    751              "devtools.debugger.javascript-tracing-on-next-interaction",
    752              !options.traceOnNextInteraction
    753            );
    754          },
    755        })
    756      );
    757      menu.append(
    758        new MenuItem({
    759          id: "jstracer-menu-item-next-load",
    760          label: l10n("traceOnNextLoad"),
    761          type: "checkbox",
    762          checked: options.traceOnNextLoad,
    763          click: () => {
    764            Services.prefs.setBoolPref(
    765              "devtools.debugger.javascript-tracing-on-next-load",
    766              !options.traceOnNextLoad
    767            );
    768          },
    769        })
    770      );
    771      menu.append(new MenuItem({ type: "separator" }));
    772      menu.append(
    773        new MenuItem({
    774          id: "jstracer-menu-item-log-values",
    775          label: l10n("traceValues"),
    776          type: "checkbox",
    777          checked: options.traceValues,
    778          click: () => {
    779            Services.prefs.setBoolPref(
    780              "devtools.debugger.javascript-tracing-values",
    781              !options.traceValues
    782            );
    783          },
    784        })
    785      );
    786      menu.append(
    787        new MenuItem({
    788          id: "jstracer-menu-item-function-return",
    789          label: l10n("traceFunctionReturn"),
    790          type: "checkbox",
    791          checked: options.traceFunctionReturn,
    792          click: () => {
    793            Services.prefs.setBoolPref(
    794              "devtools.debugger.javascript-tracing-function-return",
    795              !options.traceFunctionReturn
    796            );
    797          },
    798        })
    799      );
    800      return menu;
    801    },
    802  },
    803 ];
    804 
    805 function createHighlightButton(highlighters, id) {
    806  return {
    807    id: `command-button-${id}`,
    808    description: l10n(`toolbox.buttons.${id}`),
    809    isToolSupported: toolbox =>
    810      toolbox.commands.descriptorFront.isTabDescriptor,
    811    async onClick(event, toolbox) {
    812      const inspectorFront = await toolbox.target.getFront("inspector");
    813 
    814      await Promise.all(
    815        highlighters.map(async name => {
    816          const highlighter =
    817            await inspectorFront.getOrCreateHighlighterByType(name);
    818 
    819          if (highlighter.isShown()) {
    820            await highlighter.hide();
    821          } else {
    822            await highlighter.show();
    823          }
    824        })
    825      );
    826    },
    827    isChecked(toolbox) {
    828      // if the inspector doesn't exist, then the highlighter has not yet been connected
    829      // to the front end.
    830      const inspectorFront = toolbox.target.getCachedFront("inspector");
    831      if (!inspectorFront) {
    832        // initialize the inspector front asyncronously. There is a potential for buggy
    833        // behavior here, but we need to change how the buttons get data (have them
    834        // consume data from reducers rather than writing our own version) in order to
    835        // fix this properly.
    836        return false;
    837      }
    838 
    839      return highlighters.every(name =>
    840        inspectorFront.getKnownHighlighter(name)?.isShown()
    841      );
    842    },
    843    isToggle: true,
    844  };
    845 }
    846 
    847 /**
    848 * Lookup l10n string from a string bundle.
    849 *
    850 * @param {string} name
    851 *        The key to lookup.
    852 * @param {...string} args
    853 *        Optional format argument.
    854 * @returns A localized version of the given key.
    855 */
    856 function l10n(name, ...args) {
    857  try {
    858    return args ? L10N.getFormatStr(name, ...args) : L10N.getStr(name);
    859  } catch (ex) {
    860    console.log("Error reading '" + name + "'");
    861    throw new Error("l10n error with " + name);
    862  }
    863 }
    864 
    865 function commandkey(name) {
    866  try {
    867    return CommandKeys.formatValueSync(name);
    868  } catch (ex) {
    869    console.log("Error reading '" + name + "'");
    870    throw new Error("l10n error with " + name);
    871  }
    872 }
    873 
    874 function functionkey(shortkey) {
    875  return shortkey.split("_")[1];
    876 }