在FireFox扩展中动态插入新菜单

时间:2013-09-04 20:49:38

标签: javascript firefox-addon

我正在尝试使用我的扩展程序在主菜单栏上插入一个新菜单。我知道如何使用XUL覆盖,但它需要通过JavaScript插入。此代码应该创建一个名为“New”的新菜单,其中包含一个“New Tab”选项。 alert(doc);显示[object XMLDocument],但我的新菜单不会显示。

var xmlString = '<menu id="new-menu" label="New" accesskey="N">'+
      '<menupopup id="menu_NewPopup">'+
      '<menuitem id="menu_newNavigatorTab" label="New Tab" command="cmd_newNavigatorTab" key="key_newNavigatorTab" accesskey="T"/>'+
      '</menupopup>'+
      '</menu>';

var parser = new DOMParser();
var doc = parser.parseFromString(xmlString, "text/xml");
document.getElementById('main-menubar').appendChild(doc);

1 个答案:

答案 0 :(得分:2)

使用常规DOM API。

首先,找出正确的父节点。在browser.xul通常是以下之一:

  • #mainPopupSet - 全新菜单
  • #menu_ToolsPopup - 工具菜单
  • #contentAreaContextMenu - 内容的主要上下文菜单

对于其他菜单自己追踪ID(例如使用DOM检查器,或者阅读chrome://browser/content/browser.xul source)。在你自己的窗户里,无论如何你最了解自己。

然后你可以动态构建你的菜单,比如

var parent = document.getElementById("<parent from step 1>");
var menu = document.createElement("menu"); // in a XUL window, the XUL namespace is already implied.
menu.setAttribute("id", "my-extension-menu"); // Use sane names that are unlikely to clash with other ids in the window.
menu.setAttribute("label", "My Item");

var item = document.createElement("menuitem");
item.setAttribute("label", "My Item");
item.addEventListener("command", function item_click(e) {
  alert("clicked");
}, false);

menu.appendChild(item);
parent.appendChild(menu); // Or insertBefore()

在XUL叠加层中常常会对popupshowing事件做出反应,只根据需要构建/更新菜单。还有一个popuphidden事件。

document.getElementById("contentAreaContextMenu")
  .addEventListener("popupshowing", function construct_or_update(e) {

  // Construct menu, if first time, else update as necessary
}, true);

这通常与存根叠加结合使用:

<!-- ... xml preamble, doctype, etc. -->
<overlay id="my-extension-overlay">
  <popup id="contentAreaContextMenu">
    <menu id="my-extension-menu">
      <menupopup id="my-extension-menupopup"/>
    </menu>
  </popup>
</overlay>

然后有类似的东西:

document.getElementById("my-extension-menu")
  .addEventListener("popupshowing", function construct_or_update(e) {

   var mp = document.getElementById("my-extension-menupopup");
   // Remove cruft from last time.
   while (mp.lastChild) {
     mp.removeChild(mp.lastChild);
   }
   // Create new menu items
}, true);

如果您只有一组静态菜单项,并且您希望根据上下文或其他内容显示或隐藏您的项目,只需在元素上设置.hidden属性即可。这比一次又一次构建整个子DOM更有效。

document.getElementById("contentAreaContextMenu")
  .addEventListener("popupshowing", function update_menuitems(e) {

  var item = document.getElementById("my-extension-item");
  item.hidden = someCondition;
}, true);

PS :请勿使用DOMParser。如果您真的觉得必须这样做,请将其放在文件中XMLHttpRequest.responseXML。然后,您可以根据需要.importNode().appendChild() / .insertBefore()。但是,如果您可以使用叠加层,则不建议这样做。但是,它可能适用于无法使用叠加层的自举(无重启)扩展。

不要从字符串构造DOM片段,特别是不要从动态连接在一起的字符串构造片段。