Showing a menupopup in multiple places

Sometimes in an extension you want to show the same menupopup in multiple places. Some users like status bar icons, some like using things under Tools, some like a toolbar button. (For the love of god, don’t put it everywhere by default! Put in some sensible defaults and rely on prefs or user styles for customizability.)

To implement this, you could include the menupopup XUL in every place, but then you’re just repeating yourself. You could write some JavaScript to generate the menu, but that’s very verbose and difficult to maintain.

What I do is write the XUL in one place, then clone the contents whenever needed to the other places.

<menupopup id="primary-popup">
  <!--menu items here-->
</menupopup>
<menupopup id="secondary-popup"
           onpopupshowing="generatePopup(event)"
           onpopuphiding="clearMenu(event)">
  <!--menu items here-->
</menupopup>
function generatePopup(event) {
  //copy the stuff from the primary popup
  var primary = document.getElementById("main-popup");
  for (var i = 0; i < primary.childNodes.length; i++) {
    popup.appendChild(primary.childNodes[i].cloneNode(true));
  }
}

function clearMenu(event) {
  var popup = event.target;
  while (popup.hasChildNodes()) {
    popup.removeChild(popup.firstChild);
  }
}

A couple caveats: event listeners don’t get cloned, so if you used addEventListener rather than an on… attribute, you’ll either have to switch or regenerate the event listeners every time. Also, if you have ids defined on the menupopup’s children, you’ll be in a situation where you have multiple elements with the same id, so beware if you use getElementById subsequently (this is why I like to clear the menu when it closes - to keep the multiple id situation as short-lived as possible).

If you already do something onpopupshowing, you’ll can include the code from generatePopup in your function; you just don’t run it if event.target.id == “main-popup”.

Props to the WordPress plugin Code Autoescape and the “Disable WYSIWYG Editor” option for making this post happen.

2 Responses to “Showing a menupopup in multiple places”

  1. Tucana Says:

    Hello!
    Very good workaround! Proably I will use it :)

    I want to show a complete menu (according to prefs) in the Main Menu Bar, as a submenu in the Tools Menu and as a submenu in the Context Menu.
    I have tried in many different manner to do this with dinamically loaded or explicitly loaded overlays but with no results.
    The menu is showed in all places but the content is present only in one of the three menu.

    I have see this example on MDC: http://developer.mozilla.org/en/docs/XUL_Overlays#UI_Reuse_with_Overlays

    You think that is possible to use it in this case?
    If not, is due to unique ID’s problem?

  2. jason Says:

    Tucana, you’re indeed right that it’s due to a unique ID problem. I believe that that article is referring to reusing UI in multiple documents, not to reusing UI multiple times in a single document.

Leave a Reply

Adventures in development - Web standards and Firefox extensions