Example #1
0
function* testSubmenu(toolbox) {
  let clickFired = false;
  let menu = new Menu({
    id: "menu-popup",
  });
  let submenu = new Menu({
    id: "submenu-popup",
  });
  submenu.append(new MenuItem({
    label: "Submenu item",
    click: () => {
      info("Click callback has fired for submenu item");
      clickFired = true;
    },
  }));
  menu.append(new MenuItem({
    label: "Submenu parent",
    submenu: submenu,
  }));

  menu.popup(0, 0, toolbox);
  ok(toolbox.doc.querySelector("#menu-popup"), "A popup is in the DOM");
  is(toolbox.doc.querySelectorAll("#menu-popup > menuitem").length, 0, "No menuitem children");

  let menus = toolbox.doc.querySelectorAll("#menu-popup > menu");
  is(menus.length, 1, "Correct number of menus");
  is(menus[0].getAttribute("label"), "Submenu parent", "Correct label for menus");

  let subMenuItems = menus[0].querySelectorAll("menupopup > menuitem");
  is(subMenuItems.length, 1, "Correct number of submenu items");
  is(subMenuItems[0].getAttribute("label"), "Submenu item", "Correct label");

  yield once(menu, "open");
  let closed = once(menu, "close");

  info("Using keyboard navigation to open, close, and reopen the submenu");
  let shown = once(menus[0], "popupshown");
  EventUtils.synthesizeKey("VK_DOWN", {});
  EventUtils.synthesizeKey("VK_RIGHT", {});
  yield shown;

  let hidden = once(menus[0], "popuphidden");
  EventUtils.synthesizeKey("VK_LEFT", {});
  yield hidden;

  shown = once(menus[0], "popupshown");
  EventUtils.synthesizeKey("VK_RIGHT", {});
  yield shown;

  info("Clicking the submenu item");
  EventUtils.synthesizeMouseAtCenter(subMenuItems[0], {}, toolbox.doc.defaultView);

  yield closed;
  ok(clickFired, "Click has fired");
}
Example #2
0
function testMenuItems() {
  const menu = new Menu();
  const menuItem1 = new MenuItem();
  const menuItem2 = new MenuItem();

  menu.append(menuItem1);
  menu.append(menuItem2);

  is(menu.items.length, 2, "Correct number of 'items'");
  is(menu.items[0], menuItem1, "Correct reference to MenuItem");
  is(menu.items[1], menuItem2, "Correct reference to MenuItem");
}
Example #3
0
 this.state.tabs.forEach(tab => {
   menu.append(new MenuItem({
     label: tab.title,
     type: "checkbox",
     checked: this.getCurrentTabId() == tab.id,
     click: () => this.select(tab.id),
   }));
 });
Example #4
0
 panelDefinitions.forEach(({id, label}) => {
   menu.append(new MenuItem({
     checked: currentToolId === id,
     click: () => {
       selectTool(id);
     },
     id: "all-tools-menupopup-" + id,
     label,
     type: "checkbox",
   }));
 });
Example #5
0
 panelDefinitions.forEach(({id, label}) => {
   if (this.state.overflowedTabIds.includes(id)) {
     menu.append(new MenuItem({
       click: () => {
         selectTool(id, "tab_switch");
       },
       id: "tools-chevron-menupopup-" + id,
       label,
       type: "checkbox",
     }));
   }
 });
Example #6
0
/**
 * Display the "..." menu (affectionately known as the meatball menu).
 *
 * @param {Object} menuButton
 *        The <button> element from which the menu should pop out. The geometry
 *        of this element is used to position the menu.
 * @param {Object} props
 *        Properties as described below.
 * @param {string} props.currentToolId
 *        The id of the currently selected tool.
 * @param {Object[]} props.hostTypes
 *        Array of host type objects.
 *        This array will be empty if we shouldn't shouldn't show any dock
 *        options.
 * @param {string} props.hostTypes[].position
 *        Position name.
 * @param {Function} props.hostTypes[].switchHost
 *        Function to switch the host.
 * @param {string} props.currentHostType
 *        The current docking configuration.
 * @param {boolean} isSplitConsoleActive
 *        Is the split console currently visible?
 * @param {boolean|undefined} disableAutohide
 *        Are we disabling the behavior where pop-ups are automatically
 *        closed when clicking outside them.
 *        (Only defined for the browser toolbox.)
 * @param {Function} selectTool
 *        Function to select a tool based on its id.
 * @param {Function} toggleOptions
 *        Function to turn the options panel on / off.
 * @param {Function} toggleSplitConsole
 *        Function to turn the split console on / off.
 * @param {Function} toggleNoAutohide
 *        Function to turn the disable pop-up autohide behavior on / off.
 * @param {Object} props.L10N
 *        Localization interface.
 * @param {Object} props.toolbox
 *        The devtools toolbox. Used by the Menu component to determine which
 *        document to use.
 */
