Bug 1466897 - Support devtools context menus in top level HTML pages. r=bgrins
Create a popugroup element to setup the context menu behind the scenes.
Create all the menu related elements with the XUL namespace.
MozReview-Commit-ID: DI24aNHHFON
Signed-off-by: Brendan Dahl <brendan.dahl@gmail.com>
--- a/devtools/client/framework/menu.js
+++ b/devtools/client/framework/menu.js
@@ -1,16 +1,17 @@
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
+const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
const EventEmitter = require("devtools/shared/event-emitter");
const { getCurrentZoom } = require("devtools/shared/layout/utils");
/**
* A partial implementation of the Menu API provided by electron:
* https://github.com/electron/electron/blob/master/docs/api/menu.md.
*
* Extra features:
@@ -75,27 +76,32 @@ Menu.prototype.popupWithZoom = function(
*
* @param {int} screenX
* @param {int} screenY
* @param Toolbox toolbox (non standard)
* Needed so we in which window to inject XUL
*/
Menu.prototype.popup = function(screenX, screenY, toolbox) {
const doc = toolbox.doc;
- const popupset = doc.querySelector("popupset");
+
+ let popupset = doc.querySelector("popupset");
+ if (!popupset) {
+ popupset = doc.createElementNS(XUL_NS, "popupset");
+ doc.documentElement.appendChild(popupset);
+ }
// See bug 1285229, on Windows, opening the same popup multiple times in a
// row ends up duplicating the popup. The newly inserted popup doesn't
// dismiss the old one. So remove any previously displayed popup before
// opening a new one.
let popup = popupset.querySelector("menupopup[menu-api=\"true\"]");
if (popup) {
popup.hidePopup();
}
- popup = doc.createElement("menupopup");
+ popup = doc.createElementNS(XUL_NS, "menupopup");
popup.setAttribute("menu-api", "true");
popup.setAttribute("consumeoutsideclicks", "true");
if (this.id) {
popup.id = this.id;
}
this._createMenuItems(popup);
@@ -120,40 +126,40 @@ Menu.prototype.popup = function(screenX,
Menu.prototype._createMenuItems = function(parent) {
const doc = parent.ownerDocument;
this.menuitems.forEach(item => {
if (!item.visible) {
return;
}
if (item.submenu) {
- const menupopup = doc.createElement("menupopup");
+ const menupopup = doc.createElementNS(XUL_NS, "menupopup");
item.submenu._createMenuItems(menupopup);
- const menu = doc.createElement("menu");
+ const menu = doc.createElementNS(XUL_NS, "menu");
menu.appendChild(menupopup);
menu.setAttribute("label", item.label);
if (item.disabled) {
menu.setAttribute("disabled", "true");
}
if (item.accelerator) {
menu.setAttribute("acceltext", item.accelerator);
}
if (item.accesskey) {
menu.setAttribute("accesskey", item.accesskey);
}
if (item.id) {
menu.id = item.id;
}
parent.appendChild(menu);
} else if (item.type === "separator") {
- const menusep = doc.createElement("menuseparator");
+ const menusep = doc.createElementNS(XUL_NS, "menuseparator");
parent.appendChild(menusep);
} else {
- const menuitem = doc.createElement("menuitem");
+ const menuitem = doc.createElementNS(XUL_NS, "menuitem");
menuitem.setAttribute("label", item.label);
menuitem.addEventListener("command", () => {
item.click();
});
menuitem.addEventListener("DOMMenuItemActive", () => {
item.hover();
});