Bug 1302742 - Add keyboard modifiers to contextMenus ClickInfo
MozReview-Commit-ID: K4YnQdH5uOO
--- a/browser/components/extensions/ext-contextMenus.js
+++ b/browser/components/extensions/ext-contextMenus.js
@@ -1,16 +1,17 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
Cu.import("resource://gre/modules/ExtensionUtils.jsm");
Cu.import("resource://gre/modules/MatchPattern.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/AppConstants.jsm");
var {
ExtensionError,
IconDetails,
SingletonEventManager,
} = ExtensionUtils;
const ACTION_MENU_TOP_LEVEL_LIMIT = 6;
@@ -227,16 +228,23 @@ var gMenuBuilder = {
// Select the clicked radio item.
item.checked = true;
}
item.tabManager.addActiveTabPermission();
let tab = item.tabManager.convert(contextData.tab);
let info = item.getClickInfo(contextData, wasChecked);
+
+ const map = {shiftKey: "Shift", altKey: "Alt", metaKey: "Command", ctrlKey: "Ctrl"};
+ info.modifiers = Object.keys(map).filter(key => event[key]).map(key => map[key]);
+ if (event.ctrlKey && AppConstants.platform === "macosx") {
+ info.modifiers.push("MacCtrl");
+ }
+
item.extension.emit("webext-contextmenu-menuitem-click", info, tab);
});
return element;
},
handleEvent(event) {
if (this.xulMenu != event.target || event.type != "popuphidden") {
--- a/browser/components/extensions/test/browser/browser_ext_contextMenus_onclick.js
+++ b/browser/components/extensions/test/browser/browser_ext_contextMenus_onclick.js
@@ -1,12 +1,14 @@
/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";
+const PAGE = "http://mochi.test:8888/browser/browser/components/extensions/test/browser/context.html";
+
// Loaded both as a background script and a tab page.
function testScript() {
let page = location.pathname.includes("tab.html") ? "tab" : "background";
let clickCounts = {
old: 0,
new: 0,
};
browser.contextMenus.onClicked.addListener(() => {
@@ -71,18 +73,17 @@ function testScript() {
pages = pages.filter(w => w !== window);
browser.test.assertEq(pages[0], browser.extension.getBackgroundPage(),
"Expected the other page to be a background page");
browser.test.sendMessage("tab.html ready");
}
}
add_task(function* () {
- let tab1 = yield BrowserTestUtils.openNewForegroundTab(gBrowser,
- "http://mochi.test:8888/browser/browser/components/extensions/test/browser/context.html");
+ let tab1 = yield BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE);
gBrowser.selectedTab = tab1;
let extension = ExtensionTestUtils.loadExtension({
manifest: {
"permissions": ["contextMenus"],
},
background: testScript,
@@ -189,8 +190,57 @@ add_task(function* () {
// more coverage, let's use removeAll instead of remove.
extension.sendMessage(pageOne, "removeAll");
yield extension.awaitMessage("next");
}
}
yield extension.unload();
yield BrowserTestUtils.removeTab(tab1);
});
+
+add_task(function* test_onclick_modifiers() {
+ const manifest = {
+ permissions: ["contextMenus"],
+ };
+
+ function background() {
+ function onclick(info) {
+ browser.test.sendMessage("click", info);
+ }
+ browser.contextMenus.create({contexts: ["all"], title: "modify", onclick});
+ browser.test.sendMessage("ready");
+ }
+
+ const extension = ExtensionTestUtils.loadExtension({manifest, background});
+ const tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE);
+
+ yield extension.startup();
+ yield extension.awaitMessage("ready");
+
+ function* click(modifiers = {}) {
+ const menu = yield openContextMenu();
+ const items = menu.getElementsByAttribute("label", "modify");
+ yield closeExtensionContextMenu(items[0], modifiers);
+ return extension.awaitMessage("click");
+ }
+
+ const plain = yield click();
+ is(plain.modifiers.length, 0, "modifiers array empty with a plain click");
+
+ const shift = yield click({shiftKey: true});
+ is(shift.modifiers.join(), "Shift", "Correct modifier: Shift");
+
+ const ctrl = yield click({ctrlKey: true});
+ if (AppConstants.platform !== "macosx") {
+ is(ctrl.modifiers.join(), "Ctrl", "Correct modifier: Ctrl");
+ } else {
+ is(ctrl.modifiers.sort().join(), "Ctrl,MacCtrl", "Correct modifier: Ctrl (and MacCtrl)");
+
+ const meta = yield click({metaKey: true});
+ is(meta.modifiers.join(), "Command", "Correct modifier: Command");
+ }
+
+ const altShift = yield click({altKey: true, shiftKey: true});
+ is(altShift.modifiers.sort().join(), "Alt,Shift", "Correct modifiers: Shift+Alt");
+
+ yield BrowserTestUtils.removeTab(tab);
+ yield extension.unload();
+});
--- a/browser/components/extensions/test/browser/head.js
+++ b/browser/components/extensions/test/browser/head.js
@@ -252,20 +252,20 @@ function* openExtensionContextMenu(selec
let extensionMenu = topLevelMenu[0].childNodes[0];
let popupShownPromise = BrowserTestUtils.waitForEvent(contextMenu, "popupshown");
EventUtils.synthesizeMouseAtCenter(extensionMenu, {});
yield popupShownPromise;
return extensionMenu;
}
-function* closeExtensionContextMenu(itemToSelect) {
+function* closeExtensionContextMenu(itemToSelect, modifiers = {}) {
let contentAreaContextMenu = document.getElementById("contentAreaContextMenu");
let popupHiddenPromise = BrowserTestUtils.waitForEvent(contentAreaContextMenu, "popuphidden");
- EventUtils.synthesizeMouseAtCenter(itemToSelect, {});
+ EventUtils.synthesizeMouseAtCenter(itemToSelect, modifiers);
yield popupHiddenPromise;
}
function* openChromeContextMenu(menuId, target, win = window) {
const node = win.document.querySelector(target);
const menu = win.document.getElementById(menuId);
const shown = BrowserTestUtils.waitForEvent(menu, "popupshown");
EventUtils.synthesizeMouseAtCenter(node, {type: "contextmenu"}, win);