function showMeatballMenu(
  menuButton,
  {
    currentToolId,
    hostTypes,
    currentHostType,
    isSplitConsoleActive,
    disableAutohide,
    toggleOptions,
    toggleSplitConsole,
    toggleNoAutohide,
    L10N,
    toolbox,
  }
) {
  const menu = new Menu({ id: "toolbox-meatball-menu" });

  // Dock options
  for (const hostType of hostTypes) {
    const l10nkey =
      hostType.position === "window"
        ? "separateWindow"
        : hostType.position;
    menu.append(
      new MenuItem({
        id: `toolbox-meatball-menu-dock-${hostType.position}`,
        label: L10N.getStr(`toolbox.meatballMenu.dock.${l10nkey}.label`),
        click: () => hostType.switchHost(),
        type: "checkbox",
        checked: hostType.position === currentHostType,
      })
    );
  }

  if (menu.items.length) {
    menu.append(new MenuItem({ type: "separator" }));
  }

  // Split console
  if (currentToolId !== "webconsole") {
    menu.append(new MenuItem({
      id: "toolbox-meatball-menu-splitconsole",
      label: L10N.getStr(
        `toolbox.meatballMenu.${
          isSplitConsoleActive ? "hideconsole" : "splitconsole"
        }.label`
      ),
      accelerator: "Esc",
      click: toggleSplitConsole,
    }));
  }

  // Disable pop-up autohide
  //
  // If |disableAutohide| is undefined, it means this feature is not available
  // in this context.
  if (typeof disableAutohide !== "undefined") {
    menu.append(new MenuItem({
      id: "toolbox-meatball-menu-noautohide",
      label: L10N.getStr("toolbox.meatballMenu.noautohide.label"),
      type: "checkbox",
      checked: disableAutohide,
      click: toggleNoAutohide,
    }));
  }

  // Settings
  menu.append(new MenuItem({
    id: "toolbox-meatball-menu-settings",
    label: L10N.getStr("toolbox.meatballMenu.settings.label"),
    accelerator: L10N.getStr("toolbox.help.key"),
    click: () => toggleOptions(),
  }));

  if (menu.items.length) {
    menu.append(new MenuItem({ type: "separator" }));
  }

  // Getting started
  menu.append(new MenuItem({
    id: "toolbox-meatball-menu-documentation",
    label: L10N.getStr("toolbox.meatballMenu.documentation.label"),
    click: () => {
      openWebLink(
        "https://developer.mozilla.org/docs/Tools?utm_source=devtools&utm_medium=tabbar-menu");
    },
  }));

  // Give feedback
  menu.append(new MenuItem({
    id: "toolbox-meatball-menu-community",
    label: L10N.getStr("toolbox.meatballMenu.community.label"),
    click: () => {
      openWebLink(
        "https://discourse.mozilla.org/c/devtools?utm_source=devtools&utm_medium=tabbar-menu");
    },
  }));

  const rect = menuButton.getBoundingClientRect();
  const screenX = menuButton.ownerDocument.defaultView.mozInnerScreenX;
  const screenY = menuButton.ownerDocument.defaultView.mozInnerScreenY;

  // Display the popup below the button.
  menu.popupWithZoom(rect.left + screenX, rect.bottom + screenY, toolbox);
}
Example #7
0
async function testMenuPopup(toolbox) {
  let clickFired = false;

  const menu = new Menu({
    id: "menu-popup",
  });
  menu.append(new MenuItem({ type: "separator" }));

  const MENU_ITEMS = [
    new MenuItem({
      id: "menu-item-1",
      label: "Normal Item",
      click: () => {
        info("Click callback has fired for menu item");
        clickFired = true;
      },
    }),
    new MenuItem({
      label: "Checked Item",
      type: "checkbox",
      checked: true,
    }),
    new MenuItem({
      label: "Radio Item",
      type: "radio",
    }),
    new MenuItem({
      label: "Disabled Item",
      disabled: true,
    }),
    new MenuItem({
      l10nID: "editmenu-undo",
    }),
  ];

  for (const item of MENU_ITEMS) {
    menu.append(item);
  }

  // Append an invisible MenuItem, which shouldn't show up in the DOM
  menu.append(new MenuItem({
    label: "Invisible",
    visible: false,
  }));

  menu.popup(0, 0, toolbox.doc);

  ok(toolbox.topDoc.querySelector("#menu-popup"), "A popup is in the DOM");

  const menuSeparators =
    toolbox.topDoc.querySelectorAll("#menu-popup > menuseparator");
  is(menuSeparators.length, 1, "A separator is in the menu");

  const menuItems = toolbox.topDoc.querySelectorAll("#menu-popup > menuitem");
  is(menuItems.length, MENU_ITEMS.length, "Correct number of menuitems");

  is(menuItems[0].id, MENU_ITEMS[0].id, "Correct id for menuitem");
  is(menuItems[0].getAttribute("label"), MENU_ITEMS[0].label, "Correct label");

  is(menuItems[1].getAttribute("label"), MENU_ITEMS[1].label, "Correct label");
  is(menuItems[1].getAttribute("type"), "checkbox", "Correct type attr");
  is(menuItems[1].getAttribute("checked"), "true", "Has checked attr");

  is(menuItems[2].getAttribute("label"), MENU_ITEMS[2].label, "Correct label");
  is(menuItems[2].getAttribute("type"), "radio", "Correct type attr");
  ok(!menuItems[2].hasAttribute("checked"), "Doesn't have checked attr");

  is(menuItems[3].getAttribute("label"), MENU_ITEMS[3].label, "Correct label");
  is(menuItems[3].getAttribute("disabled"), "true", "disabled attr menuitem");

  is(menuItems[4].getAttribute("data-l10n-id"), MENU_ITEMS[4].l10nID, "Correct localization attribute");

  await once(menu, "open");
  const closed = once(menu, "close");
  EventUtils.synthesizeMouseAtCenter(menuItems[0], {}, toolbox.topWindow);
  await closed;
  ok(clickFired, "Click has fired");

  ok(!toolbox.topDoc.querySelector("#menu-popup"), "Popup removed from the DOM");
}
Example #8
0
async function testSubmenu(toolbox) {
  let clickFired = false;
  const menu = new Menu({
    id: "menu-popup",
  });
  const submenu = new Menu({
    id: "submenu-popup",
  });
  submenu.append(new MenuItem({
    label: "Submenu item",
    click: () => {
      info("Click callback has fired for submenu item");
      clickFired = true;
    },
  }));
  menu.append(new MenuItem({
    l10nID: "editmenu-copy",
    submenu: submenu,
  }));
  menu.append(new MenuItem({
    label: "Submenu parent with attributes",
    id: "submenu-parent-with-attrs",
    submenu: submenu,
    accesskey: "A",
    disabled: true,
  }));

  menu.popup(0, 0, toolbox.doc);
  ok(toolbox.topDoc.querySelector("#menu-popup"), "A popup is in the DOM");
  is(toolbox.topDoc.querySelectorAll("#menu-popup > menuitem").length, 0,
    "No menuitem children");

  const menus = toolbox.topDoc.querySelectorAll("#menu-popup > menu");
  is(menus.length, 2, "Correct number of menus");
  ok(!menus[0].hasAttribute("label"), "No label: should be set by localization");
  ok(!menus[0].hasAttribute("disabled"), "Correct disabled state");
  is(menus[0].getAttribute("data-l10n-id"), "editmenu-copy", "Correct localization attribute");

  is(menus[1].getAttribute("accesskey"), "A", "Correct accesskey");
  ok(menus[1].hasAttribute("disabled"), "Correct disabled state");
  is(menus[1].id, "submenu-parent-with-attrs", "Correct id");

  const subMenuItems = menus[0].querySelectorAll("menupopup > menuitem");
  is(subMenuItems.length, 1, "Correct number of submenu items");
  is(subMenuItems[0].getAttribute("label"), "Submenu item", "Correct label");

  await once(menu, "open");
  const closed = once(menu, "close");

  info("Using keyboard navigation to open, close, and reopen the submenu");
  let shown = once(menus[0], "popupshown");
  EventUtils.synthesizeKey("KEY_ArrowDown");
  EventUtils.synthesizeKey("KEY_ArrowRight");
  await shown;

  const hidden = once(menus[0], "popuphidden");
  EventUtils.synthesizeKey("KEY_ArrowLeft");
  await hidden;

  shown = once(menus[0], "popupshown");
  EventUtils.synthesizeKey("KEY_ArrowRight");
  await shown;

  info("Clicking the submenu item");
  EventUtils.synthesizeMouseAtCenter(subMenuItems[0], {}, toolbox.topWindow);

  await closed;
  ok(clickFired, "Click has fired");
}
    return NetMonitorView.RequestsMenu.items;
  },

  /**
   * Handle the context menu opening. Hide items if no request is selected.
   * Since visible attribute only accept boolean value but the method call may
   * return undefined, we use !! to force convert any object to boolean
   */
  open({ screenX = 0, screenY = 0 } = {}) {
    let selectedItem = this.selectedItem;

    let menu = new Menu();
    menu.append(new MenuItem({
      id: "request-menu-context-copy-url",
      label: L10N.getStr("netmonitor.context.copyUrl"),
      accesskey: L10N.getStr("netmonitor.context.copyUrl.accesskey"),
      visible: !!selectedItem,
      click: () => this.copyUrl(),
    }));

    menu.append(new MenuItem({
      id: "request-menu-context-copy-url-params",
      label: L10N.getStr("netmonitor.context.copyUrlParams"),
      accesskey: L10N.getStr("netmonitor.context.copyUrlParams.accesskey"),
      visible: !!(selectedItem &&
               NetworkHelper.nsIURL(selectedItem.attachment.url).query),
      click: () => this.copyUrlParams(),
    }));

    menu.append(new MenuItem({
      id: "request-menu-context-copy-post-data",
Example #10
0
/**
 * Create a Menu instance for the webconsole.
 *
 * @param {Object} hud
 *        The webConsoleFrame.
 * @param {Element} parentNode
 *        The container of the new console frontend output wrapper.
 * @param {Object} options
 *        - {String} actor (optional) actor id to use for context menu actions
 *        - {String} clipboardText (optional) text to "Copy" if no selection is available
 *        - {String} variableText (optional) which is the textual frontend
 *            representation of the variable
 *        - {Object} message (optional) message object containing metadata such as:
 *          - {String} source
 *          - {String} request
 *        - {Function} openSidebar (optional) function that will open the object
 *            inspector sidebar
 *        - {String} rootActorId (optional) actor id for the root object being clicked on
 */
function createContextMenu(hud, parentNode, {
  actor,
  clipboardText,
  variableText,
  message,
  serviceContainer,
  openSidebar,
  rootActorId,
}) {
  let win = parentNode.ownerDocument.defaultView;
  let selection = win.getSelection();

  let { source, request } = message || {};

  let menu = new Menu({
    id: "webconsole-menu"
  });

  // Copy URL for a network request.
  menu.append(new MenuItem({
    id: "console-menu-copy-url",
    label: l10n.getStr("webconsole.menu.copyURL.label"),
    accesskey: l10n.getStr("webconsole.menu.copyURL.accesskey"),
    visible: source === MESSAGE_SOURCE.NETWORK,
    click: () => {
      if (!request) {
        return;
      }
      clipboardHelper.copyString(request.url);
    },
  }));

  // Open Network message in the Network panel.
  if (serviceContainer.openNetworkPanel && request) {
    menu.append(new MenuItem({
      id: "console-menu-open-in-network-panel",
      label: l10n.getStr("webconsole.menu.openInNetworkPanel.label"),
      accesskey: l10n.getStr("webconsole.menu.openInNetworkPanel.accesskey"),
      visible: source === MESSAGE_SOURCE.NETWORK,
      click: () => serviceContainer.openNetworkPanel(message.messageId)
    }));
  }

  // Open URL in a new tab for a network request.
  menu.append(new MenuItem({
    id: "console-menu-open-url",
    label: l10n.getStr("webconsole.menu.openURL.label"),
    accesskey: l10n.getStr("webconsole.menu.openURL.accesskey"),
    visible: source === MESSAGE_SOURCE.NETWORK,
    click: () => {
      if (!request) {
        return;
      }
      let mainWindow = Services.wm.getMostRecentWindow(gDevTools.chromeWindowType);
      mainWindow.openWebLinkIn(request.url, "tab", {
        triggeringPrincipal: mainWindow.document.nodePrincipal,
      });
    },
  }));

  // Store as global variable.
  menu.append(new MenuItem({
    id: "console-menu-store",
    label: l10n.getStr("webconsole.menu.storeAsGlobalVar.label"),
    accesskey: l10n.getStr("webconsole.menu.storeAsGlobalVar.accesskey"),
    disabled: !actor,
    click: () => {
      let evalString = `{ let i = 0;
        while (this.hasOwnProperty("temp" + i) && i < 1000) {
          i++;
        }
        this["temp" + i] = _self;
        "temp" + i;
      }`;
      let options = {
        selectedObjectActor: actor,
      };

      hud.jsterm.requestEvaluation(evalString, options).then((res) => {
        hud.jsterm.focus();
        hud.jsterm.setInputValue(res.result);
      });
    },
  }));

  // Copy message or grip.
  menu.append(new MenuItem({
    id: "console-menu-copy",
    label: l10n.getStr("webconsole.menu.copyMessage.label"),
    accesskey: l10n.getStr("webconsole.menu.copyMessage.accesskey"),
    // Disabled if there is no selection and no message element available to copy.
    disabled: selection.isCollapsed && !clipboardText,
    click: () => {
      if (selection.isCollapsed) {
        // If the selection is empty/collapsed, copy the text content of the
        // message for which the context menu was opened.
        clipboardHelper.copyString(clipboardText);
      } else {
        clipboardHelper.copyString(selection.toString());
      }
    },
  }));

  // Copy message object.
  menu.append(new MenuItem({
    id: "console-menu-copy-object",
    label: l10n.getStr("webconsole.menu.copyObject.label"),
    accesskey: l10n.getStr("webconsole.menu.copyObject.accesskey"),
    // Disabled if there is no actor and no variable text associated.
    disabled: (!actor && !variableText),
    click: () => {
      if (actor) {
        // The Debugger.Object of the OA will be bound to |_self| during evaluation,
        hud.jsterm.copyObject(`_self`, { selectedObjectActor: actor }).then((res) => {
          clipboardHelper.copyString(res.helperResult.value);
        });
      } else {
        clipboardHelper.copyString(variableText);
      }
    },
  }));

  // Select all.
  menu.append(new MenuItem({
    id: "console-menu-select",
    label: l10n.getStr("webconsole.menu.selectAll.label"),
    accesskey: l10n.getStr("webconsole.menu.selectAll.accesskey"),
    disabled: false,
    click: () => {
      let webconsoleOutput = parentNode.querySelector(".webconsole-output");
      selection.selectAllChildren(webconsoleOutput);
    },
  }));

  // Open object in sidebar.
  if (openSidebar) {
    menu.append(new MenuItem({
      id: "console-menu-open-sidebar",
      label: l10n.getStr("webconsole.menu.openInSidebar.label"),
      accesskey: l10n.getStr("webconsole.menu.openInSidebar.accesskey"),
      disabled: !rootActorId,
      click: () => openSidebar(message.messageId),
    }));
  }

  return menu;
}
Example #11
0
/**
 * Return an 'edit' menu for a input field. This integrates directly
 * with docshell commands to provide the right enabled state and editor
 * functionality.
 *
 * You'll need to call menu.popup() yourself, this just returns the Menu instance.
 *
 * @returns {Menu}
 */
function createEditContextMenu() {
  const docshell = window.docShell;
  const menu = new Menu({
    id: "webconsole-menu"
  });
  menu.append(new MenuItem({
    id: "editmenu-undo",
    l10nID: "editmenu-undo",
    disabled: !docshell.isCommandEnabled("cmd_undo"),
    click: () => {
      docshell.doCommand("cmd_undo");
    },
  }));
  menu.append(new MenuItem({
    type: "separator"
  }));
  menu.append(new MenuItem({
    id: "editmenu-cut",
    l10nID: "editmenu-cut",
    disabled: !docshell.isCommandEnabled("cmd_cut"),
    click: () => {
      docshell.doCommand("cmd_cut");
    },
  }));
  menu.append(new MenuItem({
    id: "editmenu-copy",
    l10nID: "editmenu-copy",
    disabled: !docshell.isCommandEnabled("cmd_copy"),
    click: () => {
      docshell.doCommand("cmd_copy");
    },
  }));
  menu.append(new MenuItem({
    id: "editmenu-paste",
    l10nID: "editmenu-paste",
    disabled: !docshell.isCommandEnabled("cmd_paste"),
    click: () => {
      docshell.doCommand("cmd_paste");
    },
  }));
  menu.append(new MenuItem({
    id: "editmenu-delete",
    l10nID: "editmenu-delete",
    disabled: !docshell.isCommandEnabled("cmd_delete"),
    click: () => {
      docshell.doCommand("cmd_delete");
    },
  }));
  menu.append(new MenuItem({
    type: "separator"
  }));
  menu.append(new MenuItem({
    id: "editmenu-selectAll",
    l10nID: "editmenu-select-all",
    disabled: !docshell.isCommandEnabled("cmd_selectAll"),
    click: () => {
      docshell.doCommand("cmd_selectAll");
    },
  }));
  return menu;
}
Example #12
0
  _openMenu: function ({ target, screenX = 0, screenY = 0 } = { }) {
    // In the sidebar we do not have this.styleDocument.popupNode
    // so we need to save the node ourselves.
    this.styleDocument.popupNode = target;
    this.styleWindow.focus();

    let menu = new Menu();

    let menuitemCopy = new MenuItem({
      label: STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copy"),
      accesskey: STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copy.accessKey"),
      click: () => {
        this._onCopy();
      },
      disabled: !this._hasTextSelected(),
    });
    let menuitemCopyLocation = new MenuItem({
      label: STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copyLocation"),
      click: () => {
        this._onCopyLocation();
      },
      visible: false,
    });
    let menuitemCopyRule = new MenuItem({
      label: STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copyRule"),
      click: () => {
        this._onCopyRule();
      },
      visible: this.isRuleView,
    });
    let copyColorAccessKey = "styleinspector.contextmenu.copyColor.accessKey";
    let menuitemCopyColor = new MenuItem({
      label: STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copyColor"),
      accesskey: STYLE_INSPECTOR_L10N.getStr(copyColorAccessKey),
      click: () => {
        this._onCopyColor();
      },
      visible: this._isColorPopup(),
    });
    let copyUrlAccessKey = "styleinspector.contextmenu.copyUrl.accessKey";
    let menuitemCopyUrl = new MenuItem({
      label: STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copyUrl"),
      accesskey: STYLE_INSPECTOR_L10N.getStr(copyUrlAccessKey),
      click: () => {
        this._onCopyUrl();
      },
      visible: this._isImageUrl(),
    });
    let copyImageAccessKey = "styleinspector.contextmenu.copyImageDataUrl.accessKey";
    let menuitemCopyImageDataUrl = new MenuItem({
      label: STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copyImageDataUrl"),
      accesskey: STYLE_INSPECTOR_L10N.getStr(copyImageAccessKey),
      click: () => {
        this._onCopyImageDataUrl();
      },
      visible: this._isImageUrl(),
    });
    let copyPropDeclarationLabel = "styleinspector.contextmenu.copyPropertyDeclaration";
    let menuitemCopyPropertyDeclaration = new MenuItem({
      label: STYLE_INSPECTOR_L10N.getStr(copyPropDeclarationLabel),
      click: () => {
        this._onCopyPropertyDeclaration();
      },
      visible: false,
    });
    let menuitemCopyPropertyName = new MenuItem({
      label: STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copyPropertyName"),
      click: () => {
        this._onCopyPropertyName();
      },
      visible: false,
    });
    let menuitemCopyPropertyValue = new MenuItem({
      label: STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copyPropertyValue"),
      click: () => {
        this._onCopyPropertyValue();
      },
      visible: false,
    });
    let menuitemCopySelector = new MenuItem({
      label: STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.copySelector"),
      click: () => {
        this._onCopySelector();
      },
      visible: false,
    });

    this._clickedNodeInfo = this._getClickedNodeInfo();
    if (this.isRuleView && this._clickedNodeInfo) {
      switch (this._clickedNodeInfo.type) {
        case VIEW_NODE_PROPERTY_TYPE :
          menuitemCopyPropertyDeclaration.visible = true;
          menuitemCopyPropertyName.visible = true;
          break;
        case VIEW_NODE_VALUE_TYPE :
          menuitemCopyPropertyDeclaration.visible = true;
          menuitemCopyPropertyValue.visible = true;
          break;
        case VIEW_NODE_SELECTOR_TYPE :
          menuitemCopySelector.visible = true;
          break;
        case VIEW_NODE_LOCATION_TYPE :
          menuitemCopyLocation.visible = true;
          break;
      }
    }

    menu.append(menuitemCopy);
    menu.append(menuitemCopyLocation);
    menu.append(menuitemCopyRule);
    menu.append(menuitemCopyColor);
    menu.append(menuitemCopyUrl);
    menu.append(menuitemCopyImageDataUrl);
    menu.append(menuitemCopyPropertyDeclaration);
    menu.append(menuitemCopyPropertyName);
    menu.append(menuitemCopyPropertyValue);
    menu.append(menuitemCopySelector);

    menu.append(new MenuItem({
      type: "separator",
    }));

    // Select All
    let selectAllAccessKey = "styleinspector.contextmenu.selectAll.accessKey";
    let menuitemSelectAll = new MenuItem({
      label: STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.selectAll"),
      accesskey: STYLE_INSPECTOR_L10N.getStr(selectAllAccessKey),
      click: () => {
        this._onSelectAll();
      },
    });
    menu.append(menuitemSelectAll);

    menu.append(new MenuItem({
      type: "separator",
    }));

    // Add new rule
    let addRuleAccessKey = "styleinspector.contextmenu.addNewRule.accessKey";
    let menuitemAddRule = new MenuItem({
      label: STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.addNewRule"),
      accesskey: STYLE_INSPECTOR_L10N.getStr(addRuleAccessKey),
      click: () => {
        this._onAddNewRule();
      },
      visible: this.isRuleView,
      disabled: !this.isRuleView ||
                this.inspector.selection.isAnonymousNode(),
    });
    menu.append(menuitemAddRule);

    // Show MDN Docs
    let mdnDocsAccessKey = "styleinspector.contextmenu.showMdnDocs.accessKey";
    let menuitemShowMdnDocs = new MenuItem({
      label: STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.showMdnDocs"),
      accesskey: STYLE_INSPECTOR_L10N.getStr(mdnDocsAccessKey),
      click: () => {
        this._onShowMdnDocs();
      },
      visible: (Services.prefs.getBoolPref(PREF_ENABLE_MDN_DOCS_TOOLTIP) &&
                                                    this._isPropertyName()),
    });
    menu.append(menuitemShowMdnDocs);

    // Show Original Sources
    let sourcesAccessKey = "styleinspector.contextmenu.toggleOrigSources.accessKey";
    let menuitemSources = new MenuItem({
      label: STYLE_INSPECTOR_L10N.getStr("styleinspector.contextmenu.toggleOrigSources"),
      accesskey: STYLE_INSPECTOR_L10N.getStr(sourcesAccessKey),
      click: () => {
        this._onToggleOrigSources();
      },
      type: "checkbox",
      checked: Services.prefs.getBoolPref(PREF_ORIG_SOURCES),
    });
    menu.append(menuitemSources);

    menu.popup(screenX, screenY, this.inspector._toolbox);
    return menu;
  },
Example #13
0
/**
 * Create a Menu instance for the webconsole.
 *
 * @param {WebConsoleUI} webConsoleUI
 *        The webConsoleUI instance.
 * @param {Element} parentNode
 *        The container of the new console frontend output wrapper.
 * @param {Object} options
 *        - {String} actor (optional) actor id to use for context menu actions
 *        - {String} clipboardText (optional) text to "Copy" if no selection is available
 *        - {String} variableText (optional) which is the textual frontend
 *            representation of the variable
 *        - {Object} message (optional) message object containing metadata such as:
 *          - {String} source
 *          - {String} request
 *        - {Function} openSidebar (optional) function that will open the object
 *            inspector sidebar
 *        - {String} rootActorId (optional) actor id for the root object being clicked on
 *        - {Object} executionPoint (optional) when replaying, the execution point where
 *            this message was logged
 */
function createContextMenu(webConsoleUI, parentNode, {
  actor,
  clipboardText,
  variableText,
  message,
  serviceContainer,
  openSidebar,
  rootActorId,
  executionPoint,
  toolbox,
  url,
}) {
  const win = parentNode.ownerDocument.defaultView;
  const selection = win.getSelection();

  const { source, request } = message || {};

  const menu = new Menu({
    id: "webconsole-menu",
  });

  // Copy URL for a network request.
  menu.append(new MenuItem({
    id: "console-menu-copy-url",
    label: l10n.getStr("webconsole.menu.copyURL.label"),
    accesskey: l10n.getStr("webconsole.menu.copyURL.accesskey"),
    visible: source === MESSAGE_SOURCE.NETWORK,
    click: () => {
      if (!request) {
        return;
      }
      clipboardHelper.copyString(request.url);
    },
  }));

  // Open Network message in the Network panel.
  if (serviceContainer.openNetworkPanel && request) {
    menu.append(new MenuItem({
      id: "console-menu-open-in-network-panel",
      label: l10n.getStr("webconsole.menu.openInNetworkPanel.label"),
      accesskey: l10n.getStr("webconsole.menu.openInNetworkPanel.accesskey"),
      visible: source === MESSAGE_SOURCE.NETWORK,
      click: () => serviceContainer.openNetworkPanel(message.messageId),
    }));
  }

  // Resend Network message.
  if (serviceContainer.resendNetworkRequest && request) {
    menu.append(new MenuItem({
      id: "console-menu-resend-network-request",
      label: l10n.getStr("webconsole.menu.resendNetworkRequest.label"),
      accesskey: l10n.getStr("webconsole.menu.resendNetworkRequest.accesskey"),
      visible: source === MESSAGE_SOURCE.NETWORK,
      click: () => serviceContainer.resendNetworkRequest(message.messageId),
    }));
  }

  // Open URL in a new tab for a network request.
  menu.append(new MenuItem({
    id: "console-menu-open-url",
    label: l10n.getStr("webconsole.menu.openURL.label"),
    accesskey: l10n.getStr("webconsole.menu.openURL.accesskey"),
    visible: source === MESSAGE_SOURCE.NETWORK,
    click: () => {
      if (!request) {
        return;
      }
      openContentLink(request.url);
    },
  }));

  // Store as global variable.
  menu.append(new MenuItem({
    id: "console-menu-store",
    label: l10n.getStr("webconsole.menu.storeAsGlobalVar.label"),
    accesskey: l10n.getStr("webconsole.menu.storeAsGlobalVar.accesskey"),
    disabled: !actor,
    click: () => {
      const evalString = `{ let i = 0;
        while (this.hasOwnProperty("temp" + i) && i < 1000) {
          i++;
        }
        this["temp" + i] = _self;
        "temp" + i;
      }`;
      const options = {
        selectedObjectActor: actor,
      };

      webConsoleUI.jsterm.requestEvaluation(evalString, options).then((res) => {
        webConsoleUI.jsterm.focus();
        webConsoleUI.hud.setInputValue(res.result);
      });
    },
  }));

  // Copy message or grip.
  menu.append(new MenuItem({
    id: "console-menu-copy",
    label: l10n.getStr("webconsole.menu.copyMessage.label"),
    accesskey: l10n.getStr("webconsole.menu.copyMessage.accesskey"),
    // Disabled if there is no selection and no message element available to copy.
    disabled: selection.isCollapsed && !clipboardText,
    click: () => {
      if (selection.isCollapsed) {
        // If the selection is empty/collapsed, copy the text content of the
        // message for which the context menu was opened.
        clipboardHelper.copyString(clipboardText);
      } else {
        clipboardHelper.copyString(selection.toString());
      }
    },
  }));

  // Copy message object.
  menu.append(new MenuItem({
    id: "console-menu-copy-object",
    label: l10n.getStr("webconsole.menu.copyObject.label"),
    accesskey: l10n.getStr("webconsole.menu.copyObject.accesskey"),
    // Disabled if there is no actor and no variable text associated.
    disabled: (!actor && !variableText),
    click: () => {
      if (actor) {
        // The Debugger.Object of the OA will be bound to |_self| during evaluation,
        webConsoleUI.jsterm.copyObject(`_self`, { selectedObjectActor: actor })
          .then((res) => {
            clipboardHelper.copyString(res.helperResult.value);
          });
      } else {
        clipboardHelper.copyString(variableText);
      }
    },
  }));

  // Select all.
  menu.append(new MenuItem({
    id: "console-menu-select",
    label: l10n.getStr("webconsole.menu.selectAll.label"),
    accesskey: l10n.getStr("webconsole.menu.selectAll.accesskey"),
    disabled: false,
    click: () => {
      const webconsoleOutput = parentNode.querySelector(".webconsole-output");
      selection.selectAllChildren(webconsoleOutput);
    },
  }));

  // Export to clipboard
  menu.append(new MenuItem({
    id: "console-menu-export-clipboard",
    label: l10n.getStr("webconsole.menu.exportClipboard.label"),
    disabled: false,
    click: () => {
      const webconsoleOutput = parentNode.querySelector(".webconsole-output");
      clipboardHelper.copyString(getElementText(webconsoleOutput));
    },
  }));

  // Open object in sidebar.
  if (openSidebar) {
    menu.append(new MenuItem({
      id: "console-menu-open-sidebar",
      label: l10n.getStr("webconsole.menu.openInSidebar.label"),
      accesskey: l10n.getStr("webconsole.menu.openInSidebar.accesskey"),
      disabled: !rootActorId,
      click: () => openSidebar(message.messageId),
    }));
  }

  // Add time warp option if available.
  if (executionPoint) {
    menu.append(new MenuItem({
      id: "console-menu-time-warp",
      label: l10n.getStr("webconsole.menu.timeWarp.label"),
      disabled: false,
      click: () => {
        const threadClient = toolbox.threadClient;
        threadClient.timeWarp(executionPoint);
      },
    }));
  }

  if (url) {
    menu.append(new MenuItem({
      id: "console-menu-copy-url",
      label: l10n.getStr("webconsole.menu.copyURL.label"),
      accesskey: l10n.getStr("webconsole.menu.copyURL.accesskey"),
      click: () => clipboardHelper.copyString(url),
    }));
  }

  return menu;
}
Example #14
0
/**
 * Return an 'edit' menu for a input field. This integrates directly
 * with docshell commands to provide the right enabled state and editor
 * functionality.
 *
 * You'll need to call menu.popup() yourself, this just returns the Menu instance.
 *
 * @param {Window} win parent window reference
 * @param {String} id menu ID
 *
 * @returns {Menu}
 */
function createEditContextMenu(win, id) {
  // Localized strings for the menu are loaded lazily.
  loadEditMenuStrings(win);

  const docshell = win.docShell;
  const menu = new Menu({id});
  menu.append(new MenuItem({
    id: "editmenu-undo",
    l10nID: "editmenu-undo",
    disabled: !docshell.isCommandEnabled("cmd_undo"),
    click: () => {
      docshell.doCommand("cmd_undo");
    },
  }));
  menu.append(new MenuItem({
    type: "separator",
  }));
  menu.append(new MenuItem({
    id: "editmenu-cut",
    l10nID: "editmenu-cut",
    disabled: !docshell.isCommandEnabled("cmd_cut"),
    click: () => {
      docshell.doCommand("cmd_cut");
    },
  }));
  menu.append(new MenuItem({
    id: "editmenu-copy",
    l10nID: "editmenu-copy",
    disabled: !docshell.isCommandEnabled("cmd_copy"),
    click: () => {
      docshell.doCommand("cmd_copy");
    },
  }));
  menu.append(new MenuItem({
    id: "editmenu-paste",
    l10nID: "editmenu-paste",
    disabled: !docshell.isCommandEnabled("cmd_paste"),
    click: () => {
      docshell.doCommand("cmd_paste");
    },
  }));
  menu.append(new MenuItem({
    id: "editmenu-delete",
    l10nID: "editmenu-delete",
    disabled: !docshell.isCommandEnabled("cmd_delete"),
    click: () => {
      docshell.doCommand("cmd_delete");
    },
  }));
  menu.append(new MenuItem({
    type: "separator",
  }));
  menu.append(new MenuItem({
    id: "editmenu-selectAll",
    l10nID: "editmenu-select-all",
    disabled: !docshell.isCommandEnabled("cmd_selectAll"),
    click: () => {
      docshell.doCommand("cmd_selectAll");
    },
  }));
  return menu;
}
Example #15
0
function* testMenuPopup(toolbox) {
  let clickFired = false;

  let menu = new Menu({
    id: "menu-popup",
  });
  menu.append(new MenuItem({ type: "separator" }));

  let MENU_ITEMS = [
    new MenuItem({
      id: "menu-item-1",
      label: "Normal Item",
      click: () => {
        info("Click callback has fired for menu item");
        clickFired = true;
      },
    }),
    new MenuItem({
      label: "Checked Item",
      type: "checkbox",
      checked: true,
    }),
    new MenuItem({
      label: "Radio Item",
      type: "radio",
    }),
    new MenuItem({
      label: "Disabled Item",
      disabled: true,
    }),
  ];

  for (let item of MENU_ITEMS) {
    menu.append(item);
  }

  menu.popup(0, 0, toolbox);

  ok(toolbox.doc.querySelector("#menu-popup"), "A popup is in the DOM");

  let menuSeparators = toolbox.doc.querySelectorAll("#menu-popup > menuseparator");
  is(menuSeparators.length, 1, "A separator is in the menu");

  let menuItems = toolbox.doc.querySelectorAll("#menu-popup > menuitem");
  is(menuItems.length, MENU_ITEMS.length, "Correct number of menuitems");

  is(menuItems[0].id, MENU_ITEMS[0].id, "Correct id for menuitem");
  is(menuItems[0].getAttribute("label"), MENU_ITEMS[0].label, "Correct label");

  is(menuItems[1].getAttribute("label"), MENU_ITEMS[1].label, "Correct label");
  is(menuItems[1].getAttribute("type"), "checkbox", "Correct type attribute");
  is(menuItems[1].getAttribute("checked"), "true", "Has checked attribute");

  is(menuItems[2].getAttribute("label"), MENU_ITEMS[2].label, "Correct label");
  is(menuItems[2].getAttribute("type"), "radio", "Correct type attribute");
  ok(!menuItems[2].hasAttribute("checked"), "Doesn't have checked attribute");

  is(menuItems[3].getAttribute("label"), MENU_ITEMS[3].label, "Correct label");
  is(menuItems[3].getAttribute("disabled"), "true", "disabled attribute menuitem");

  yield once(menu, "open");
  let closed = once(menu, "close");
  EventUtils.synthesizeMouseAtCenter(menuItems[0], {}, toolbox.doc.defaultView);
  yield closed;
  ok(clickFired, "Click has fired");

  ok(!toolbox.doc.querySelector("#menu-popup"), "The popup is removed from the DOM");
}
Example #16
0
/**
 * Create a Menu instance for the webconsole.
 *
 * @param {Object} jsterm
 *        The JSTerm instance used by the webconsole.
 * @param {Element} parentNode
 *        The container of the new console frontend output wrapper.
 * @param {Object} options
 *        - {String} actor (optional) actor id to use for context menu actions
 *        - {String} clipboardText (optional) text to "Copy" if no selection is available
 *        - {Object} message (optional) message object containing metadata such as:
 *          - {String} source
 *          - {String} request
 */
function createContextMenu(jsterm, parentNode, { actor, clipboardText, message }) {
  let win = parentNode.ownerDocument.defaultView;
  let selection = win.getSelection();

  let { source, request } = message || {};

  let menu = new Menu({
    id: "webconsole-menu"
  });

  // Copy URL for a network request.
  menu.append(new MenuItem({
    id: "console-menu-copy-url",
    label: l10n.getStr("webconsole.menu.copyURL.label"),
    accesskey: l10n.getStr("webconsole.menu.copyURL.accesskey"),
    visible: source === MESSAGE_SOURCE.NETWORK,
    click: () => {
      if (!request) {
        return;
      }
      clipboardHelper.copyString(request.url);
    },
  }));

  // Open URL in a new tab for a network request.
  menu.append(new MenuItem({
    id: "console-menu-open-url",
    label: l10n.getStr("webconsole.menu.openURL.label"),
    accesskey: l10n.getStr("webconsole.menu.openURL.accesskey"),
    visible: source === MESSAGE_SOURCE.NETWORK,
    click: () => {
      if (!request) {
        return;
      }
      let mainWindow = Services.wm.getMostRecentWindow(gDevTools.chromeWindowType);
      mainWindow.openUILinkIn(request.url, "tab");
    },
  }));

  // Open in variables view.
  menu.append(new MenuItem({
    id: "console-menu-open",
    label: l10n.getStr("webconsole.menu.openInVarView.label"),
    accesskey: l10n.getStr("webconsole.menu.openInVarView.accesskey"),
    disabled: !actor,
    click: () => {
      openVariablesView(actor);
    },
  }));

  // Store as global variable.
  menu.append(new MenuItem({
    id: "console-menu-store",
    label: l10n.getStr("webconsole.menu.storeAsGlobalVar.label"),
    accesskey: l10n.getStr("webconsole.menu.storeAsGlobalVar.accesskey"),
    disabled: !actor,
    click: () => {
      let evalString = `{ let i = 0;
        while (this.hasOwnProperty("temp" + i) && i < 1000) {
          i++;
        }
        this["temp" + i] = _self;
        "temp" + i;
      }`;
      let options = {
        selectedObjectActor: actor,
      };

      jsterm.requestEvaluation(evalString, options).then((res) => {
        jsterm.focus();
        jsterm.setInputValue(res.result);
      });
    },
  }));

  // Copy message or grip.
  menu.append(new MenuItem({
    id: "console-menu-copy",
    label: l10n.getStr("webconsole.menu.copy.label"),
    accesskey: l10n.getStr("webconsole.menu.copy.accesskey"),
    // Disabled if there is no selection and no message element available to copy.
    disabled: selection.isCollapsed && !clipboardText,
    click: () => {
      if (selection.isCollapsed) {
        // If the selection is empty/collapsed, copy the text content of the
        // message for which the context menu was opened.
        clipboardHelper.copyString(clipboardText);
      } else {
        clipboardHelper.copyString(selection.toString());
      }
    },
  }));

  // Select all.
  menu.append(new MenuItem({
    id: "console-menu-select",
    label: l10n.getStr("webconsole.menu.selectAll.label"),
    accesskey: l10n.getStr("webconsole.menu.selectAll.accesskey"),
    disabled: false,
    click: () => {
      let webconsoleOutput = parentNode.querySelector(".webconsole-output");
      selection.selectAllChildren(webconsoleOutput);
    },
  }));

  return menu;
}