--- a/services/sync/tps/extensions/tps/resource/modules/bookmarks.jsm
+++ b/services/sync/tps/extensions/tps/resource/modules/bookmarks.jsm
@@ -14,27 +14,20 @@ const {classes: Cc, interfaces: Ci, util
Cu.import("resource://gre/modules/PlacesBackups.jsm");
Cu.import("resource://gre/modules/PlacesSyncUtils.jsm");
Cu.import("resource://gre/modules/PlacesUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://services-common/async.js");
Cu.import("resource://tps/logger.jsm");
-var DumpBookmarks = function TPS_Bookmarks__DumpBookmarks() {
- let cb = Async.makeSpinningCallback();
- PlacesBackups.getBookmarksTree().then(result => {
- let [bookmarks, ] = result;
- Logger.logInfo("Dumping Bookmarks...\n" + JSON.stringify(bookmarks) + "\n\n");
- cb(null);
- }).catch(error => {
- cb(error);
- });
- cb.wait();
-};
+async function DumpBookmarks() {
+ let [bookmarks, ] = await PlacesBackups.getBookmarksTree()
+ Logger.logInfo("Dumping Bookmarks...\n" + JSON.stringify(bookmarks, undefined, 2) + "\n\n");
+}
/**
* extend, causes a child object to inherit from a parent
*/
function extend(child, supertype) {
child.prototype.__proto__ = supertype.prototype;
}
@@ -80,23 +73,29 @@ function PlacesItem(props) {
}
/**
* Instance methods for generic places items.
*/
PlacesItem.prototype = {
// an array of possible root folders for places items
_bookmarkFolders: {
- "places": "placesRoot",
- "menu": "bookmarksMenuFolder",
- "tags": "tagFolder",
- "unfiled": "unfiledBookmarksFolder",
- "toolbar": "toolbarFolder",
+ "places": PlacesUtils.bookmarks.rootGuid,
+ "menu": PlacesUtils.bookmarks.menuGuid,
+ "tags": PlacesUtils.bookmarks.tagsGuid,
+ "unfiled": PlacesUtils.bookmarks.unfiledGuid,
+ "toolbar": PlacesUtils.bookmarks.toolbarGuid,
},
+ _typeMap: new Map([
+ [PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER, PlacesUtils.bookmarks.TYPE_FOLDER],
+ [PlacesUtils.TYPE_X_MOZ_PLACE_SEPARATOR, PlacesUtils.bookmarks.TYPE_SEPARATOR],
+ [PlacesUtils.TYPE_X_MOZ_PLACE, PlacesUtils.bookmarks.TYPE_BOOKMARK],
+ ]),
+
toString() {
var that = this;
var props = ["uri", "title", "location", "folder", "feedUri", "siteUri", "livemark"];
var string = (this.props.type ? this.props.type + " " : "") +
"(" +
(function() {
var ret = [];
for (var i in props) {
@@ -104,79 +103,71 @@ PlacesItem.prototype = {
ret.push(props[i] + ": " + that.props[props[i]])
}
}
return ret;
})().join(", ") + ")";
return string;
},
- GetSyncId() {
- let guid = Async.promiseSpinningly(PlacesUtils.promiseItemGuid(this.props.item_id));
- return PlacesSyncUtils.bookmarks.guidToSyncId(guid);
- },
-
/**
- * GetPlacesNodeId
+ * GetPlacesChildGuid
*
- * Finds the id of the an item with the specified properties in the places
- * database.
+ * Finds the guid of the an item with the specified properties in the places
+ * database under the specified parent.
*
- * @param folder The id of the folder to search
+ * @param folder The guid of the folder to search
* @param type The type of the item to find, or null to match any item;
- * this is one of the values listed at
- * https://developer.mozilla.org/en/nsINavHistoryResultNode#Constants
+ * this is one of the PlacesUtils.bookmarks.TYPE_* values
* @param title The title of the item to find, or null to match any title
* @param uri The uri of the item to find, or null to match any uri
*
- * @return the node id if the item was found, otherwise -1
+ * @return the node id if the item was found, otherwise null
*/
- GetPlacesNodeId(folder, type, title, uri) {
- let node_id = -1;
-
- let options = PlacesUtils.history.getNewQueryOptions();
- let query = PlacesUtils.history.getNewQuery();
- query.setFolders([folder], 1);
- let result = PlacesUtils.history.executeQuery(query, options);
- let rootNode = result.root;
- rootNode.containerOpen = true;
-
- for (let j = 0; j < rootNode.childCount; j++) {
- let node = rootNode.getChild(j);
+ async GetPlacesChildGuid(folder, type, title, uri) {
+ let children = (await PlacesUtils.promiseBookmarksTree(folder)).children;
+ if (!children) {
+ return null;
+ }
+ let guid = null;
+ for (let node of children) {
if (node.title == title) {
- if (type == null || type == undefined || node.type == type)
- if (uri == undefined || uri == null || node.uri.spec == uri.spec)
- node_id = node.itemId;
+ let nodeType = this._typeMap.get(node.type);
+ if (type == null || type == undefined || nodeType == type)
+ if (uri == undefined || uri == null || node.uri.spec == uri.spec) {
+ // Note that this is suspect as we return the *last* matching
+ // child, which some tests rely on (ie, an early-return here causes
+ // at least 1 test to fail). But that's a yak for another day.
+ guid = node.guid;
+ }
}
}
- rootNode.containerOpen = false;
-
- return node_id;
+ return guid;
},
/**
* IsAdjacentTo
*
* Determines if this object is immediately adjacent to another.
*
* @param itemName The name of the other object; this may be any kind of
* places item
* @param relativePos The relative position of the other object. If -1,
* it means the other object should precede this one, if +1,
* the other object should come after this one
* @return true if this object is immediately adjacent to the other object,
* otherwise false
*/
- IsAdjacentTo(itemName, relativePos) {
- Logger.AssertTrue(this.props.folder_id != -1 && this.props.item_id != -1,
- "Either folder_id or item_id was invalid");
- let other_id = this.GetPlacesNodeId(this.props.folder_id, null, itemName);
- Logger.AssertTrue(other_id != -1, "item " + itemName + " not found");
- let other_pos = PlacesUtils.bookmarks.getItemIndex(other_id);
- let this_pos = PlacesUtils.bookmarks.getItemIndex(this.props.item_id);
+ async IsAdjacentTo(itemName, relativePos) {
+ Logger.AssertTrue(this.props.folder_id != -1 && this.props.guid != null,
+ "Either folder_id or guid was invalid");
+ let otherGuid = await this.GetPlacesChildGuid(this.props.parentGuid, null, itemName);
+ Logger.AssertTrue(otherGuid, "item " + itemName + " not found");
+ let other_pos = (await PlacesUtils.bookmarks.fetch(otherGuid)).index;
+ let this_pos = (await PlacesUtils.bookmarks.fetch(this.props.guid)).index;
if (other_pos + relativePos != this_pos) {
Logger.logPotentialError("Invalid position - " +
(this.props.title ? this.props.title : this.props.folder) +
" not " + (relativePos == 1 ? "after " : "before ") + itemName +
" for " + this.toString());
return false;
}
return true;
@@ -184,118 +175,117 @@ PlacesItem.prototype = {
/**
* GetItemIndex
*
* Gets the item index for this places item.
*
* @return the item index, or -1 if there's an error
*/
- GetItemIndex() {
- if (this.props.item_id == -1)
+ async GetItemIndex() {
+ if (this.props.guid == null)
return -1;
- return PlacesUtils.bookmarks.getItemIndex(this.props.item_id);
+ return (await PlacesUtils.bookmarks.fetch(this.props.guid)).index;
},
/**
* GetFolder
*
- * Gets the folder id for the specified bookmark folder
+ * Gets the folder guid for the specified bookmark folder
*
* @param location The full path of the folder, which must begin
* with one of the bookmark root folders
- * @return the folder id if the folder is found, otherwise -1
+ * @return the folder guid if the folder is found, otherwise null
*/
- GetFolder(location) {
+ async GetFolder(location) {
let folder_parts = location.split("/");
if (!(folder_parts[0] in this._bookmarkFolders)) {
- return -1;
+ return null;
}
- let folder_id = PlacesUtils.bookmarks[this._bookmarkFolders[folder_parts[0]]];
+ let folderGuid = this._bookmarkFolders[folder_parts[0]];
for (let i = 1; i < folder_parts.length; i++) {
- let subfolder_id = this.GetPlacesNodeId(
- folder_id,
- Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER,
+ let guid = await this.GetPlacesChildGuid(
+ folderGuid,
+ PlacesUtils.bookmarks.TYPE_FOLDER,
folder_parts[i]);
- if (subfolder_id == -1) {
- return -1;
+ if (guid == null) {
+ return null;
}
- folder_id = subfolder_id;
+ folderGuid = guid;
}
- return folder_id;
+ return folderGuid;
},
/**
* CreateFolder
*
* Creates a bookmark folder.
*
* @param location The full path of the folder, which must begin
* with one of the bookmark root folders
* @return the folder id if the folder was created, otherwise -1
*/
- CreateFolder(location) {
+ async CreateFolder(location) {
let folder_parts = location.split("/");
if (!(folder_parts[0] in this._bookmarkFolders)) {
return -1;
}
- let folder_id = PlacesUtils.bookmarks[this._bookmarkFolders[folder_parts[0]]];
+ let folderGuid = this._bookmarkFolders[folder_parts[0]];
for (let i = 1; i < folder_parts.length; i++) {
- let subfolder_id = this.GetPlacesNodeId(
- folder_id,
- Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER,
- folder_parts[i]);
- if (subfolder_id == -1) {
- folder_id = PlacesUtils.bookmarks.createFolder(folder_id,
- folder_parts[i], -1);
+ let subfolderGuid = await this.GetPlacesChildGuid(
+ folderGuid,
+ PlacesUtils.bookmarks.TYPE_FOLDER,
+ folder_parts[i]
+ );
+ if (subfolderGuid == null) {
+ let {guid} = await PlacesUtils.bookmarks.insert({parentGuid: folderGuid,
+ name: folder_parts[i],
+ type: PlacesUtils.bookmarks.TYPE_FOLDER});
+ folderGuid = guid;
} else {
- folder_id = subfolder_id;
+ folderGuid = subfolderGuid;
}
}
- return folder_id;
+ return folderGuid;
},
/**
* GetOrCreateFolder
*
* Locates the specified folder; if not found it is created.
*
* @param location The full path of the folder, which must begin
* with one of the bookmark root folders
* @return the folder id if the folder was found or created, otherwise -1
*/
- GetOrCreateFolder(location) {
- let folder_id = this.GetFolder(location);
- if (folder_id == -1)
- folder_id = this.CreateFolder(location);
- return folder_id;
+ async GetOrCreateFolder(location) {
+ let parentGuid = await this.GetFolder(location);
+ if (parentGuid == null)
+ parentGuid = await this.CreateFolder(location);
+ return parentGuid;
},
/**
* CheckDescription
*
* Compares the description of this places item with an expected
* description.
*
* @param expectedDescription The description this places item is
* expected to have
* @return true if the actual and expected descriptions match, or if
* there is no expected description; otherwise false
*/
- CheckDescription(expectedDescription) {
+ async CheckDescription(expectedDescription) {
if (expectedDescription != null) {
- let description = "";
- if (PlacesUtils.annotations.itemHasAnnotation(this.props.item_id,
- "bookmarkProperties/description")) {
- description = PlacesUtils.annotations.getItemAnnotation(
- this.props.item_id, "bookmarkProperties/description");
- }
- if (description != expectedDescription) {
+ // Use PlacesSyncUtils as it gives us the description.
+ let info = await PlacesSyncUtils.bookmarks.fetch(this.props.guid);
+ if (info.description != expectedDescription) {
Logger.logPotentialError("Invalid description, expected: " +
- expectedDescription + ", actual: " + description + " for " +
+ expectedDescription + ", actual: " + info.description + " for " +
this.toString());
return false;
}
}
return true;
},
/**
@@ -306,25 +296,26 @@ PlacesItem.prototype = {
* @param before The name of the places item that this item should be
before, or null if this check should be skipped
* @param after The name of the places item that this item should be
after, or null if this check should be skipped
* @param last_item_pos The index of the places item above this one,
* or null if this check should be skipped
* @return true if this item is in the correct position, otherwise false
*/
- CheckPosition(before, after, last_item_pos) {
+ async CheckPosition(before, after, last_item_pos) {
if (after)
- if (!this.IsAdjacentTo(after, 1)) return false;
+ if (!(await this.IsAdjacentTo(after, 1))) return false;
if (before)
- if (!this.IsAdjacentTo(before, -1)) return false;
+ if (!(await this.IsAdjacentTo(before, -1))) return false;
if (last_item_pos != null && last_item_pos > -1) {
- if (this.GetItemIndex() != last_item_pos + 1) {
+ let index = await this.GetItemIndex();
+ if (index != last_item_pos + 1) {
Logger.logPotentialError("Item not found at the expected index, got " +
- this.GetItemIndex() + ", expected " + (last_item_pos + 1) + " for " +
+ index + ", expected " + (last_item_pos + 1) + " for " +
this.toString());
return false;
}
}
return true;
},
/**
@@ -332,85 +323,95 @@ PlacesItem.prototype = {
*
* Moves this places item to a different folder.
*
* @param location The full path of the folder to which to move this
* places item, which must begin with one of the bookmark root
* folders; if null, no changes are made
* @return nothing if successful, otherwise an exception is thrown
*/
- SetLocation(location) {
+ async SetLocation(location) {
if (location != null) {
- let newfolder_id = this.GetOrCreateFolder(location);
- Logger.AssertTrue(newfolder_id != -1, "Location " + location +
+ let newfolderGuid = await this.GetOrCreateFolder(location);
+ Logger.AssertTrue(newfolderGuid, "Location " + location +
" doesn't exist; can't change item's location");
- PlacesUtils.bookmarks.moveItem(this.props.item_id, newfolder_id, -1);
- this.props.folder_id = newfolder_id;
+ await PlacesUtils.bookmarks.update({
+ guid: this.props.guid,
+ parentGuid: newfolderGuid,
+ index: PlacesUtils.bookmarks.DEFAULT_INDEX,
+ });
+ this.props.parentGuid = newfolderGuid;
}
},
/**
* SetDescription
*
* Updates the description for this places item.
*
* @param description The new description to set; if null, no changes are
* made
* @return nothing
*/
- SetDescription(description) {
+ async SetDescription(description) {
+ let itemId = await PlacesUtils.promiseItemId(this.props.guid);
+
if (description != null) {
if (description != "")
- PlacesUtils.annotations.setItemAnnotation(this.props.item_id,
+ PlacesUtils.annotations.setItemAnnotation(itemId,
"bookmarkProperties/description",
description,
0,
PlacesUtils.annotations.EXPIRE_NEVER);
else
- PlacesUtils.annotations.removeItemAnnotation(this.props.item_id,
+ PlacesUtils.annotations.removeItemAnnotation(itemId,
"bookmarkProperties/description");
}
},
/**
* SetPosition
*
* Updates the position of this places item within this item's current
* folder. Use SetLocation to change folders.
*
* @param position The new index this item should be moved to; if null,
* no changes are made; if -1, this item is moved to the bottom of
- * the current folder
+ * the current folder. Otherwise, must be a string which is the
+ * title of an existing item in the folder, who's current position
+ * is used as the index.
* @return nothing if successful, otherwise an exception is thrown
*/
- SetPosition(position) {
- if (position != null) {
- let newposition = -1;
- if (position != -1) {
- newposition = this.GetPlacesNodeId(this.props.folder_id,
- null, position);
- Logger.AssertTrue(newposition != -1, "position " + position +
- " is invalid; unable to change position");
- newposition = PlacesUtils.bookmarks.getItemIndex(newposition);
+ async SetPosition(position) {
+ if (position == null) {
+ return;
+ }
+ let index = -1;
+ if (position != -1) {
+ let existingGuid = await this.GetPlacesChildGuid(this.props.parentGuid,
+ null, position);
+ if (existingGuid) {
+ index = (await PlacesUtils.bookmarks.fetch(existingGuid)).index;
}
- PlacesUtils.bookmarks.moveItem(this.props.item_id,
- this.props.folder_id, newposition);
+ Logger.AssertTrue(index != -1, "position " + position +
+ " is invalid; unable to change position");
}
+ await PlacesUtils.bookmarks.update({guid: this.props.guid, index});
},
/**
* Update the title of this places item
*
* @param title The new title to set for this item; if null, no changes
* are made
* @return nothing
*/
- SetTitle(title) {
+ async SetTitle(title) {
if (title != null) {
- PlacesUtils.bookmarks.setItemTitle(this.props.item_id, title);
+ await PlacesUtils.bookmarks.update({guid: this.props.guid, title});
}
},
};
/**
* Bookmark class constructor. Initializes instance properties.
*/
function Bookmark(props) {
@@ -428,81 +429,63 @@ Bookmark.prototype = {
* SetKeyword
*
* Update this bookmark's keyword.
*
* @param keyword The keyword to set for this bookmark; if null, no
* changes are made
* @return nothing
*/
- SetKeyword(keyword) {
+ async SetKeyword(keyword) {
if (keyword != null) {
// Mirror logic from PlacesSyncUtils's updateBookmarkMetadata
- let entry = Async.promiseSpinningly(PlacesUtils.keywords.fetch({
- url: this.props.uri,
- }));
+ let entry = await PlacesUtils.keywords.fetch({url: this.props.uri});
if (entry) {
- Async.promiseSpinningly(PlacesUtils.keywords.remove(entry));
+ await PlacesUtils.keywords.remove(entry);
}
- Async.promiseSpinningly(PlacesUtils.keywords.insert({
- keyword,
- url: this.props.uri
- }));
+ await PlacesUtils.keywords.insert({keyword, url: this.props.uri});
}
},
/**
* SetLoadInSidebar
*
* Updates this bookmark's loadInSidebar property.
*
* @param loadInSidebar if true, the loadInSidebar property will be set,
* if false, it will be cleared, and any other value will result
* in no change
* @return nothing
*/
- SetLoadInSidebar(loadInSidebar) {
+ async SetLoadInSidebar(loadInSidebar) {
+ let itemId = await PlacesUtils.promiseItemId(this.props.guid);
if (loadInSidebar == true)
- PlacesUtils.annotations.setItemAnnotation(this.props.item_id,
+ PlacesUtils.annotations.setItemAnnotation(itemId,
"bookmarkProperties/loadInSidebar",
true,
0,
PlacesUtils.annotations.EXPIRE_NEVER);
else if (loadInSidebar == false)
- PlacesUtils.annotations.removeItemAnnotation(this.props.item_id,
+ PlacesUtils.annotations.removeItemAnnotation(itemId,
"bookmarkProperties/loadInSidebar");
},
/**
- * SetTitle
- *
- * Updates this bookmark's title.
- *
- * @param title The new title to set for this boomark; if null, no changes
- * are made
- * @return nothing
- */
- SetTitle(title) {
- if (title)
- PlacesUtils.bookmarks.setItemTitle(this.props.item_id, title);
- },
-
- /**
* SetUri
*
* Updates this bookmark's URI.
*
* @param uri The new URI to set for this boomark; if null, no changes
* are made
* @return nothing
*/
- SetUri(uri) {
+ async SetUri(uri) {
if (uri) {
- let newURI = Services.io.newURI(uri);
- PlacesUtils.bookmarks.changeBookmarkURI(this.props.item_id, newURI);
+ let url = Services.io.newURI(uri);
+ await PlacesUtils.bookmarks.update({guid: this.props.guid, url})
}
},
/**
* SetTags
*
* Updates this bookmark's tags.
*
@@ -523,138 +506,138 @@ Bookmark.prototype = {
/**
* Create
*
* Creates the bookmark described by this object's properties.
*
* @return the id of the created bookmark
*/
- Create() {
- this.props.folder_id = this.GetOrCreateFolder(this.props.location);
- Logger.AssertTrue(this.props.folder_id != -1, "Unable to create " +
+ async Create() {
+ this.props.parentGuid = await this.GetOrCreateFolder(this.props.location);
+ Logger.AssertTrue(this.props.parentGuid, "Unable to create " +
"bookmark, error creating folder " + this.props.location);
let bookmarkURI = Services.io.newURI(this.props.uri);
- this.props.item_id = PlacesUtils.bookmarks.insertBookmark(this.props.folder_id,
- bookmarkURI,
- -1,
- this.props.title);
- this.SetKeyword(this.props.keyword);
- this.SetDescription(this.props.description);
- this.SetLoadInSidebar(this.props.loadInSidebar);
- this.SetTags(this.props.tags);
- return this.props.item_id;
+ let {guid} = await PlacesUtils.bookmarks.insert({parentGuid: this.props.parentGuid,
+ url: bookmarkURI,
+ title: this.props.title});
+ this.props.guid = guid;
+ await this.SetKeyword(this.props.keyword);
+ await this.SetDescription(this.props.description);
+ await this.SetLoadInSidebar(this.props.loadInSidebar);
+ await this.SetTags(this.props.tags);
+ return this.props.guid;
},
/**
* Update
*
* Updates this bookmark's properties according the properties on this
* object's 'updateProps' property.
*
* @return nothing
*/
- Update() {
- Logger.AssertTrue(this.props.item_id != -1 && this.props.item_id != null,
- "Invalid item_id during Remove");
- this.SetDescription(this.updateProps.description);
- this.SetLoadInSidebar(this.updateProps.loadInSidebar);
- this.SetTitle(this.updateProps.title);
- this.SetUri(this.updateProps.uri);
- this.SetKeyword(this.updateProps.keyword);
- this.SetTags(this.updateProps.tags);
- this.SetLocation(this.updateProps.location);
- this.SetPosition(this.updateProps.position);
+ async Update() {
+ Logger.AssertTrue(this.props.guid, "Invalid guid during Update");
+ await this.SetDescription(this.updateProps.description);
+ await this.SetLoadInSidebar(this.updateProps.loadInSidebar);
+ await this.SetTitle(this.updateProps.title);
+ await this.SetUri(this.updateProps.uri);
+ await this.SetKeyword(this.updateProps.keyword);
+ await this.SetTags(this.updateProps.tags);
+ await this.SetLocation(this.updateProps.location);
+ await this.SetPosition(this.updateProps.position);
},
/**
* Find
*
* Locates the bookmark which corresponds to this object's properties.
*
- * @return the bookmark id if the bookmark was found, otherwise -1
+ * @return the bookmark guid if the bookmark was found, otherwise null
*/
- Find() {
- this.props.folder_id = this.GetFolder(this.props.location);
- if (this.props.folder_id == -1) {
+ async Find() {
+ this.props.parentGuid = await this.GetFolder(this.props.location);
+
+ if (this.props.parentGuid == null) {
Logger.logError("Unable to find folder " + this.props.location);
- return -1;
+ return null;
}
let bookmarkTitle = this.props.title;
- this.props.item_id = this.GetPlacesNodeId(this.props.folder_id,
- null,
- bookmarkTitle,
- this.props.uri);
+ this.props.guid = await this.GetPlacesChildGuid(this.props.parentGuid,
+ null,
+ bookmarkTitle,
+ this.props.uri);
- if (this.props.item_id == -1) {
+ if (!this.props.guid) {
Logger.logPotentialError(this.toString() + " not found");
- return -1;
+ return null;
}
- if (!this.CheckDescription(this.props.description))
- return -1;
+ if (!(await this.CheckDescription(this.props.description))) {
+ return null;
+ }
if (this.props.keyword != null) {
- let { keyword } = Async.promiseSpinningly(
- PlacesSyncUtils.bookmarks.fetch(this.GetSyncId()));
+ let {keyword} = await PlacesSyncUtils.bookmarks.fetch(this.props.guid);
if (keyword != this.props.keyword) {
Logger.logPotentialError("Incorrect keyword - expected: " +
this.props.keyword + ", actual: " + keyword +
" for " + this.toString());
- return -1;
+ return null;
}
}
+ let itemId = await PlacesUtils.promiseItemId(this.props.guid);
let loadInSidebar = PlacesUtils.annotations.itemHasAnnotation(
- this.props.item_id,
+ itemId,
"bookmarkProperties/loadInSidebar");
if (loadInSidebar)
loadInSidebar = PlacesUtils.annotations.getItemAnnotation(
- this.props.item_id,
+ itemId,
"bookmarkProperties/loadInSidebar");
if (this.props.loadInSidebar != null &&
loadInSidebar != this.props.loadInSidebar) {
Logger.logPotentialError("Incorrect loadInSidebar setting - expected: " +
this.props.loadInSidebar + ", actual: " + loadInSidebar +
" for " + this.toString());
- return -1;
+ return null;
}
if (this.props.tags != null) {
try {
let URI = Services.io.newURI(this.props.uri);
let tags = PlacesUtils.tagging.getTagsForURI(URI, {});
tags.sort();
this.props.tags.sort();
if (JSON.stringify(tags) != JSON.stringify(this.props.tags)) {
Logger.logPotentialError("Wrong tags - expected: " +
JSON.stringify(this.props.tags) + ", actual: " +
JSON.stringify(tags) + " for " + this.toString());
- return -1;
+ return null;
}
} catch (e) {
Logger.logPotentialError("error processing tags " + e);
- return -1;
+ return null;
}
}
- if (!this.CheckPosition(this.props.before,
- this.props.after,
- this.props.last_item_pos))
- return -1;
- return this.props.item_id;
+ if (!(await this.CheckPosition(this.props.before,
+ this.props.after,
+ this.props.last_item_pos)))
+ return null;
+ return this.props.guid;
},
/**
* Remove
*
* Removes this bookmark. The bookmark should have been located previously
* by a call to Find.
*
* @return nothing
*/
- Remove() {
- Logger.AssertTrue(this.props.item_id != -1 && this.props.item_id != null,
- "Invalid item_id during Remove");
- PlacesUtils.bookmarks.removeItem(this.props.item_id);
+ async Remove() {
+ Logger.AssertTrue(this.props.guid, "Invalid guid during Remove");
+ await PlacesUtils.bookmarks.remove(this.props.guid);
},
};
extend(Bookmark, PlacesItem);
/**
* BookmarkFolder class constructor. Initializes instance properties.
*/
@@ -669,84 +652,89 @@ function BookmarkFolder(props) {
BookmarkFolder.prototype = {
/**
* Create
*
* Creates the bookmark folder described by this object's properties.
*
* @return the id of the created bookmark folder
*/
- Create() {
- this.props.folder_id = this.GetOrCreateFolder(this.props.location);
- Logger.AssertTrue(this.props.folder_id != -1, "Unable to create " +
+ async Create() {
+ this.props.parentGuid = await this.GetOrCreateFolder(this.props.location);
+ Logger.AssertTrue(this.props.parentGuid, "Unable to create " +
"folder, error creating parent folder " + this.props.location);
- this.props.item_id = PlacesUtils.bookmarks.createFolder(this.props.folder_id,
- this.props.folder,
- -1);
- this.SetDescription(this.props.description);
- return this.props.folder_id;
+ let {guid} = await PlacesUtils.bookmarks.insert({parentGuid: this.props.parentGuid,
+ title: this.props.folder,
+ index: PlacesUtils.bookmarks.DEFAULT_INDEX,
+ type: PlacesUtils.bookmarks.TYPE_FOLDER,
+ });
+ this.props.guid = guid;
+ await this.SetDescription(this.props.description);
+ return this.props.parentGuid;
},
/**
* Find
*
* Locates the bookmark folder which corresponds to this object's
* properties.
*
- * @return the folder id if the folder was found, otherwise -1
+ * @return the folder guid if the folder was found, otherwise null
*/
- Find() {
- this.props.folder_id = this.GetFolder(this.props.location);
- if (this.props.folder_id == -1) {
+ async Find() {
+ this.props.parentGuid = await this.GetFolder(this.props.location);
+ if (this.props.parentGuid == null) {
Logger.logError("Unable to find folder " + this.props.location);
- return -1;
+ return null;
}
- this.props.item_id = this.GetPlacesNodeId(
- this.props.folder_id,
- Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER,
+ this.props.guid = await this.GetPlacesChildGuid(
+ this.props.parentGuid,
+ PlacesUtils.bookmarks.TYPE_FOLDER,
this.props.folder);
- if (!this.CheckDescription(this.props.description))
- return -1;
- if (!this.CheckPosition(this.props.before,
- this.props.after,
- this.props.last_item_pos))
- return -1;
- return this.props.item_id;
+ if (this.props.guid == null) {
+ return null;
+ }
+ if (!(await this.CheckDescription(this.props.description))) {
+ return null;
+ }
+ if (!(await this.CheckPosition(this.props.before,
+ this.props.after,
+ this.props.last_item_pos))) {
+ return null;
+ }
+ return this.props.guid;
},
/**
* Remove
*
* Removes this folder. The folder should have been located previously
* by a call to Find.
*
* @return nothing
*/
- Remove() {
- Logger.AssertTrue(this.props.item_id != -1 && this.props.item_id != null,
- "Invalid item_id during Remove");
- PlacesUtils.bookmarks.removeFolderChildren(this.props.item_id);
- PlacesUtils.bookmarks.removeItem(this.props.item_id);
+ async Remove() {
+ Logger.AssertTrue(this.props.guid, "Invalid guid during Remove");
+ await PlacesUtils.bookmarks.remove(this.props.guid);
},
/**
* Update
*
* Updates this bookmark's properties according the properties on this
* object's 'updateProps' property.
*
* @return nothing
*/
- Update() {
- Logger.AssertTrue(this.props.item_id != -1 && this.props.item_id != null,
- "Invalid item_id during Update");
- this.SetLocation(this.updateProps.location);
- this.SetPosition(this.updateProps.position);
- this.SetTitle(this.updateProps.folder);
- this.SetDescription(this.updateProps.description);
+ async Update() {
+ Logger.AssertTrue(this.props.guid, "Invalid guid during Update");
+ await this.SetLocation(this.updateProps.location);
+ await this.SetPosition(this.updateProps.position);
+ await this.SetTitle(this.updateProps.folder);
+ await this.SetDescription(this.updateProps.description);
},
};
extend(BookmarkFolder, PlacesItem);
/**
* Livemark class constructor. Initialzes instance properties.
*/
@@ -761,129 +749,120 @@ function Livemark(props) {
Livemark.prototype = {
/**
* Create
*
* Creates the livemark described by this object's properties.
*
* @return the id of the created livemark
*/
- Create() {
- this.props.folder_id = this.GetOrCreateFolder(this.props.location);
- Logger.AssertTrue(this.props.folder_id != -1, "Unable to create " +
+ async Create() {
+ this.props.parentGuid = await this.GetOrCreateFolder(this.props.location);
+ Logger.AssertTrue(this.props.parentGuid, "Unable to create " +
"folder, error creating parent folder " + this.props.location);
let siteURI = null;
if (this.props.siteUri != null)
siteURI = Services.io.newURI(this.props.siteUri);
- let livemarkObj = {parentId: this.props.folder_id,
+ let livemarkObj = {parentGuid: this.props.parentGuid,
title: this.props.livemark,
siteURI,
feedURI: Services.io.newURI(this.props.feedUri),
index: PlacesUtils.bookmarks.DEFAULT_INDEX};
- // Until this can handle asynchronous creation, we need to spin.
- let spinningCb = Async.makeSpinningCallback();
-
- PlacesUtils.livemarks.addLivemark(livemarkObj).then(
- aLivemark => { spinningCb(null, [Components.results.NS_OK, aLivemark]) },
- () => { spinningCb(null, [Components.results.NS_ERROR_UNEXPECTED, null]) }
- );
-
- let [status, livemark] = spinningCb.wait();
- if (!Components.isSuccessCode(status)) {
- throw new Error(status);
- }
-
- this.props.item_id = livemark.id;
- return this.props.item_id;
+ let livemark = await PlacesUtils.livemarks.addLivemark(livemarkObj);
+ this.props.guid = livemark.guid;
+ return this.props.guid;
},
/**
* Find
*
* Locates the livemark which corresponds to this object's
* properties.
*
- * @return the item id if the livemark was found, otherwise -1
+ * @return the item guid if the livemark was found, otherwise null
*/
- Find() {
- this.props.folder_id = this.GetFolder(this.props.location);
- if (this.props.folder_id == -1) {
+ async Find() {
+ this.props.parentGuid = await this.GetFolder(this.props.location);
+ if (this.props.parentGuid == null) {
Logger.logError("Unable to find folder " + this.props.location);
- return -1;
+ return null;
}
- this.props.item_id = this.GetPlacesNodeId(
- this.props.folder_id,
- Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER,
+ this.props.guid = await this.GetPlacesChildGuid(
+ this.props.parentGuid,
+ PlacesUtils.bookmarks.TYPE_FOLDER,
this.props.livemark);
+ if (!this.props.guid) {
+ Logger.logPotentialError("can't find livemark for " + this.toString());
+ return null;
+ }
+ let itemId = await PlacesUtils.promiseItemId(this.props.guid);
if (!PlacesUtils.annotations
- .itemHasAnnotation(this.props.item_id, PlacesUtils.LMANNO_FEEDURI)) {
+ .itemHasAnnotation(itemId, PlacesUtils.LMANNO_FEEDURI)) {
Logger.logPotentialError("livemark folder found, but it's just a regular folder, for " +
this.toString());
- this.props.item_id = -1;
- return -1;
+ this.props.guid = null;
+ return null;
}
let feedURI = Services.io.newURI(this.props.feedUri);
let lmFeedURISpec =
- PlacesUtils.annotations.getItemAnnotation(this.props.item_id,
+ PlacesUtils.annotations.getItemAnnotation(itemId,
PlacesUtils.LMANNO_FEEDURI);
if (feedURI.spec != lmFeedURISpec) {
Logger.logPotentialError("livemark feed uri not correct, expected: " +
this.props.feedUri + ", actual: " + lmFeedURISpec +
" for " + this.toString());
- return -1;
+ return null;
}
if (this.props.siteUri != null) {
let siteURI = Services.io.newURI(this.props.siteUri);
let lmSiteURISpec =
- PlacesUtils.annotations.getItemAnnotation(this.props.item_id,
+ PlacesUtils.annotations.getItemAnnotation(itemId,
PlacesUtils.LMANNO_SITEURI);
if (siteURI.spec != lmSiteURISpec) {
Logger.logPotentialError("livemark site uri not correct, expected: " +
this.props.siteUri + ", actual: " + lmSiteURISpec + " for " +
this.toString());
- return -1;
+ return null;
}
}
- if (!this.CheckPosition(this.props.before,
- this.props.after,
- this.props.last_item_pos))
- return -1;
- return this.props.item_id;
+ if (!(await this.CheckPosition(this.props.before,
+ this.props.after,
+ this.props.last_item_pos)))
+ return null;
+ return this.props.guid;
},
/**
* Update
*
* Updates this livemark's properties according the properties on this
* object's 'updateProps' property.
*
* @return nothing
*/
- Update() {
- Logger.AssertTrue(this.props.item_id != -1 && this.props.item_id != null,
- "Invalid item_id during Update");
- this.SetLocation(this.updateProps.location);
- this.SetPosition(this.updateProps.position);
- this.SetTitle(this.updateProps.livemark);
+ async Update() {
+ Logger.AssertTrue(this.props.guid, "Invalid guid during Update");
+ await this.SetLocation(this.updateProps.location);
+ await this.SetPosition(this.updateProps.position);
+ await this.SetTitle(this.updateProps.livemark);
return true;
},
/**
* Remove
*
* Removes this livemark. The livemark should have been located previously
* by a call to Find.
*
* @return nothing
*/
- Remove() {
- Logger.AssertTrue(this.props.item_id != -1 && this.props.item_id != null,
- "Invalid item_id during Remove");
- PlacesUtils.bookmarks.removeItem(this.props.item_id);
+ async Remove() {
+ Logger.AssertTrue(this.props.guid, "Invalid guid during Remove");
+ await PlacesUtils.bookmarks.remove(this.props.guid);
},
};
extend(Livemark, PlacesItem);
/**
* Separator class constructor. Initializes instance properties.
*/
@@ -898,95 +877,99 @@ function Separator(props) {
Separator.prototype = {
/**
* Create
*
* Creates the bookmark separator described by this object's properties.
*
* @return the id of the created separator
*/
- Create() {
- this.props.folder_id = this.GetOrCreateFolder(this.props.location);
- Logger.AssertTrue(this.props.folder_id != -1, "Unable to create " +
+ async Create() {
+ this.props.parentGuid = await this.GetOrCreateFolder(this.props.location);
+ Logger.AssertTrue(this.props.parentGuid, "Unable to create " +
"folder, error creating parent folder " + this.props.location);
- this.props.item_id = PlacesUtils.bookmarks.insertSeparator(this.props.folder_id,
- -1);
- return this.props.item_id;
+ let {guid} = await PlacesUtils.bookmarks.insert({
+ parentGuid: this.props.parentGuid,
+ type: PlacesUtils.bookmarks.TYPE_SEPARATOR
+ });
+ this.props.guid = guid;
+ return guid;
},
/**
* Find
*
* Locates the bookmark separator which corresponds to this object's
* properties.
*
- * @return the item id if the separator was found, otherwise -1
+ * @return the item guid if the separator was found, otherwise null
*/
- Find() {
- this.props.folder_id = this.GetFolder(this.props.location);
- if (this.props.folder_id == -1) {
+ async Find() {
+ this.props.parentGuid = await this.GetFolder(this.props.location);
+ if (this.props.parentGuid == null) {
Logger.logError("Unable to find folder " + this.props.location);
- return -1;
+ return null;
}
if (this.props.before == null && this.props.last_item_pos == null) {
Logger.logPotentialError("Separator requires 'before' attribute if it's the" +
"first item in the list");
- return -1;
+ return null;
}
let expected_pos = -1;
if (this.props.before) {
- let other_id = this.GetPlacesNodeId(this.props.folder_id,
- null,
- this.props.before);
- if (other_id == -1) {
+ let otherGuid = this.GetPlacesChildGuid(this.props.parentGuid,
+ null,
+ this.props.before);
+ if (otherGuid == null) {
Logger.logPotentialError("Can't find places item " + this.props.before +
" for locating separator");
- return -1;
+ return null;
}
- expected_pos = PlacesUtils.bookmarks.getItemIndex(other_id) - 1;
+ expected_pos = (await PlacesUtils.bookmarks.fetch(otherGuid)).index - 1;
} else {
expected_pos = this.props.last_item_pos + 1;
}
- this.props.item_id = PlacesUtils.bookmarks.getIdForItemAt(this.props.folder_id,
- expected_pos);
- if (this.props.item_id == -1) {
+ // Note these are syncIDs instead of GUIDs, but that's ok here.
+ let children = await PlacesSyncUtils.bookmarks.fetchChildSyncIds(this.props.parentGuid);
+ this.props.guid = children[expected_pos];
+ if (this.props.guid == null) {
Logger.logPotentialError("No separator found at position " + expected_pos);
- } else if (PlacesUtils.bookmarks.getItemType(this.props.item_id) !=
- PlacesUtils.bookmarks.TYPE_SEPARATOR) {
- Logger.logPotentialError("Places item at position " + expected_pos +
- " is not a separator");
- return -1;
- }
- return this.props.item_id;
+ return null;
+ }
+ let info = await PlacesUtils.bookmarks.fetch(this.props.guid);
+ if (info.type != PlacesUtils.bookmarks.TYPE_SEPARATOR) {
+ Logger.logPotentialError("Places item at position " + expected_pos +
+ " is not a separator");
+ return null;
+ }
+ return this.props.guid;
},
/**
* Update
*
* Updates this separator's properties according the properties on this
* object's 'updateProps' property.
*
* @return nothing
*/
- Update() {
- Logger.AssertTrue(this.props.item_id != -1 && this.props.item_id != null,
- "Invalid item_id during Update");
- this.SetLocation(this.updateProps.location);
- this.SetPosition(this.updateProps.position);
+ async Update() {
+ Logger.AssertTrue(this.props.guid, "Invalid guid during Update");
+ await this.SetLocation(this.updateProps.location);
+ await this.SetPosition(this.updateProps.position);
return true;
},
/**
* Remove
*
* Removes this separator. The separator should have been located
* previously by a call to Find.
*
* @return nothing
*/
- Remove() {
- Logger.AssertTrue(this.props.item_id != -1 && this.props.item_id != null,
- "Invalid item_id during Update");
- PlacesUtils.bookmarks.removeItem(this.props.item_id);
+ async Remove() {
+ Logger.AssertTrue(this.props.guid, "Invalid guid during Update");
+ await PlacesUtils.bookmarks.remove(this.props.guid);
},
};
extend(Separator, PlacesItem);
--- a/services/sync/tps/extensions/tps/resource/tps.jsm
+++ b/services/sync/tps/extensions/tps/resource/tps.jsm
@@ -99,16 +99,17 @@ const OBSERVER_TOPICS = ["fxaccounts:onl
"weave:engine:stop-tracking",
"weave:service:login:error",
"weave:service:setup-complete",
"weave:service:sync:finish",
"weave:service:sync:delayed",
"weave:service:sync:error",
"weave:service:sync:start",
"weave:service:resyncs-finished",
+ "places-browser-init-complete",
];
var TPS = {
_currentAction: -1,
_currentPhase: -1,
_enabledEngines: null,
_errors: 0,
_isTracking: false,
@@ -127,16 +128,17 @@ var TPS = {
_triggeredSync: false,
_usSinceEpoch: 0,
_requestedQuit: false,
shouldValidateAddons: false,
shouldValidateBookmarks: false,
shouldValidatePasswords: false,
shouldValidateForms: false,
_windowsUpDeferred: PromiseUtils.defer(),
+ _placesInitDeferred: PromiseUtils.defer(),
_init: function TPS__init() {
this.delayAutoSync();
OBSERVER_TOPICS.forEach(function(aTopic) {
Services.obs.addObserver(this, aTopic, true);
}, this);
@@ -177,16 +179,20 @@ var TPS = {
Logger.close();
break;
case "sessionstore-windows-restored":
this._windowsUpDeferred.resolve();
break;
+ case "places-browser-init-complete":
+ this._placesInitDeferred.resolve();
+ break;
+
case "weave:service:setup-complete":
this._setupComplete = true;
if (this._syncWipeAction) {
Weave.Svc.Prefs.set("firstSync", this._syncWipeAction);
this._syncWipeAction = null;
}
@@ -500,81 +506,83 @@ var TPS = {
default:
throw new Error("Unknown action for add-on: " + action);
}
}
Logger.logPass("executing action " + action.toUpperCase() +
" on addons");
},
- HandleBookmarks(bookmarks, action) {
+ async HandleBookmarks(bookmarks, action) {
+ // wait for default bookmarks to be created.
+ await this._placesInitDeferred.promise;
this.shouldValidateBookmarks = true;
try {
let items = [];
for (let folder in bookmarks) {
let last_item_pos = -1;
for (let bookmark of bookmarks[folder]) {
Logger.clearPotentialError();
let placesItem;
bookmark.location = folder;
if (last_item_pos != -1)
bookmark.last_item_pos = last_item_pos;
- let item_id = -1;
+ let itemGuid = null;
if (action != ACTION_MODIFY && action != ACTION_DELETE)
Logger.logInfo("executing action " + action.toUpperCase() +
" on bookmark " + JSON.stringify(bookmark));
if ("uri" in bookmark)
placesItem = new Bookmark(bookmark);
else if ("folder" in bookmark)
placesItem = new BookmarkFolder(bookmark);
else if ("livemark" in bookmark)
placesItem = new Livemark(bookmark);
else if ("separator" in bookmark)
placesItem = new Separator(bookmark);
if (action == ACTION_ADD) {
- item_id = placesItem.Create();
+ itemGuid = await placesItem.Create();
} else {
- item_id = placesItem.Find();
+ itemGuid = await placesItem.Find();
if (action == ACTION_VERIFY_NOT) {
- Logger.AssertTrue(item_id == -1,
+ Logger.AssertTrue(itemGuid == null,
"places item exists but it shouldn't: " +
JSON.stringify(bookmark));
} else
- Logger.AssertTrue(item_id != -1, "places item not found", true);
+ Logger.AssertTrue(itemGuid, "places item not found", true);
}
- last_item_pos = placesItem.GetItemIndex();
+ last_item_pos = await placesItem.GetItemIndex();
items.push(placesItem);
}
}
if (action == ACTION_DELETE || action == ACTION_MODIFY) {
for (let item of items) {
Logger.logInfo("executing action " + action.toUpperCase() +
" on bookmark " + JSON.stringify(item));
switch (action) {
case ACTION_DELETE:
- item.Remove();
+ await item.Remove();
break;
case ACTION_MODIFY:
if (item.updateProps != null)
- item.Update();
+ await item.Update();
break;
}
}
}
Logger.logPass("executing action " + action.toUpperCase() +
" on bookmarks");
} catch (e) {
- DumpBookmarks();
+ await DumpBookmarks();
throw (e);
}
},
MozmillEndTestListener: function TPS__MozmillEndTestListener(obj) {
Logger.logInfo("mozmill endTest: " + JSON.stringify(obj));
if (obj.failed > 0) {
this.DumpError("mozmill test failed, name: " + obj.name + ", reason: " + JSON.stringify(obj.fails));
@@ -1218,30 +1226,30 @@ var Addons = {
TPS.HandleAddons(addons, ACTION_VERIFY_NOT);
},
skipValidation() {
TPS.shouldValidateAddons = false;
}
};
var Bookmarks = {
- add: function Bookmarks__add(bookmarks) {
- TPS.HandleBookmarks(bookmarks, ACTION_ADD);
+ async add(bookmarks) {
+ await TPS.HandleBookmarks(bookmarks, ACTION_ADD);
},
- modify: function Bookmarks__modify(bookmarks) {
- TPS.HandleBookmarks(bookmarks, ACTION_MODIFY);
+ async modify(bookmarks) {
+ await TPS.HandleBookmarks(bookmarks, ACTION_MODIFY);
},
- delete: function Bookmarks__delete(bookmarks) {
- TPS.HandleBookmarks(bookmarks, ACTION_DELETE);
+ async delete(bookmarks) {
+ await TPS.HandleBookmarks(bookmarks, ACTION_DELETE);
},
- verify: function Bookmarks__verify(bookmarks) {
- TPS.HandleBookmarks(bookmarks, ACTION_VERIFY);
+ async verify(bookmarks) {
+ await TPS.HandleBookmarks(bookmarks, ACTION_VERIFY);
},
- verifyNot: function Bookmarks__verifyNot(bookmarks) {
- TPS.HandleBookmarks(bookmarks, ACTION_VERIFY_NOT);
+ async verifyNot(bookmarks) {
+ await TPS.HandleBookmarks(bookmarks, ACTION_VERIFY_NOT);
},
skipValidation() {
TPS.shouldValidateBookmarks = false;
}
};
var Formdata = {
add: function Formdata__add(formdata) {