Bug 1252250 - Implement browser.bookmarks.removeTree(), r=kmag r=mak

MozReview-Commit-ID: HyjJrEjcsZu
This commit is contained in:
bsilverberg 2016-03-03 08:00:42 -05:00
parent 41df2edda1
commit e41f4463e6
5 changed files with 75 additions and 7 deletions

View File

@ -193,6 +193,18 @@ extensions.registerSchemaAPI("bookmarks", "bookmarks", (extension, context) => {
};
// The API doesn't give you the old bookmark at the moment
try {
return Bookmarks.remove(info, {preventRemovalOfNonEmptyFolders: true}).then(result => {});
} catch (e) {
return Promise.reject({message: `Invalid bookmark: ${JSON.stringify(info)}`});
}
},
removeTree: function(id) {
let info = {
guid: id,
};
try {
return Bookmarks.remove(info).then(result => {});
} catch (e) {

View File

@ -400,7 +400,6 @@
},
{
"name": "removeTree",
"unsupported": true,
"type": "function",
"description": "Recursively removes a bookmark folder.",
"async": "callback",

View File

@ -156,7 +156,15 @@ function backgroundScript() {
}).then(results => {
browser.test.assertTrue(results.length >= 9, "At least as many bookmarks as added were returned by search({})");
return browser.bookmarks.getSubTree(createdFolderId);
return Promise.resolve().then(() => {
return browser.bookmarks.remove(createdFolderId);
}).then(expectedError, error => {
browser.test.assertTrue(
error.message.includes("Cannot remove a non-empty folder"),
"Expected error thrown when trying to remove a non-empty folder"
);
return browser.bookmarks.getSubTree(createdFolderId);
});
});
}).then(results => {
browser.test.assertEq(1, results.length, "Expected number of nodes returned by getSubTree");
@ -334,9 +342,37 @@ function backgroundScript() {
browser.test.assertEq("Toolbar Item", results[3].title, "Bookmark has the expected title");
browser.test.assertEq("Menu Item", results[4].title, "Bookmark has the expected title");
return browser.bookmarks.search({});
}).then(results => {
let startBookmarkCount = results.length;
return browser.bookmarks.search({title: "Mozilla Folder"}).then(result => {
return browser.bookmarks.removeTree(result[0].id);
}).then(() => {
return browser.bookmarks.search({}).then(results => {
browser.test.assertEq(
startBookmarkCount - 4,
results.length,
"Expected number of results returned after removeTree");
});
});
}).then(() => {
return browser.bookmarks.create({title: "Empty Folder"});
}).then(result => {
let emptyFolderId = result.id;
browser.test.assertEq("Empty Folder", result.title, "Folder has the expected title");
return browser.bookmarks.remove(emptyFolderId).then(() => {
return browser.bookmarks.get(emptyFolderId).then(expectedError, error => {
browser.test.assertTrue(
error.message.includes("Bookmark not found"),
"Expected error thrown when trying to get a removed folder"
);
});
});
}).then(() => {
return browser.test.notifyPass("bookmarks");
}).catch(error => {
browser.test.fail(`Error: ${String(error)} :: ${error.stack}`);
browser.test.notifyFail("bookmarks");
});
}

View File

@ -372,13 +372,18 @@ var Bookmarks = Object.freeze({
* @param guidOrInfo
* The globally unique identifier of the item to remove, or an
* object representing it, as defined above.
* @param {Object} [options={}]
* Additional options that can be passed to the function.
* Currently supports preventRemovalOfNonEmptyFolders which
* will cause an exception to be thrown if attempting to remove
* a folder that is not empty.
*
* @return {Promise} resolved when the removal is complete.
* @resolves to an object representing the removed bookmark.
* @rejects if the provided guid doesn't match any existing bookmark.
* @throws if the arguments are invalid.
*/
remove(guidOrInfo) {
remove(guidOrInfo, options={}) {
let info = guidOrInfo;
if (!info)
throw new Error("Input should be a valid object");
@ -400,7 +405,7 @@ var Bookmarks = Object.freeze({
if (!item)
throw new Error("No bookmarks found for the provided GUID.");
item = yield removeBookmark(item);
item = yield removeBookmark(item, options);
// Notify onItemRemoved to listeners.
let observers = PlacesUtils.bookmarks.getObservers();
@ -1068,7 +1073,7 @@ function fetchBookmarksByParent(info) {
////////////////////////////////////////////////////////////////////////////////
// Remove implementation.
function removeBookmark(item) {
function removeBookmark(item, options) {
return PlacesUtils.withConnectionWrapper("Bookmarks.jsm: updateBookmark",
Task.async(function*(db) {
@ -1076,8 +1081,12 @@ function removeBookmark(item) {
yield db.executeTransaction(function* transaction() {
// If it's a folder, remove its contents first.
if (item.type == Bookmarks.TYPE_FOLDER)
if (item.type == Bookmarks.TYPE_FOLDER) {
if (options.preventRemovalOfNonEmptyFolders && item._childCount > 0) {
throw new Error("Cannot remove a non-empty folder.");
}
yield removeFoldersContents(db, [item.guid]);
}
// Remove annotations first. If it's a tag, we can avoid paying that cost.
if (!isUntagging) {

View File

@ -55,7 +55,7 @@ add_task(function* remove_roots_fail() {
}
});
add_task(function* remove_normal_folder_undes_root_succeeds() {
add_task(function* remove_normal_folder_under_root_succeeds() {
let folder = yield PlacesUtils.bookmarks.insert({ parentGuid: PlacesUtils.bookmarks.rootGuid,
type: PlacesUtils.bookmarks.TYPE_FOLDER });
checkBookmarkObject(folder);
@ -151,6 +151,7 @@ add_task(function* test_nested_contents_removed() {
Assert.strictEqual((yield PlacesUtils.bookmarks.fetch(folder2.guid)), null);
Assert.strictEqual((yield PlacesUtils.bookmarks.fetch(sep.guid)), null);
});
add_task(function* remove_folder_empty_title() {
let bm1 = yield PlacesUtils.bookmarks.insert({ parentGuid: PlacesUtils.bookmarks.unfiledGuid,
type: PlacesUtils.bookmarks.TYPE_FOLDER,
@ -182,6 +183,17 @@ add_task(function* remove_separator() {
Assert.ok(!("title" in bm2));
});
add_task(function* test_nested_content_fails_when_not_allowed() {
let folder1 = yield PlacesUtils.bookmarks.insert({ parentGuid: PlacesUtils.bookmarks.unfiledGuid,
type: PlacesUtils.bookmarks.TYPE_FOLDER,
title: "a folder" });
let folder2 = yield PlacesUtils.bookmarks.insert({ parentGuid: folder1.guid,
type: PlacesUtils.bookmarks.TYPE_FOLDER,
title: "a folder" });
Assert.rejects(PlacesUtils.bookmarks.remove(folder1, {preventRemovalOfNonEmptyFolders: true}),
/Cannot remove a non-empty folder./);
});
function run_test() {
run_next_test();
}