--- a/browser/base/content/browser-places.js
+++ b/browser/base/content/browser-places.js
@@ -561,17 +561,17 @@ var PlacesCommandHook = {
*/
bookmarkCurrentPage: function PCH_bookmarkCurrentPage(aShowEditUI, aParent) {
this.bookmarkPage(gBrowser.selectedBrowser, aParent, aShowEditUI)
.catch(Components.utils.reportError);
},
/**
* Adds a bookmark to the page targeted by a link.
- * @param aParent
+ * @param aParentId
* The folder in which to create a new bookmark if aURL isn't
* bookmarked.
* @param aURL (string)
* the address of the link target
* @param aTitle
* The link text
* @param [optional] aDescription
* The linked page description, if available
@@ -580,19 +580,23 @@ var PlacesCommandHook = {
let node = await PlacesUIUtils.fetchNodeLike({ url: aURL });
if (node) {
PlacesUIUtils.showBookmarkDialog({ action: "edit",
node
}, window.top);
return;
}
+ let parentGuid = aParentId == PlacesUtils.bookmarksMenuFolderId ?
+ PlacesUtils.bookmarks.menuGuid :
+ await PlacesUtils.promiseItemGuid(aParentId);
let ip = new InsertionPoint(aParentId,
PlacesUtils.bookmarks.DEFAULT_INDEX,
- Components.interfaces.nsITreeView.DROP_ON);
+ Components.interfaces.nsITreeView.DROP_ON,
+ null, null, parentGuid);
PlacesUIUtils.showBookmarkDialog({ action: "add",
type: "bookmark",
uri: makeURI(aURL),
title: aTitle,
description: aDescription,
defaultInsertionPoint: ip,
hiddenRows: [ "description",
"location",
@@ -660,17 +664,18 @@ var PlacesCommandHook = {
* @title title
* The title of the feed. Optional.
* @subtitle subtitle
* A short description of the feed. Optional.
*/
async addLiveBookmark(url, feedTitle, feedSubtitle) {
let toolbarIP = new InsertionPoint(PlacesUtils.toolbarFolderId,
PlacesUtils.bookmarks.DEFAULT_INDEX,
- Components.interfaces.nsITreeView.DROP_ON);
+ Components.interfaces.nsITreeView.DROP_ON,
+ null, null, PlacesUtils.bookmarks.toolbarGuid);
let feedURI = makeURI(url);
let title = feedTitle || gBrowser.contentTitle;
let description = feedSubtitle;
if (!description) {
description = (await this._getPageDetails(gBrowser.selectedBrowser)).description;
}
@@ -1076,33 +1081,35 @@ var PlacesMenuDNDHandler = {
/**
* Called when the user drags over the <menu> element.
* @param event
* The DragOver event.
*/
onDragOver: function PMDH_onDragOver(event) {
let ip = new InsertionPoint(PlacesUtils.bookmarksMenuFolderId,
PlacesUtils.bookmarks.DEFAULT_INDEX,
- Components.interfaces.nsITreeView.DROP_ON);
+ Components.interfaces.nsITreeView.DROP_ON,
+ null, null, PlacesUtils.bookmarks.menuGuid);
if (ip && PlacesControllerDragHelper.canDrop(ip, event.dataTransfer))
event.preventDefault();
event.stopPropagation();
},
/**
* Called when the user drops on the <menu> element.
* @param event
* The Drop event.
*/
onDrop: function PMDH_onDrop(event) {
// Put the item at the end of bookmark menu.
let ip = new InsertionPoint(PlacesUtils.bookmarksMenuFolderId,
PlacesUtils.bookmarks.DEFAULT_INDEX,
- Components.interfaces.nsITreeView.DROP_ON);
+ Components.interfaces.nsITreeView.DROP_ON,
+ null, null, PlacesUtils.bookmarks.menuGuid);
PlacesControllerDragHelper.onDrop(ip, event.dataTransfer);
PlacesControllerDragHelper.currentDropTarget = null;
event.stopPropagation();
}
};
/**
* This object handles the initialization and uninitialization of the bookmarks
--- a/browser/components/places/content/bookmarkProperties.js
+++ b/browser/components/places/content/bookmarkProperties.js
@@ -161,17 +161,18 @@ var BookmarkPropertiesPanel = {
this._title = dialogInfo.title;
if ("defaultInsertionPoint" in dialogInfo) {
this._defaultInsertionPoint = dialogInfo.defaultInsertionPoint;
} else {
this._defaultInsertionPoint =
new InsertionPoint(PlacesUtils.bookmarksMenuFolderId,
PlacesUtils.bookmarks.DEFAULT_INDEX,
- Ci.nsITreeView.DROP_ON);
+ Ci.nsITreeView.DROP_ON, null, null,
+ PlacesUtils.bookmarks.menuGuid);
}
switch (dialogInfo.type) {
case "bookmark":
this._itemType = BOOKMARK_ITEM;
if ("uri" in dialogInfo) {
NS_ASSERT(dialogInfo.uri instanceof Ci.nsIURI,
"uri property should be a uri object");
@@ -488,21 +489,22 @@ var BookmarkPropertiesPanel = {
/**
* [New Item Mode] Get the insertion point details for the new item, given
* dialog state and opening arguments.
*
* The container-identifier and insertion-index are returned separately in
* the form of [containerIdentifier, insertionIndex]
*/
- _getInsertionPointDetails: function BPP__getInsertionPointDetails() {
- var containerId = this._defaultInsertionPoint.itemId;
- var indexInContainer = this._defaultInsertionPoint.index;
-
- return [containerId, indexInContainer];
+ async _getInsertionPointDetails() {
+ return [
+ this._defaultInsertionPoint.itemId,
+ await this._defaultInsertionPoint.getIndex(),
+ await this._defaultInsertionPoint.promiseGuid(),
+ ]
},
/**
* Returns a transaction for creating a new bookmark item representing the
* various fields and opening arguments of the dialog.
*/
_getCreateNewBookmarkTransaction:
function BPP__getCreateNewBookmarkTransaction(aContainer, aIndex) {
@@ -579,17 +581,17 @@ var BookmarkPropertiesPanel = {
annotations.push(this._getDescriptionAnnotation(this._description));
return new PlacesCreateFolderTransaction(this._title, aContainer,
aIndex, annotations,
childItemsTransactions);
},
async _createNewItem() {
- let [container, index] = this._getInsertionPointDetails();
+ let [container, index] = await this._getInsertionPointDetails();
let txn;
switch (this._itemType) {
case BOOKMARK_FOLDER:
txn = this._getCreateNewFolderTransaction(container, index);
break;
case LIVEMARK_CONTAINER:
txn = new PlacesCreateLivemarkTransaction(this._feedURI, this._siteURI,
this._title, container, index);
@@ -626,18 +628,17 @@ var BookmarkPropertiesPanel = {
}
});
},
async _promiseNewItem() {
if (!PlacesUIUtils.useAsyncTransactions)
return this._createNewItem();
- let [containerId, index] = this._getInsertionPointDetails();
- let parentGuid = await PlacesUtils.promiseItemGuid(containerId);
+ let [containerId, index, parentGuid] = await this._getInsertionPointDetails();
let annotations = [];
if (this._description) {
annotations.push({ name: PlacesUIUtils.DESCRIPTION_ANNO,
value: this._description });
}
if (this._loadInSidebar) {
annotations.push({ name: PlacesUIUtils.LOAD_IN_SIDEBAR_ANNO,
value: true });
--- a/browser/components/places/content/browserPlacesViews.js
+++ b/browser/components/places/content/browserPlacesViews.js
@@ -218,17 +218,18 @@ PlacesViewBase.prototype = {
}
}
}
if (PlacesControllerDragHelper.disallowInsertion(container))
return null;
return new InsertionPoint(PlacesUtils.getConcreteItemId(container),
- index, orientation, tagName);
+ index, orientation, tagName, null,
+ PlacesUtils.getConcreteItemGuid(container));
},
buildContextMenu: function PVB_buildContextMenu(aPopup) {
this._contextMenuShown = aPopup;
window.updateCommands("places");
return this.controller.buildContextMenu(aPopup);
},
@@ -1415,68 +1416,73 @@ PlacesToolbar.prototype = {
// If we are in the middle of it, drop inside it.
// Otherwise, drop before it, with regards to RTL mode.
let threshold = eltRect.width * 0.25;
if (this.isRTL ? (aEvent.clientX > eltRect.right - threshold)
: (aEvent.clientX < eltRect.left + threshold)) {
// Drop before this folder.
dropPoint.ip =
new InsertionPoint(PlacesUtils.getConcreteItemId(this._resultNode),
- eltIndex, Ci.nsITreeView.DROP_BEFORE);
+ eltIndex, Ci.nsITreeView.DROP_BEFORE, null, null,
+ PlacesUtils.getConcreteItemGuid(this._resultNode));
dropPoint.beforeIndex = eltIndex;
} else if (this.isRTL ? (aEvent.clientX > eltRect.left + threshold)
: (aEvent.clientX < eltRect.right - threshold)) {
// Drop inside this folder.
let tagName = PlacesUtils.nodeIsTagQuery(elt._placesNode) ?
elt._placesNode.title : null;
dropPoint.ip =
new InsertionPoint(PlacesUtils.getConcreteItemId(elt._placesNode),
- -1, Ci.nsITreeView.DROP_ON,
- tagName);
+ -1, Ci.nsITreeView.DROP_ON, tagName, null,
+ PlacesUtils.getConcreteItemGuid(elt._placesNode));
dropPoint.beforeIndex = eltIndex;
dropPoint.folderElt = elt;
} else {
// Drop after this folder.
let beforeIndex =
(eltIndex == this._rootElt.childNodes.length - 1) ?
-1 : eltIndex + 1;
dropPoint.ip =
new InsertionPoint(PlacesUtils.getConcreteItemId(this._resultNode),
- beforeIndex, Ci.nsITreeView.DROP_BEFORE);
+ beforeIndex, Ci.nsITreeView.DROP_BEFORE, null, null,
+ PlacesUtils.getConcreteItemGuid(this._resultNode));
dropPoint.beforeIndex = beforeIndex;
}
} else {
// This is a non-folder node or a read-only folder.
// Drop before it with regards to RTL mode.
let threshold = eltRect.width * 0.5;
if (this.isRTL ? (aEvent.clientX > eltRect.left + threshold)
: (aEvent.clientX < eltRect.left + threshold)) {
// Drop before this bookmark.
dropPoint.ip =
new InsertionPoint(PlacesUtils.getConcreteItemId(this._resultNode),
- eltIndex, Ci.nsITreeView.DROP_BEFORE);
+ eltIndex, Ci.nsITreeView.DROP_BEFORE, null, null,
+ PlacesUtils.getConcreteItemGuid(this._resultNode));
dropPoint.beforeIndex = eltIndex;
} else {
// Drop after this bookmark.
let beforeIndex =
eltIndex == this._rootElt.childNodes.length - 1 ?
-1 : eltIndex + 1;
dropPoint.ip =
new InsertionPoint(PlacesUtils.getConcreteItemId(this._resultNode),
- beforeIndex, Ci.nsITreeView.DROP_BEFORE);
+ beforeIndex, Ci.nsITreeView.DROP_BEFORE, null, null,
+ PlacesUtils.getConcreteItemGuid(this._resultNode));
dropPoint.beforeIndex = beforeIndex;
}
}
} else {
// We are most likely dragging on the empty area of the
// toolbar, we should drop after the last node.
dropPoint.ip =
new InsertionPoint(PlacesUtils.getConcreteItemId(this._resultNode),
- -1, Ci.nsITreeView.DROP_BEFORE);
+ -1, Ci.nsITreeView.DROP_BEFORE, null, null,
+ PlacesUtils.getConcreteItemGuid(this._resultNode));
dropPoint.beforeIndex = -1;
}
return dropPoint;
},
_setTimer: function PT_setTimer(aTime) {
let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
--- a/browser/components/places/content/controller.js
+++ b/browser/components/places/content/controller.js
@@ -32,43 +32,65 @@ const RELOAD_ACTION_MOVE = 3;
* The index within the container where we should insert
* @param aOrientation
* The orientation of the insertion. NOTE: the adjustments to the
* insertion point to accommodate the orientation should be done by
* the person who constructs the IP, not the user. The orientation
* is provided for informational purposes only!
* @param [optional] aTag
* The tag name if this IP is set to a tag, null otherwise.
- * @param [optional] aDropNearItemId
- * When defined we will calculate index based on this itemId
+ * @param [optional] aDropNearNode
+ * When defined we will calculate index based on this node
+ * @param [optional] aGuid
+ * The guid of the parent container
* @constructor
*/
function InsertionPoint(aItemId, aIndex, aOrientation, aTagName = null,
- aDropNearItemId = false) {
+ aDropNearNode = null, aGuid = null) {
+
this.itemId = aItemId;
+ this.guid = aGuid;
this._index = aIndex;
this.orientation = aOrientation;
this.tagName = aTagName;
- this.dropNearItemId = aDropNearItemId;
+ this.dropNearNode = aDropNearNode;
}
InsertionPoint.prototype = {
set index(val) {
return this._index = val;
},
+ // TODO (Bug 1382991): Remove this backwards compatibility shim.
promiseGuid() {
- return PlacesUtils.promiseItemGuid(this.itemId);
+ return this.guid || PlacesUtils.promiseItemGuid(this.itemId);
},
+ // TODO (Bug 1382991): Remove this backwards compatibility shim.
get index() {
- if (this.dropNearItemId > 0) {
+ if (this.dropNearNode && typeof this.dropNearNode != "number")
+ throw new Error("dropNearNode is not a number, use getIndex() instead?");
+ if (this.dropNearNode > 0) {
// If dropNearItemId is set up we must calculate the real index of
// the item near which we will drop.
- var index = PlacesUtils.bookmarks.getItemIndex(this.dropNearItemId);
+ var index = PlacesUtils.bookmarks.getItemIndex(this.dropNearNode);
+ return this.orientation == Ci.nsITreeView.DROP_BEFORE ? index : index + 1;
+ }
+ return this._index;
+ },
+
+ async getIndex() {
+ // TODO (Bug 1382991): Remove this backwards compatibility check.
+ if (typeof this.dropNearNode == "number")
+ return this.index;
+
+ if (this.dropNearNode) {
+ // If dropNearNode is set up we must calculate the index of the item near
+ // which we will drop.
+ let index = (await PlacesUtils.bookmarks.fetch(this.dropNearNode.bookmarkGuid)).index;
return this.orientation == Ci.nsITreeView.DROP_BEFORE ? index : index + 1;
}
return this._index;
},
get isTag() {
return typeof(this.tagName) == "string";
}
@@ -263,20 +285,20 @@ PlacesController.prototype = {
break;
case "placesCmd_open:privatewindow":
PlacesUIUtils.openNodeIn(this._view.selectedNode, "window", this._view, true);
break;
case "placesCmd_open:tab":
PlacesUIUtils.openNodeIn(this._view.selectedNode, "tab", this._view);
break;
case "placesCmd_new:folder":
- this.newItem("folder");
+ this.newItem("folder").catch(Components.utils.reportError);
break;
case "placesCmd_new:bookmark":
- this.newItem("bookmark");
+ this.newItem("bookmark").catch(Components.utils.reportError);
break;
case "placesCmd_new:separator":
this.newSeparator().catch(Components.utils.reportError);
break;
case "placesCmd_show:info":
this.showBookmarkPropertiesForSelection();
break;
case "placesCmd_moveBookmarks":
@@ -723,55 +745,56 @@ PlacesController.prototype = {
},
/**
* Shows the Add Bookmark UI for the current insertion point.
*
* @param aType
* the type of the new item (bookmark/livemark/folder)
*/
- newItem: function PC_newItem(aType) {
+ async newItem(aType) {
let ip = this._view.insertionPoint;
if (!ip)
throw Cr.NS_ERROR_NOT_AVAILABLE;
let performed =
PlacesUIUtils.showBookmarkDialog({ action: "add",
type: aType,
defaultInsertionPoint: ip,
hiddenRows: [ "folderPicker" ]
}, window.top);
if (performed) {
// Select the new item.
let insertedNodeId = PlacesUtils.bookmarks
- .getIdForItemAt(ip.itemId, ip.index);
+ .getIdForItemAt(ip.itemId, await ip.getIndex());
this._view.selectItems([insertedNodeId], false);
}
},
/**
* Create a new Bookmark separator somewhere.
*/
async newSeparator() {
var ip = this._view.insertionPoint;
if (!ip)
throw Cr.NS_ERROR_NOT_AVAILABLE;
+ let index = await ip.getIndex();
if (!PlacesUIUtils.useAsyncTransactions) {
- let txn = new PlacesCreateSeparatorTransaction(ip.itemId, ip.index);
+ let txn = new PlacesCreateSeparatorTransaction(ip.itemId, index);
PlacesUtils.transactionManager.doTransaction(txn);
// Select the new item.
let insertedNodeId = PlacesUtils.bookmarks
- .getIdForItemAt(ip.itemId, ip.index);
+ .getIdForItemAt(ip.itemId, index);
this._view.selectItems([insertedNodeId], false);
return;
}
let txn = PlacesTransactions.NewSeparator({ parentGuid: await ip.promiseGuid(),
- index: ip.index });
+ index });
let guid = await txn.transact();
let itemId = await PlacesUtils.promiseItemId(guid);
// Select the new item.
this._view.selectItems([itemId], false);
},
/**
* Opens a dialog for moving the selected nodes.
@@ -837,35 +860,37 @@ PlacesController.prototype = {
* A range is an array of adjacent nodes in a view.
* @param [in] range
* An array of nodes to remove. Should all be adjacent.
* @param [out] transactions
* An array of transactions.
* @param [optional] removedFolders
* An array of folder nodes that have already been removed.
*/
- _removeRange: function PC__removeRange(range, transactions, removedFolders) {
+ async _removeRange(range, transactions, removedFolders) {
NS_ASSERT(transactions instanceof Array, "Must pass a transactions array");
if (!removedFolders)
removedFolders = [];
for (var i = 0; i < range.length; ++i) {
var node = range[i];
if (this._shouldSkipNode(node, removedFolders))
continue;
if (PlacesUtils.nodeIsTagQuery(node.parent)) {
// This is a uri node inside a tag container. It needs a special
// untag transaction.
var tagItemId = PlacesUtils.getConcreteItemId(node.parent);
var uri = NetUtil.newURI(node.uri);
if (PlacesUIUtils.useAsyncTransactions) {
let tag = node.parent.title;
- if (!tag)
- tag = PlacesUtils.bookmarks.getItemTitle(tagItemId);
+ if (!tag) {
+ let tagGuid = PlacesUtils.getConcreteItemGuid(node.parent);
+ tag = (await PlacesUtils.bookmarks.fetch(tagGuid)).title;
+ }
transactions.push(PlacesTransactions.Untag({ uri, tag }));
} else {
let txn = new PlacesUntagURITransaction(uri, [tagItemId]);
transactions.push(txn);
}
} else if (PlacesUtils.nodeIsTagQuery(node) && node.parent &&
PlacesUtils.nodeIsQuery(node.parent) &&
PlacesUtils.asQuery(node.parent).queryOptions.resultType ==
@@ -923,18 +948,19 @@ PlacesController.prototype = {
* @param txnName
* See |remove|.
*/
async _removeRowsFromBookmarks(txnName) {
var ranges = this._view.removableSelectionRanges;
var transactions = [];
var removedFolders = [];
- for (var i = 0; i < ranges.length; i++)
- this._removeRange(ranges[i], transactions, removedFolders);
+ for (let range of ranges) {
+ await this._removeRange(range, transactions, removedFolders);
+ }
if (transactions.length > 0) {
if (PlacesUIUtils.useAsyncTransactions) {
await PlacesTransactions.batch(transactions);
} else {
var txn = new PlacesAggregatedTransaction(txnName, transactions);
PlacesUtils.transactionManager.doTransaction(txn);
}
@@ -1267,17 +1293,17 @@ PlacesController.prototype = {
let itemsToSelect = [];
if (PlacesUIUtils.useAsyncTransactions) {
if (ip.isTag) {
let urls = items.filter(item => "uri" in item).map(item => Services.io.newURI(item.uri));
await PlacesTransactions.Tag({ urls, tag: ip.tagName }).transact();
} else {
await PlacesTransactions.batch(async function() {
- let insertionIndex = ip.index;
+ let insertionIndex = await ip.getIndex();
let parent = await ip.promiseGuid();
for (let item of items) {
let doCopy = action == "copy";
// If this is not a copy, check for safety that we can move the
// source, otherwise report an error and fallback to a copy.
if (!doCopy &&
@@ -1294,51 +1320,51 @@ PlacesController.prototype = {
// position. If index is DEFAULT_INDEX, items are just appended.
if (insertionIndex != PlacesUtils.bookmarks.DEFAULT_INDEX)
insertionIndex++;
}
});
}
} else {
let transactions = [];
- let insertionIndex = ip.index;
- for (let i = 0; i < items.length; ++i) {
+ let insertionIndex = await ip.getIndex();
+ for (let index = insertionIndex, i = 0; i < items.length; ++i) {
if (ip.isTag) {
// Pasting into a tag container means tagging the item, regardless of
// the requested action.
let tagTxn = new PlacesTagURITransaction(NetUtil.newURI(items[i].uri),
[ip.itemId]);
transactions.push(tagTxn);
continue;
}
// Adjust index to make sure items are pasted in the correct position.
// If index is DEFAULT_INDEX, items are just appended.
- if (ip.index != PlacesUtils.bookmarks.DEFAULT_INDEX)
- insertionIndex = ip.index + i;
+ if (index != PlacesUtils.bookmarks.DEFAULT_INDEX)
+ index += i;
// If this is not a copy, check for safety that we can move the source,
// otherwise report an error and fallback to a copy.
if (action != "copy" && !PlacesControllerDragHelper.canMoveUnwrappedNode(items[i])) {
Components.utils.reportError("Tried to move an unmovable Places " +
"node, reverting to a copy operation.");
action = "copy";
}
transactions.push(
PlacesUIUtils.makeTransaction(items[i], type, ip.itemId,
- insertionIndex, action == "copy")
+ index, action == "copy")
);
}
let aggregatedTxn = new PlacesAggregatedTransaction("Paste", transactions);
PlacesUtils.transactionManager.doTransaction(aggregatedTxn);
for (let i = 0; i < transactions.length; ++i) {
itemsToSelect.push(
- PlacesUtils.bookmarks.getIdForItemAt(ip.itemId, ip.index + i)
+ PlacesUtils.bookmarks.getIdForItemAt(ip.itemId, insertionIndex + i)
);
}
}
// Cut/past operations are not repeatable, so clear the clipboard.
if (action == "cut") {
this._clearClipboard();
}
@@ -1588,23 +1614,23 @@ var PlacesControllerDragHelper = {
let spec = uri ? uri.spec : "about:blank";
nodes = [{ uri: spec,
title: data.label,
type: PlacesUtils.TYPE_X_MOZ_URL}];
} else
throw new Error("bogus data was passed as a tab");
for (let unwrapped of nodes) {
- let index = insertionPoint.index;
+ let index = await insertionPoint.getIndex();
// Adjust insertion index to prevent reversal of dragged items. When you
// drag multiple elts upward: need to increment index or each successive
// elt will be inserted at the same index, each above the previous.
let dragginUp = insertionPoint.itemId == unwrapped.parent &&
- index < PlacesUtils.bookmarks.getItemIndex(unwrapped.id);
+ index < (await PlacesUtils.bookmarks.fetch(unwrapped.itemGuid)).index;
if (index != -1 && dragginUp)
index += movedCount++;
// If dragging over a tag container we should tag the item.
if (insertionPoint.isTag) {
let uri = NetUtil.newURI(unwrapped.uri);
let tagItemId = insertionPoint.itemId;
if (PlacesUIUtils.useAsyncTransactions)
--- a/browser/components/places/content/editBookmarkOverlay.js
+++ b/browser/components/places/content/editBookmarkOverlay.js
@@ -1006,27 +1006,28 @@ var gEditItemOverlay = {
async newFolder() {
let ip = this._folderTree.insertionPoint;
// default to the bookmarks menu folder
if (!ip || ip.itemId == PlacesUIUtils.allBookmarksFolderId) {
ip = new InsertionPoint(PlacesUtils.bookmarksMenuFolderId,
PlacesUtils.bookmarks.DEFAULT_INDEX,
- Ci.nsITreeView.DROP_ON);
+ Ci.nsITreeView.DROP_ON, null, null,
+ PlacesUtils.bookmarks.menuGuid);
}
// XXXmano: add a separate "New Folder" string at some point...
let title = this._element("newFolderButton").label;
if (PlacesUIUtils.useAsyncTransactions) {
let parentGuid = await ip.promiseGuid();
- await PlacesTransactions.NewFolder({ parentGuid, title, index: ip.index })
+ await PlacesTransactions.NewFolder({ parentGuid, title, index: await ip.getIndex() })
.transact().catch(Components.utils.reportError);
} else {
- let txn = new PlacesCreateFolderTransaction(title, ip.itemId, ip.index);
+ let txn = new PlacesCreateFolderTransaction(title, ip.itemId, await ip.getIndex());
PlacesUtils.transactionManager.doTransaction(txn);
}
this._folderTree.focus();
this._folderTree.selectItems([ip.itemId]);
PlacesUtils.asContainer(this._folderTree.selectedNode).containerOpen = true;
this._folderTree.selectItems([this._lastNewItem]);
this._folderTree.startEditing(this._folderTree.view.selection.currentIndex,
--- a/browser/components/places/content/menu.xml
+++ b/browser/components/places/content/menu.xml
@@ -88,17 +88,19 @@
let eltY = elt.boxObject.y - scrollboxOffset;
let eltHeight = elt.boxObject.height;
if (!elt._placesNode) {
// If we are dragging over a non places node drop at the end.
dropPoint.ip = new InsertionPoint(
PlacesUtils.getConcreteItemId(resultNode),
-1,
- Ci.nsITreeView.DROP_ON);
+ Ci.nsITreeView.DROP_ON,
+ null,
+ PlacesUtils.getConcreteItemGuid(resultNode));
// We can set folderElt if we are dropping over a static menu that
// has an internal placespopup.
let isMenu = elt.localName == "menu" ||
(elt.localName == "toolbarbutton" &&
elt.getAttribute("type") == "menu");
if (isMenu && elt.lastChild &&
elt.lastChild.hasAttribute("placespopup"))
dropPoint.folderElt = elt;
@@ -113,47 +115,52 @@
// This is a folder or a tag container.
if (eventY - eltY < eltHeight * 0.20) {
// If mouse is in the top part of the element, drop above folder.
dropPoint.ip = new InsertionPoint(
PlacesUtils.getConcreteItemId(resultNode),
-1,
Ci.nsITreeView.DROP_BEFORE,
tagName,
- elt._placesNode.itemId);
+ elt._placesNode,
+ PlacesUtils.getConcreteItemGuid(resultNode));
return dropPoint;
} else if (eventY - eltY < eltHeight * 0.80) {
// If mouse is in the middle of the element, drop inside folder.
dropPoint.ip = new InsertionPoint(
PlacesUtils.getConcreteItemId(elt._placesNode),
-1,
Ci.nsITreeView.DROP_ON,
- tagName);
+ tagName,
+ null,
+ PlacesUtils.getConcreteItemGuid(elt._placesNode));
dropPoint.folderElt = elt;
return dropPoint;
}
} else if (eventY - eltY <= eltHeight / 2) {
// This is a non-folder node or a readonly folder.
// If the mouse is above the middle, drop above this item.
dropPoint.ip = new InsertionPoint(
PlacesUtils.getConcreteItemId(resultNode),
-1,
Ci.nsITreeView.DROP_BEFORE,
tagName,
- elt._placesNode.itemId);
+ elt._placesNode,
+ PlacesUtils.getConcreteItemGuid(resultNode));
return dropPoint;
}
// Drop below the item.
dropPoint.ip = new InsertionPoint(
PlacesUtils.getConcreteItemId(resultNode),
-1,
Ci.nsITreeView.DROP_AFTER,
tagName,
- elt._placesNode.itemId);
+ elt._placesNode,
+ PlacesUtils.getConcreteItemGuid(resultNode));
return dropPoint;
]]></body>
</method>
<!-- Sub-menus should be opened when the mouse drags over them, and closed
when the mouse drags off. The overFolder object manages opening and
closing of folders when the mouse hovers. -->
<field name="_overFolder"><![CDATA[({
--- a/browser/components/places/content/tree.xml
+++ b/browser/components/places/content/tree.xml
@@ -466,17 +466,17 @@
<method name="_getInsertionPoint">
<parameter name="index"/>
<parameter name="orientation"/>
<body><![CDATA[
var result = this.result;
var resultview = this.view;
var container = result.root;
- var dropNearItemId = -1;
+ var dropNearNode = null;
NS_ASSERT(container, "null container");
// When there's no selection, assume the container is the container
// the view is populated from (i.e. the result's itemId).
if (index != -1) {
var lastSelected = resultview.nodeForTreeIndex(index);
if (resultview.isContainer(index) && orientation == Ci.nsITreeView.DROP_ON) {
// If the last selected item is an open container, append _into_
// it, rather than insert adjacent to it.
@@ -510,17 +510,17 @@
index = -1;
} else if (queryOptions.excludeItems ||
queryOptions.excludeQueries ||
queryOptions.excludeReadOnlyFolders) {
// Some item may be invisible, insert near last selected one.
// We don't replace index here to avoid requests to the db,
// instead it will be calculated later by the controller.
index = -1;
- dropNearItemId = lastSelected.itemId;
+ dropNearNode = lastSelected;
} else {
var lsi = container.getChildIndex(lastSelected);
index = orientation == Ci.nsITreeView.DROP_BEFORE ? lsi : lsi + 1;
}
}
}
if (PlacesControllerDragHelper.disallowInsertion(container))
@@ -532,17 +532,18 @@
tagName = container.title;
if (!tagName)
return null;
}
return new InsertionPoint(PlacesUtils.getConcreteItemId(container),
index, orientation,
tagName,
- dropNearItemId);
+ dropNearNode,
+ PlacesUtils.getConcreteItemGuid(container));
]]></body>
</method>
<!-- nsIPlacesView -->
<method name="selectAll">
<body><![CDATA[
this.view.selection.selectAll();
]]></body>
--- a/browser/components/places/content/treeView.js
+++ b/browser/components/places/content/treeView.js
@@ -1368,17 +1368,17 @@ PlacesTreeView.prototype = {
return false;
let ip = this._getInsertionPoint(aRow, aOrientation);
return ip && PlacesControllerDragHelper.canDrop(ip, aDataTransfer);
},
_getInsertionPoint: function PTV__getInsertionPoint(index, orientation) {
let container = this._result.root;
- let dropNearItemId = -1;
+ let dropNearNode = null;
// When there's no selection, assume the container is the container
// the view is populated from (i.e. the result's itemId).
if (index != -1) {
let lastSelected = this.nodeForTreeIndex(index);
if (this.isContainer(index) && orientation == Ci.nsITreeView.DROP_ON) {
// If the last selected item is an open container, append _into_
// it, rather than insert adjacent to it.
container = lastSelected;
@@ -1416,17 +1416,17 @@ PlacesTreeView.prototype = {
index = -1;
} else if (queryOptions.excludeItems ||
queryOptions.excludeQueries ||
queryOptions.excludeReadOnlyFolders) {
// Some item may be invisible, insert near last selected one.
// We don't replace index here to avoid requests to the db,
// instead it will be calculated later by the controller.
index = -1;
- dropNearItemId = lastSelected.itemId;
+ dropNearNode = lastSelected;
} else {
let lsi = container.getChildIndex(lastSelected);
index = orientation == Ci.nsITreeView.DROP_BEFORE ? lsi : lsi + 1;
}
}
}
if (PlacesControllerDragHelper.disallowInsertion(container))
@@ -1438,17 +1438,18 @@ PlacesTreeView.prototype = {
tagName = container.title;
if (!tagName)
return null;
}
return new InsertionPoint(PlacesUtils.getConcreteItemId(container),
index, orientation,
tagName,
- dropNearItemId);
+ dropNearNode,
+ PlacesUtils.getConcreteItemGuid(container));
},
drop: function PTV_drop(aRow, aOrientation, aDataTransfer) {
// We are responsible for translating the |index| and |orientation|
// parameters into a container id and index within the container,
// since this information is specific to the tree view.
let ip = this._getInsertionPoint(aRow, aOrientation);
if (ip) {