diff --git a/browser/base/content/browser-places.js b/browser/base/content/browser-places.js
index 5073afbbc2b1..0662fe14875f 100644
--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -1279,123 +1279,10 @@ var PlacesToolbarHelper = {
}
},
- updateManagedBookmarksContextMenu(popup) {
- let hiddenContainerItems = [
- "placesContextManaged_openSeparator",
- "placesContextManaged_open:newtab",
- "placesContextManaged_open:newwindow",
- "placesContextManaged_copy",
- ];
-
- if (
- popup.triggerNode.id == "managed-bookmarks" &&
- !popup.triggerNode.menupopup.hasAttribute("hasbeenopened")
- ) {
- this.populateManagedBookmarks(popup.triggerNode.menupopup);
- }
- let isContainer = popup.triggerNode.getAttribute("container") == "true";
- document.getElementById(
- "placesContextManaged_openContainer:tabs"
- ).hidden = !isContainer;
- let openContainerInTabs = false;
- if (isContainer) {
- let menuitems = popup.triggerNode.menupopup.children;
- openContainerInTabs = Array.from(menuitems).some(
- menuitem => menuitem.link
- );
- }
- document.getElementById(
- "placesContextManaged_openContainer:tabs"
- ).disabled = !openContainerInTabs;
- document.getElementById(
- "placesContextManaged_open:newprivatewindow"
- ).hidden = isContainer || PrivateBrowsingUtils.isWindowPrivate(window);
-
- hiddenContainerItems.forEach(
- id => (document.getElementById(id).hidden = isContainer)
- );
- },
-
- openManagedBookmark(event, where, private = false) {
- event = getRootEvent(event);
- if (where) {
- openUILinkIn(event.target.parentNode.triggerNode.link, where, {
- triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
- private,
- });
- } else {
- openUILink(event.target.link, event, {
- triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
- });
- }
- },
-
- openManagedFolder(event) {
- let menuitems = event.target.parentNode.triggerNode.menupopup.children;
- let items = [];
- for (let i = 0; i < menuitems.length; i++) {
- if (menuitems[i].link) {
- let item = {};
- item.uri = menuitems[i].link;
- item.isBookmark = true;
- items.push(item);
- }
- }
- PlacesUIUtils.openTabset(items, event, window);
- },
-
- copyManagedBookmark(event) {
- // This is a little hacky, but there is a lot of code in Places that handles
- // clipboard stuff, so it's easier to reuse.
- let node = {};
- node.type = 0;
- node.title = event.target.parentNode.triggerNode.label;
- node.uri = event.target.parentNode.triggerNode.link;
- // Copied from _populateClipboard in controller.js
-
- // This order is _important_! It controls how this and other applications
- // select data to be inserted based on type.
- let contents = [
- { type: PlacesUtils.TYPE_X_MOZ_URL, entries: [] },
- { type: PlacesUtils.TYPE_HTML, entries: [] },
- { type: PlacesUtils.TYPE_UNICODE, entries: [] },
- ];
-
- contents.forEach(function(content) {
- content.entries.push(PlacesUtils.wrapNode(node, content.type));
+ openManagedBookmark(event) {
+ openUILink(event.target.link, event, {
+ triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
});
-
- function addData(type, data) {
- xferable.addDataFlavor(type);
- xferable.setTransferData(
- type,
- PlacesUtils.toISupportsString(data),
- data.length * 2
- );
- }
-
- let xferable = Cc["@mozilla.org/widget/transferable;1"].createInstance(
- Ci.nsITransferable
- );
- xferable.init(null);
- let hasData = false;
- // This order matters here! It controls how this and other applications
- // select data to be inserted based on type.
- contents.forEach(function(content) {
- if (content.entries.length) {
- hasData = true;
- let glue = PlacesUtils.endl;
- addData(content.type, content.entries.join(glue));
- }
- });
-
- if (hasData) {
- Services.clipboard.setData(
- xferable,
- null,
- Ci.nsIClipboard.kGlobalClipboard
- );
- }
},
onDragStartManaged(event) {
diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js
index e2723c51258e..c45991c6e390 100644
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -2098,9 +2098,11 @@ var gBrowserInit = {
child => !("toplevel_name" in child)
);
if (children.length) {
- let managedBookmarksButton = document.getElementById(
- "managed-bookmarks"
+ let managedBookmarksButton = document.createXULElement(
+ "toolbarbutton"
);
+ managedBookmarksButton.setAttribute("id", "managed-bookmarks");
+ managedBookmarksButton.setAttribute("class", "bookmark-item");
let toplevel = managedBookmarks.find(
element => "toplevel_name" in element
);
@@ -2109,9 +2111,48 @@ var gBrowserInit = {
"label",
toplevel.toplevel_name
);
- managedBookmarksButton.removeAttribute("data-l10n-id");
+ } else {
+ managedBookmarksButton.setAttribute(
+ "data-l10n-id",
+ "managed-bookmarks"
+ );
}
- managedBookmarksButton.hidden = false;
+ managedBookmarksButton.setAttribute("context", "placesContext");
+ managedBookmarksButton.setAttribute("container", "true");
+ managedBookmarksButton.setAttribute("removable", "false");
+ managedBookmarksButton.setAttribute("type", "menu");
+
+ let managedBookmarksPopup = document.createXULElement("menupopup");
+ managedBookmarksPopup.setAttribute("id", "managed-bookmarks-popup");
+ managedBookmarksPopup.setAttribute(
+ "oncommand",
+ "PlacesToolbarHelper.openManagedBookmark(event);"
+ );
+ managedBookmarksPopup.setAttribute(
+ "onclick",
+ "checkForMiddleClick(this, event);"
+ );
+ managedBookmarksPopup.setAttribute(
+ "ondragover",
+ "event.dataTransfer.effectAllowed='none';"
+ );
+ managedBookmarksPopup.setAttribute(
+ "ondragstart",
+ "PlacesToolbarHelper.onDragStartManaged(event);"
+ );
+ managedBookmarksPopup.setAttribute(
+ "onpopupshowing",
+ "PlacesToolbarHelper.populateManagedBookmarks(this);"
+ );
+ managedBookmarksPopup.setAttribute("placespopup", "true");
+ managedBookmarksPopup.setAttribute("is", "places-popup");
+ managedBookmarksButton.appendChild(managedBookmarksPopup);
+
+ gNavToolbox.palette.appendChild(managedBookmarksButton);
+ CustomizableUI.ensureWidgetPlacedInWindow(
+ "managed-bookmarks",
+ window
+ );
}
}
}
diff --git a/browser/base/content/browser.xhtml b/browser/base/content/browser.xhtml
index 0206335f4c59..a5e936777e7c 100644
--- a/browser/base/content/browser.xhtml
+++ b/browser/base/content/browser.xhtml
@@ -2051,22 +2051,6 @@
customizable="true">
-
-
-
-
{
SimpleTest.waitForClipboard(
diff --git a/browser/components/places/PlacesUIUtils.jsm b/browser/components/places/PlacesUIUtils.jsm
index 7ea995cb2f44..b1d52cc131d0 100644
--- a/browser/components/places/PlacesUIUtils.jsm
+++ b/browser/components/places/PlacesUIUtils.jsm
@@ -454,6 +454,10 @@ var PlacesUIUtils = {
return null;
}
if (popupNode) {
+ let isManaged = !!popupNode.closest("#managed-bookmarks");
+ if (isManaged) {
+ return this.managedBookmarksController;
+ }
let view = this.getViewForNode(popupNode);
if (view && view._contextMenuShown) {
return view.controllers.getControllerForCommand(command);
@@ -1213,6 +1217,196 @@ var PlacesUIUtils = {
this.maybeToggleBookmarkToolbarVisibility(true);
}
},
+
+ async managedPlacesContextShowing(event) {
+ let menupopup = event.target;
+ let document = menupopup.ownerDocument;
+ let window = menupopup.ownerGlobal;
+ // We need to populate the submenus in order to have information
+ // to show the context menu.
+ if (
+ menupopup.triggerNode.id == "managed-bookmarks" &&
+ !menupopup.triggerNode.menupopup.hasAttribute("hasbeenopened")
+ ) {
+ await window.PlacesToolbarHelper.populateManagedBookmarks(
+ menupopup.triggerNode.menupopup
+ );
+ }
+ let linkItems = [
+ "placesContext_open:newtab",
+ "placesContext_open:newwindow",
+ "placesContext_open:newprivatewindow",
+ "placesContext_openSeparator",
+ "placesContext_copy",
+ ];
+ Array.from(menupopup.children).forEach(function(child) {
+ if (!(child.id in linkItems)) {
+ child.hidden = true;
+ }
+ });
+ // Store triggerNode in controller for checking if commands are enabled
+ this.managedBookmarksController.triggerNode = menupopup.triggerNode;
+ // Container in this context means a folder.
+ let isFolder = menupopup.triggerNode.hasAttribute("container");
+ let openContainerInTabs_menuitem = document.getElementById(
+ "placesContext_openContainer:tabs"
+ );
+ if (isFolder) {
+ // Disable the openContainerInTabs menuitem if there
+ // are no children of the menu that have links.
+ let menuitems = menupopup.triggerNode.menupopup.children;
+ let openContainerInTabs = Array.from(menuitems).some(
+ menuitem => menuitem.link
+ );
+ openContainerInTabs_menuitem.disabled = !openContainerInTabs;
+ } else {
+ document.getElementById(
+ "placesContext_open:newprivatewindow"
+ ).hidden = PrivateBrowsingUtils.isWindowPrivate(window);
+ }
+ openContainerInTabs_menuitem.hidden = !isFolder;
+ linkItems.forEach(id => (document.getElementById(id).hidden = isFolder));
+
+ event.target.ownerGlobal.updateCommands("places");
+ },
+
+ placesContextShowing(event) {
+ let menupopup = event.target;
+ let isManaged = !!menupopup.triggerNode.closest("#managed-bookmarks");
+ if (isManaged) {
+ this.managedPlacesContextShowing(event);
+ return true;
+ }
+ let document = menupopup.ownerDocument;
+ menupopup._view = this.getViewForNode(document.popupNode);
+ if (!this.openInTabClosesMenu) {
+ document
+ .getElementById("placesContext_open:newtab")
+ .setAttribute("closemenu", "single");
+ }
+ return menupopup._view.buildContextMenu(menupopup);
+ },
+
+ placesContextHiding(event) {
+ let menupopup = event.target;
+ if (menupopup._view) {
+ menupopup._view.destroyContextMenu();
+ }
+ },
+
+ openSelectionInTabs(event) {
+ let isManaged = !!event.target.parentNode.triggerNode.closest(
+ "#managed-bookmarks"
+ );
+ let controller;
+ if (isManaged) {
+ controller = this.managedBookmarksController;
+ } else {
+ let document = event.target.ownerDocument;
+ controller = PlacesUIUtils.getViewForNode(document.popupNode).controller;
+ }
+ controller.openSelectionInTabs(event);
+ },
+
+ managedBookmarksController: {
+ triggerNode: null,
+
+ openSelectionInTabs(event) {
+ let window = event.target.ownerGlobal;
+ let menuitems = event.target.parentNode.triggerNode.menupopup.children;
+ let items = [];
+ for (let i = 0; i < menuitems.length; i++) {
+ if (menuitems[i].link) {
+ let item = {};
+ item.uri = menuitems[i].link;
+ item.isBookmark = true;
+ items.push(item);
+ }
+ }
+ PlacesUIUtils.openTabset(items, event, window);
+ },
+
+ isCommandEnabled(command) {
+ switch (command) {
+ case "placesCmd_copy":
+ case "placesCmd_open:window":
+ case "placesCmd_open:privatewindow":
+ case "placesCmd_open:tab": {
+ return true;
+ }
+ }
+ return false;
+ },
+
+ doCommand(command) {
+ let window = this.triggerNode.ownerGlobal;
+ switch (command) {
+ case "placesCmd_copy":
+ // This is a little hacky, but there is a lot of code in Places that handles
+ // clipboard stuff, so it's easier to reuse.
+ let node = {};
+ node.type = 0;
+ node.title = this.triggerNode.label;
+ node.uri = this.triggerNode.link;
+
+ // Copied from _populateClipboard in controller.js
+
+ // This order is _important_! It controls how this and other applications
+ // select data to be inserted based on type.
+ let contents = [
+ { type: PlacesUtils.TYPE_X_MOZ_URL, entries: [] },
+ { type: PlacesUtils.TYPE_HTML, entries: [] },
+ { type: PlacesUtils.TYPE_UNICODE, entries: [] },
+ ];
+
+ contents.forEach(function(content) {
+ content.entries.push(PlacesUtils.wrapNode(node, content.type));
+ });
+
+ let xferable = Cc[
+ "@mozilla.org/widget/transferable;1"
+ ].createInstance(Ci.nsITransferable);
+ xferable.init(null);
+
+ function addData(type, data) {
+ xferable.addDataFlavor(type);
+ xferable.setTransferData(
+ type,
+ PlacesUtils.toISupportsString(data),
+ data.length * 2
+ );
+ }
+
+ contents.forEach(function(content) {
+ addData(content.type, content.entries.join(PlacesUtils.endl));
+ });
+
+ Services.clipboard.setData(
+ xferable,
+ null,
+ Ci.nsIClipboard.kGlobalClipboard
+ );
+ break;
+ case "placesCmd_open:privatewindow":
+ window.openUILinkIn(this.triggerNode.link, "window", {
+ triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
+ private: true,
+ });
+ break;
+ case "placesCmd_open:window":
+ window.openUILinkIn(this.triggerNode.link, "window", {
+ triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
+ private: false,
+ });
+ break;
+ case "placesCmd_open:tab": {
+ window.openUILinkIn(this.triggerNode.link, "tab", {
+ triggeringPrincipal: Services.scriptSecurityManager.getSystemPrincipal(),
+ });
+ }
+ }
+ },
+ },
};
// These are lazy getters to avoid importing PlacesUtils immediately.
diff --git a/browser/components/places/content/placesContextMenu.inc.xhtml b/browser/components/places/content/placesContextMenu.inc.xhtml
index 5ad549016fe0..d5d174e1fcbd 100644
--- a/browser/components/places/content/placesContextMenu.inc.xhtml
+++ b/browser/components/places/content/placesContextMenu.inc.xhtml
@@ -3,13 +3,8 @@
# You can obtain one at http://mozilla.org/MPL/2.0/.
+ onpopupshowing="return PlacesUIUtils.placesContextShowing(event);"
+ onpopuphiding="PlacesUIUtils.placesContextHiding(event);">
-
-
-
-
-
-
-
-
-
diff --git a/browser/modules/test/browser/browser_UsageTelemetry_toolbars.js b/browser/modules/test/browser/browser_UsageTelemetry_toolbars.js
index 2038afdf4159..ca47e0805ad9 100644
--- a/browser/modules/test/browser/browser_UsageTelemetry_toolbars.js
+++ b/browser/modules/test/browser/browser_UsageTelemetry_toolbars.js
@@ -178,8 +178,6 @@ add_task(async function widgetPositions() {
"forward-button_pinned_nav-bar-start",
"back-button_pinned_nav-bar-start",
-
- "managed-bookmarks_pinned_bookmarks-bar",
]);
organizeToolbars({
@@ -230,8 +228,6 @@ add_task(async function widgetPositions() {
"fxa-toolbar-menu-button_pinned_bookmarks-bar",
"new-tab-button_pinned_bookmarks-bar",
"developer-button_pinned_bookmarks-bar",
-
- "managed-bookmarks_pinned_bookmarks-bar",
]);
CustomizableUI.reset();
@@ -273,8 +269,6 @@ add_task(async function customizeMode() {
"library-button_pinned_nav-bar-end",
"personal-bookmarks_pinned_bookmarks-bar",
-
- "managed-bookmarks_pinned_bookmarks-bar",
]);
let win = await BrowserTestUtils.openNewBrowserWindow();
@@ -365,8 +359,6 @@ add_task(async function contextMenus() {
"library-button_pinned_nav-bar-end",
"personal-bookmarks_pinned_bookmarks-bar",
-
- "managed-bookmarks_pinned_bookmarks-bar",
]);
let menu = document.getElementById("toolbar-context-menu");
@@ -450,8 +442,6 @@ add_task(async function pageActions() {
"pinTab_pinned_pageaction-urlbar",
"personal-bookmarks_pinned_bookmarks-bar",
-
- "managed-bookmarks_pinned_bookmarks-bar",
]);
let panel = document.getElementById("pageActionPanel");
@@ -554,8 +544,6 @@ add_task(async function extensions() {
"random-addon-example-com_pinned_nav-bar-end",
"random-addon-example-com_pinned_pageaction-urlbar",
-
- "managed-bookmarks_pinned_bookmarks-bar",
]);
let addon = await AddonManager.getAddonByID(extension.id);
@@ -579,8 +567,6 @@ add_task(async function extensions() {
"forward-button_pinned_nav-bar-start",
"back-button_pinned_nav-bar-start",
-
- "managed-bookmarks_pinned_bookmarks-bar",
]);
await addon.enable();
@@ -607,8 +593,6 @@ add_task(async function extensions() {
"random-addon-example-com_pinned_nav-bar-end",
"random-addon-example-com_pinned_pageaction-urlbar",
-
- "managed-bookmarks_pinned_bookmarks-bar",
]);
await addon.reload();
@@ -653,8 +637,6 @@ add_task(async function extensions() {
"forward-button_pinned_nav-bar-start",
"back-button_pinned_nav-bar-start",
-
- "managed-bookmarks_pinned_bookmarks-bar",
]);
});
});