Bug 1215376 - Always use old contextData upon refresh draft
authorRob Wu <rob@robwu.nl>
Thu, 14 Sep 2017 02:11:29 +0200
changeset 670562 59f9eda63c3d81534abe0558f4a90e634d2e967f
parent 666895 e193167e7fe99c3e7a296f569072a5ce68eb9d8e
child 670563 ad3206237adc93d3eba1b0c69d53ad57fd0bed8b
push id81676
push userbmo:rob@robwu.nl
push dateTue, 26 Sep 2017 17:26:42 +0000
bugs1215376
milestone57.0a1
Bug 1215376 - Always use old contextData upon refresh MozReview-Commit-ID: K1wfFCYpMqB
browser/components/extensions/ext-menus.js
browser/components/extensions/test/browser/browser_ext_menus_refresh.js
--- a/browser/components/extensions/ext-menus.js
+++ b/browser/components/extensions/ext-menus.js
@@ -58,19 +58,16 @@ var gMenuBuilder = {
     }
     this.afterBuildingMenu(contextData);
   },
 
   // Builds a context menu for browserAction and pageAction buttons.
   buildActionContextMenu(contextData) {
     const {menu} = contextData;
 
-    contextData.tab = tabTracker.activeTab;
-    contextData.pageUrl = contextData.tab.linkedBrowser.currentURI.spec;
-
     const root = gRootItems.get(contextData.extension);
     if (!root) {
       return;
     }
 
     const children = this.buildChildren(root, contextData);
     const visible = children.slice(0, ACTION_MENU_TOP_LEVEL_LIMIT);
 
@@ -406,16 +403,18 @@ var gMenuBuilder = {
     gShownMenuItems.clear();
   },
 
   itemsToCleanUp: new Set(),
 };
 
 // Called from pageAction or browserAction popup.
 global.actionContextMenu = function(contextData) {
+  contextData.tab = tabTracker.activeTab;
+  contextData.pageUrl = contextData.tab.linkedBrowser.currentURI.spec;
   gMenuBuilder.buildActionContextMenu(contextData);
 };
 
 const contextsMap = {
   onAudio: "audio",
   onEditableArea: "editable",
   inFrame: "frame",
   onImage: "image",
--- a/browser/components/extensions/test/browser/browser_ext_menus_refresh.js
+++ b/browser/components/extensions/test/browser/browser_ext_menus_refresh.js
@@ -283,8 +283,67 @@ add_task(async function refresh_menus_wi
   is(elem.getAttribute("label"), "visible menu item", "extension menu shown");
   elem = other_extension.getXULElementByMenuId("action_item");
   is(elem, null, "other extension's menu should be hidden");
 
   await closeActionContextMenu();
   await extension.unload();
   await other_extension.unload();
 });
+
+add_task(async function refresh_menus_during_navigation() {
+  const tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE + "?1");
+  let extension = loadExtensionWithMenusApi();
+  await extension.startup();
+
+  await extension.callMenuApi("create", {
+    id: "item1",
+    title: "item1",
+    contexts: ["browser_action"],
+    documentUrlPatterns: ["*://*/*?1*"],
+  });
+
+  await extension.callMenuApi("create", {
+    id: "item2",
+    title: "item2",
+    contexts: ["browser_action"],
+    documentUrlPatterns: ["*://*/*?2*"],
+  });
+
+  await openActionContextMenu(extension, "browser");
+  await extension.awaitMessage("onShown fired");
+
+  let elem = extension.getXULElementByMenuId("item1");
+  is(elem.getAttribute("label"), "item1", "menu item 1 should be shown");
+  elem = extension.getXULElementByMenuId("item2");
+  is(elem, null, "menu item 2 should be hidden");
+
+  await BrowserTestUtils.loadURI(tab.linkedBrowser, PAGE + "?2");
+  await BrowserTestUtils.browserStopped(tab.linkedBrowser);
+
+  await extension.callMenuApi("refresh");
+
+  // The menu items in a context menu are based on the context at the time of
+  // opening the menu. Menus are not updated if the context changes, e.g. as a
+  // result of navigation events after the menu was shown.
+  // So when refresh() is called during the onShown event, then the original
+  // URL (before navigation) should be used to determine whether to show a
+  // URL-specific menu item, and NOT the current URL (after navigation).
+  elem = extension.getXULElementByMenuId("item1");
+  is(elem.getAttribute("label"), "item1", "menu item 1 should still be shown");
+  elem = extension.getXULElementByMenuId("item2");
+  is(elem, null, "menu item 2 should still be hidden");
+
+  await closeActionContextMenu();
+  await openActionContextMenu(extension, "browser");
+  await extension.awaitMessage("onShown fired");
+
+  // Now after closing and re-opening the menu, the latest contextual info
+  // should be used.
+  elem = extension.getXULElementByMenuId("item1");
+  is(elem, null, "menu item 1 should be hidden");
+  elem = extension.getXULElementByMenuId("item2");
+  is(elem.getAttribute("label"), "item2", "menu item 2 should be shown");
+
+  await closeActionContextMenu();
+  await extension.unload();
+  await BrowserTestUtils.removeTab(tab);
+});