Bug 1302661 - Add multiple bookmark items when multiple URLs are dropped as single item. r=mak

This commit is contained in:
Tooru Fujisawa 2014-02-06 01:38:31 +09:00
Родитель 63b579c075
Коммит d2037e755b
2 изменённых файлов: 114 добавлений и 58 удалений

Просмотреть файл

@ -1488,29 +1488,31 @@ var PlacesControllerDragHelper = {
continue;
let data = dt.mozGetDataAt(flavor, i);
let dragged;
let nodes;
try {
dragged = PlacesUtils.unwrapNodes(data, flavor)[0];
nodes = PlacesUtils.unwrapNodes(data, flavor);
} catch (e) {
return false;
}
// Only bookmarks and urls can be dropped into tag containers.
if (ip.isTag &&
dragged.type != PlacesUtils.TYPE_X_MOZ_URL &&
(dragged.type != PlacesUtils.TYPE_X_MOZ_PLACE ||
(dragged.uri && dragged.uri.startsWith("place:")) ))
return false;
for (let dragged of nodes) {
// Only bookmarks and urls can be dropped into tag containers.
if (ip.isTag &&
dragged.type != PlacesUtils.TYPE_X_MOZ_URL &&
(dragged.type != PlacesUtils.TYPE_X_MOZ_PLACE ||
(dragged.uri && dragged.uri.startsWith("place:")) ))
return false;
// The following loop disallows the dropping of a folder on itself or
// on any of its descendants.
if (dragged.type == PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER ||
(dragged.uri && dragged.uri.startsWith("place:")) ) {
let parentId = ip.itemId;
while (parentId != PlacesUtils.placesRootId) {
if (dragged.concreteId == parentId || dragged.id == parentId)
return false;
parentId = PlacesUtils.bookmarks.getFolderIdForItem(parentId);
// The following loop disallows the dropping of a folder on itself or
// on any of its descendants.
if (dragged.type == PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER ||
(dragged.uri && dragged.uri.startsWith("place:")) ) {
let parentId = ip.itemId;
while (parentId != PlacesUtils.placesRootId) {
if (dragged.concreteId == parentId || dragged.id == parentId)
return false;
parentId = PlacesUtils.bookmarks.getFolderIdForItem(parentId);
}
}
}
}
@ -1576,63 +1578,77 @@ var PlacesControllerDragHelper = {
let parentGuid = PlacesUIUtils.useAsyncTransactions ?
(yield insertionPoint.promiseGuid()) : null;
let tagName = insertionPoint.tagName;
// Following flavors may contain duplicated data.
let duplicable = new Map();
duplicable.set(PlacesUtils.TYPE_UNICODE, new Set());
duplicable.set(PlacesUtils.TYPE_X_MOZ_URL, new Set());
for (let i = 0; i < dropCount; ++i) {
let flavor = this.getFirstValidFlavor(dt.mozTypesAt(i));
if (!flavor)
return;
let data = dt.mozGetDataAt(flavor, i);
let unwrapped;
if (duplicable.has(flavor)) {
let handled = duplicable.get(flavor);
if (handled.has(data))
continue;
handled.add(data);
}
let nodes;
if (flavor != TAB_DROP_TYPE) {
// There's only ever one in the D&D case.
unwrapped = PlacesUtils.unwrapNodes(data, flavor)[0];
nodes = PlacesUtils.unwrapNodes(data, flavor);
} else if (data instanceof XULElement && data.localName == "tab" &&
data.ownerGlobal instanceof ChromeWindow) {
let uri = data.linkedBrowser.currentURI;
let spec = uri ? uri.spec : "about:blank";
unwrapped = { uri: spec,
title: data.label,
type: PlacesUtils.TYPE_X_MOZ_URL};
nodes = [{ uri: spec,
title: data.label,
type: PlacesUtils.TYPE_X_MOZ_URL}];
} else
throw new Error("bogus data was passed as a tab");
let index = insertionPoint.index;
for (let unwrapped of nodes) {
let index = insertionPoint.index;
// 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);
if (index != -1 && dragginUp)
index += movedCount++;
// 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);
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)
transactions.push(PlacesTransactions.Tag({ uri, tag: tagName }));
else
transactions.push(new PlacesTagURITransaction(uri, [tagItemId]));
} else {
// 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 && !PlacesControllerDragHelper.canMoveUnwrappedNode(unwrapped)) {
Components.utils.reportError("Tried to move an unmovable Places " +
"node, reverting to a copy operation.");
doCopy = true;
}
if (PlacesUIUtils.useAsyncTransactions) {
transactions.push(
PlacesUIUtils.getTransactionForData(unwrapped,
flavor,
parentGuid,
index,
doCopy));
// 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)
transactions.push(PlacesTransactions.Tag({ uri, tag: tagName }));
else
transactions.push(new PlacesTagURITransaction(uri, [tagItemId]));
} else {
transactions.push(PlacesUIUtils.makeTransaction(unwrapped,
flavor, insertionPoint.itemId,
index, doCopy));
// 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 && !PlacesControllerDragHelper.canMoveUnwrappedNode(unwrapped)) {
Components.utils.reportError("Tried to move an unmovable Places " +
"node, reverting to a copy operation.");
doCopy = true;
}
if (PlacesUIUtils.useAsyncTransactions) {
transactions.push(
PlacesUIUtils.getTransactionForData(unwrapped,
flavor,
parentGuid,
index,
doCopy));
} else {
transactions.push(PlacesUIUtils.makeTransaction(unwrapped,
flavor, insertionPoint.itemId,
index, doCopy));
}
}
}
}

