Bug 1466897 - Support devtools context menus in top level HTML pages. r=bgrins draft
authorBrendan Dahl <brendan.dahl@gmail.com>
Wed, 06 Jun 2018 14:55:23 -0700
changeset 808285 85c6f89f0921d4cf6c5f1331ad6f3c916255092f
parent 808284 f728f117000053826a21d36b113796d65c19edc8
push id113340
push userbmo:bdahl@mozilla.com
push dateTue, 19 Jun 2018 01:11:57 +0000
reviewersbgrins
bugs1466897
milestone62.0a1
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>
devtools/client/framework/menu.js
--- 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 Services = require("Services");
 const EventEmitter = require("devtools/shared/event-emitter");
 
 /**
  * A partial implementation of the Menu API provided by electron:
  * https://github.com/electron/electron/blob/master/docs/api/menu.md.
  *
  * Extra features:
@@ -78,27 +79,41 @@ 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");
+
+  if (doc.documentElement.namespaceURI !== XUL_NS) {
+    let popupgroup = doc.querySelector("popupgroup");
+    if (!popupgroup) {
+      popupgroup = doc.createElementNS(XUL_NS, "popupgroup");
+      doc.documentElement.appendChild(popupgroup);
+    }
+  }
+
+  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);
 
@@ -123,40 +138,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();
       });