mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-23 10:15:41 +00:00
Bug 1419195: Show items from WebExtensions in Places Library context menu r=mixedpuppy
Depends on D16413 Differential Revision: https://phabricator.services.mozilla.com/D16414 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
7005fd08d0
commit
beef78d6c8
@ -4,6 +4,9 @@
|
||||
|
||||
ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
ChromeUtils.defineModuleGetter(this, "Bookmarks",
|
||||
"resource://gre/modules/Bookmarks.jsm");
|
||||
|
||||
var {
|
||||
DefaultMap,
|
||||
ExtensionError,
|
||||
@ -863,6 +866,72 @@ MenuItem.prototype = {
|
||||
},
|
||||
};
|
||||
|
||||
// windowTracker only looks as browser windows, but we're also interested in
|
||||
// the Library window. Helper for menuTracker below.
|
||||
const libraryTracker = {
|
||||
libraryWindowType: "Places:Organizer",
|
||||
|
||||
isLibraryWindow(window) {
|
||||
let winType = window.document.documentElement.getAttribute("windowtype");
|
||||
return winType === this.libraryWindowType;
|
||||
},
|
||||
|
||||
init(listener) {
|
||||
this._listener = listener;
|
||||
Services.ww.registerNotification(this);
|
||||
|
||||
// See WindowTrackerBase#*browserWindows in ext-tabs-base.js for why we
|
||||
// can't use the enumerator's windowtype filter.
|
||||
for (let window of Services.wm.getEnumerator("")) {
|
||||
if (window.document.readyState === "complete") {
|
||||
if (this.isLibraryWindow(window)) {
|
||||
this.notify(window);
|
||||
}
|
||||
} else {
|
||||
window.addEventListener("load", this, {once: true});
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// cleanupWindow is called on any library window that's open.
|
||||
uninit(cleanupWindow) {
|
||||
Services.ww.unregisterNotification(this);
|
||||
|
||||
for (let window of Services.wm.getEnumerator(this.libraryWindowType)) {
|
||||
try {
|
||||
window.removeEventListener("load", this);
|
||||
cleanupWindow(window);
|
||||
} catch (e) {
|
||||
Cu.reportError(e);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
// Gets notifications from Services.ww.registerNotification.
|
||||
// Defer actually doing anything until the window's loaded, though.
|
||||
observe(window, topic) {
|
||||
if (topic === "domwindowopened") {
|
||||
window.addEventListener("load", this, {once: true});
|
||||
}
|
||||
},
|
||||
|
||||
// Gets the load event for new windows(registered in observe()).
|
||||
handleEvent(event) {
|
||||
let window = event.target.defaultView;
|
||||
if (this.isLibraryWindow(window)) {
|
||||
this.notify(window);
|
||||
}
|
||||
},
|
||||
|
||||
notify(window) {
|
||||
try {
|
||||
this._listener.call(null, window);
|
||||
} catch (e) {
|
||||
Cu.reportError(e);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
// While any extensions are active, this Tracker registers to observe/listen
|
||||
// for menu events from both Tools and context menus, both content and chrome.
|
||||
const menuTracker = {
|
||||
@ -874,6 +943,7 @@ const menuTracker = {
|
||||
this.onWindowOpen(window);
|
||||
}
|
||||
windowTracker.addOpenListener(this.onWindowOpen);
|
||||
libraryTracker.init(this.onLibraryOpen);
|
||||
},
|
||||
|
||||
unregister() {
|
||||
@ -882,6 +952,7 @@ const menuTracker = {
|
||||
this.cleanupWindow(window);
|
||||
}
|
||||
windowTracker.removeOpenListener(this.onWindowOpen);
|
||||
libraryTracker.uninit(this.cleanupLibrary);
|
||||
},
|
||||
|
||||
observe(subject, topic, data) {
|
||||
@ -929,6 +1000,16 @@ const menuTracker = {
|
||||
}
|
||||
},
|
||||
|
||||
onLibraryOpen(window) {
|
||||
const menu = window.document.getElementById("placesContext");
|
||||
menu.addEventListener("popupshowing", menuTracker.onBookmarksContextMenu);
|
||||
},
|
||||
|
||||
cleanupLibrary(window) {
|
||||
const menu = window.document.getElementById("placesContext");
|
||||
menu.removeEventListener("popupshowing", menuTracker.onBookmarksContextMenu);
|
||||
},
|
||||
|
||||
handleEvent(event) {
|
||||
const menu = event.target;
|
||||
|
||||
@ -963,6 +1044,10 @@ const menuTracker = {
|
||||
const cell = tree.boxObject.getCellAt(event.x, event.y);
|
||||
const node = tree.view.nodeForTreeIndex(cell.row);
|
||||
|
||||
if (!node.bookmarkGuid || Bookmarks.isVirtualRootItem(node.bookmarkGuid)) {
|
||||
return;
|
||||
}
|
||||
|
||||
gMenuBuilder.build({
|
||||
menu,
|
||||
bookmarkId: node.bookmarkGuid,
|
||||
|
@ -5,7 +5,9 @@
|
||||
Services.scriptloader.loadSubScript(
|
||||
"chrome://mochitests/content/browser/browser/components/places/tests/browser/head.js",
|
||||
this);
|
||||
/* globals withSidebarTree, synthesizeClickOnSelectedTreeCell */
|
||||
/* globals withSidebarTree, synthesizeClickOnSelectedTreeCell,
|
||||
* promiseLibrary, promiseLibraryClosed
|
||||
*/
|
||||
|
||||
const PAGE = "http://mochi.test:8888/browser/browser/components/extensions/test/browser/context.html";
|
||||
|
||||
@ -606,6 +608,75 @@ add_task(async function test_bookmark_sidebar_contextmenu() {
|
||||
});
|
||||
});
|
||||
|
||||
function bookmarkFolderContextMenuExtension() {
|
||||
return ExtensionTestUtils.loadExtension({
|
||||
manifest: {
|
||||
permissions: ["contextMenus", "bookmarks"],
|
||||
},
|
||||
async background() {
|
||||
const title = "Example";
|
||||
let newBookmark = await browser.bookmarks.create({
|
||||
title,
|
||||
parentId: "toolbar_____",
|
||||
});
|
||||
await new Promise(resolve =>
|
||||
browser.contextMenus.create({
|
||||
title: "Get bookmark",
|
||||
contexts: ["bookmark"],
|
||||
}, resolve));
|
||||
browser.contextMenus.onClicked.addListener(async (info) => {
|
||||
browser.test.assertEq(newBookmark.id, info.bookmarkId, "Bookmark ID matches");
|
||||
|
||||
let [bookmark] = await browser.bookmarks.get(info.bookmarkId);
|
||||
browser.test.assertEq(title, bookmark.title, "Bookmark title matches");
|
||||
browser.test.assertFalse(info.hasOwnProperty("pageUrl"), "Context menu does not expose pageUrl");
|
||||
await browser.bookmarks.remove(info.bookmarkId);
|
||||
browser.test.sendMessage("test-finish");
|
||||
});
|
||||
browser.test.sendMessage("bookmark-created", newBookmark.id);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
add_task(async function test_organizer_contextmenu() {
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, PAGE);
|
||||
let library = await promiseLibrary("BookmarksToolbar");
|
||||
|
||||
let menu = library.document.getElementById("placesContext");
|
||||
let mainTree = library.document.getElementById("placeContent");
|
||||
let leftTree = library.document.getElementById("placesList");
|
||||
|
||||
let tests = [
|
||||
[mainTree, bookmarkContextMenuExtension],
|
||||
[mainTree, bookmarkFolderContextMenuExtension],
|
||||
[leftTree, bookmarkFolderContextMenuExtension],
|
||||
];
|
||||
|
||||
if (AppConstants.DEBUG) {
|
||||
// Avoid intermittent leak - bug 1520047
|
||||
tests.pop();
|
||||
}
|
||||
|
||||
for (let [tree, makeExtension] of tests) {
|
||||
let extension = makeExtension();
|
||||
await extension.startup();
|
||||
let bookmarkGuid = await extension.awaitMessage("bookmark-created");
|
||||
|
||||
tree.selectItems([bookmarkGuid]);
|
||||
let shown = BrowserTestUtils.waitForEvent(menu, "popupshown");
|
||||
synthesizeClickOnSelectedTreeCell(tree, {type: "contextmenu"});
|
||||
await shown;
|
||||
|
||||
let menuItem = menu.getElementsByAttribute("label", "Get bookmark")[0];
|
||||
closeChromeContextMenu("placesContext", menuItem, library);
|
||||
await extension.awaitMessage("test-finish");
|
||||
await extension.unload();
|
||||
}
|
||||
|
||||
await promiseLibraryClosed(library);
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
|
||||
add_task(async function test_bookmark_context_requires_permission() {
|
||||
const bookmarksToolbar = document.getElementById("PersonalToolbar");
|
||||
setToolbarVisibility(bookmarksToolbar, true);
|
||||
|
Loading…
Reference in New Issue
Block a user