Просмотреть файл

@ -52,7 +52,46 @@ add_task(function* test() {
// Verify that we removed the bookmark successfully.
ok(!PlacesUtils.bookmarks.isBookmarked(uri), "URI should be removed");
}
};
/**
* Simulates a drop of multiple URIs onto the bookmarks bar.
*
* @param aEffect
* The effect to use for the drop operation: move, copy, or link.
* @param aMimeType
* The mime type to use for the drop operation.
*/
let simulateDragDropMultiple = function(aEffect, aMimeType) {
const uriSpecs = [
"http://www.mozilla.org/C54263C6-A484-46CF-8E2B-FE131586348A",
"http://www.mozilla.org/71381257-61E6-4376-AF7C-BF3C5FD8870D",
"http://www.mozilla.org/091A88BD-5743-4C16-A005-3D2EA3A3B71E"
];
let uris = uriSpecs.map(spec => makeURI(spec));
let data;
if (aMimeType == "text/x-moz-url")
data = uriSpecs.map(spec => spec + "\n" + spec).join("\n");
else
data = uriSpecs.join("\n");
EventUtils.synthesizeDrop(placesItems.childNodes[0],
placesItems,
[[{type: aMimeType,
data}]],
aEffect, window);
// Verify that the drop produces exactly one bookmark per each URL.
for (let uri of uris) {
let bookmarkIds = PlacesUtils.bookmarks
.getBookmarkIdsForURI(uri);
ok(bookmarkIds.length == 1, "There should be exactly one bookmark");
PlacesUtils.bookmarks.removeItem(bookmarkIds[0]);
// Verify that we removed the bookmark successfully.
ok(!PlacesUtils.bookmarks.isBookmarked(uri), "URI should be removed");
}
};
// Simulate a bookmark drop for all of the mime types and effects.
let mimeTypes = ["text/plain", "text/unicode", "text/x-moz-url"];
@ -60,6 +99,7 @@ add_task(function* test() {
effects.forEach(function(effect) {
mimeTypes.forEach(function(mimeType) {
simulateDragDrop(effect, mimeType);
simulateDragDropMultiple(effect, mimeType);
});
});
});