зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1423896 - Make the All Bookmarks folder for the left pane of the Library a virtual query. r=mak
MozReview-Commit-ID: HzJ9y1fiEz1 --HG-- extra : rebase_source : 27b0280e9dfef2626d187f9b8a81f23e4583302f
This commit is contained in:
Родитель
e23bde49fe
Коммит
362505f227
|
@ -584,20 +584,20 @@ var PlacesCommandHook = {
|
|||
|
||||
/**
|
||||
* Opens the Places Organizer.
|
||||
* @param aLeftPaneRoot
|
||||
* The query to select in the organizer window - options
|
||||
* are: History, AllBookmarks, BookmarksMenu, BookmarksToolbar,
|
||||
* UnfiledBookmarks, Tags and Downloads.
|
||||
* @param {String} item The item to select in the organizer window,
|
||||
* options are (case sensitive):
|
||||
* BookmarksMenu, BookmarksToolbar, UnfiledBookmarks,
|
||||
* AllBookmarks, History, Downloads.
|
||||
*/
|
||||
showPlacesOrganizer: function PCH_showPlacesOrganizer(aLeftPaneRoot) {
|
||||
showPlacesOrganizer(item) {
|
||||
var organizer = Services.wm.getMostRecentWindow("Places:Organizer");
|
||||
// Due to bug 528706, getMostRecentWindow can return closed windows.
|
||||
if (!organizer || organizer.closed) {
|
||||
// No currently open places window, so open one with the specified mode.
|
||||
openDialog("chrome://browser/content/places/places.xul",
|
||||
"", "chrome,toolbar=yes,dialog=no,resizable", aLeftPaneRoot);
|
||||
"", "chrome,toolbar=yes,dialog=no,resizable", item);
|
||||
} else {
|
||||
organizer.PlacesOrganizer.selectLeftPaneContainerByHierarchy(aLeftPaneRoot);
|
||||
organizer.PlacesOrganizer.selectLeftPaneContainerByHierarchy(item);
|
||||
organizer.focus();
|
||||
}
|
||||
},
|
||||
|
|
|
@ -205,7 +205,7 @@ let InternalFaviconLoader = {
|
|||
};
|
||||
|
||||
this.PlacesUIUtils = {
|
||||
ORGANIZER_LEFTPANE_VERSION: 7,
|
||||
ORGANIZER_LEFTPANE_VERSION: 8,
|
||||
ORGANIZER_FOLDER_ANNO: "PlacesOrganizer/OrganizerFolder",
|
||||
ORGANIZER_QUERY_ANNO: "PlacesOrganizer/OrganizerQuery",
|
||||
|
||||
|
@ -513,6 +513,16 @@ this.PlacesUIUtils = {
|
|||
return false;
|
||||
}
|
||||
|
||||
// Is it a query pointing to one of the special root folders?
|
||||
if (PlacesUtils.nodeIsQuery(parentNode) && PlacesUtils.nodeIsFolder(aNode)) {
|
||||
let guid = PlacesUtils.getConcreteItemGuid(aNode);
|
||||
// If the parent folder is not a folder, it must be a query, and so this node
|
||||
// cannot be removed.
|
||||
if (PlacesUtils.isRootItem(guid)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// If it's not a bookmark, we can remove it unless it's a child of a
|
||||
// livemark.
|
||||
if (aNode.itemId == -1) {
|
||||
|
@ -563,7 +573,7 @@ this.PlacesUIUtils = {
|
|||
view.controller.hasCachedLivemarkInfo(placesNode))
|
||||
return true;
|
||||
|
||||
// leftPaneFolderId, and as a result, allBookmarksFolderId, is a lazy getter
|
||||
// leftPaneFolderId is a lazy getter
|
||||
// performing at least a synchronous DB query (and on its very first call
|
||||
// in a fresh profile, it also creates the entire structure).
|
||||
// Therefore we don't want to this function, which is called very often by
|
||||
|
@ -577,8 +587,7 @@ this.PlacesUIUtils = {
|
|||
if (typeof Object.getOwnPropertyDescriptor(this, "leftPaneFolderId").get == "function") {
|
||||
return false;
|
||||
}
|
||||
return itemId == this.leftPaneFolderId ||
|
||||
itemId == this.allBookmarksFolderId;
|
||||
return itemId == this.leftPaneFolderId;
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -839,7 +848,6 @@ this.PlacesUIUtils = {
|
|||
// Get the folder id for the organizer left-pane folder.
|
||||
maybeRebuildLeftPane() {
|
||||
let leftPaneRoot = -1;
|
||||
let allBookmarksId;
|
||||
|
||||
// Shortcuts to services.
|
||||
let bs = PlacesUtils.bookmarks;
|
||||
|
@ -852,21 +860,9 @@ this.PlacesUIUtils = {
|
|||
"Downloads": { title: this.getString("OrganizerQueryDownloads") },
|
||||
"Tags": { title: this.getString("OrganizerQueryTags") },
|
||||
"AllBookmarks": { title: this.getString("OrganizerQueryAllBookmarks") },
|
||||
"BookmarksToolbar":
|
||||
{ title: "",
|
||||
concreteTitle: PlacesUtils.getString("BookmarksToolbarFolderTitle"),
|
||||
concreteId: PlacesUtils.toolbarFolderId },
|
||||
"BookmarksMenu":
|
||||
{ title: "",
|
||||
concreteTitle: PlacesUtils.getString("BookmarksMenuFolderTitle"),
|
||||
concreteId: PlacesUtils.bookmarksMenuFolderId },
|
||||
"UnfiledBookmarks":
|
||||
{ title: "",
|
||||
concreteTitle: PlacesUtils.getString("OtherBookmarksFolderTitle"),
|
||||
concreteId: PlacesUtils.unfiledBookmarksFolderId },
|
||||
};
|
||||
// All queries but PlacesRoot.
|
||||
const EXPECTED_QUERY_COUNT = 7;
|
||||
const EXPECTED_QUERY_COUNT = 4;
|
||||
|
||||
// Removes an item and associated annotations, ignoring eventual errors.
|
||||
function safeRemoveItem(aItemId) {
|
||||
|
@ -1053,19 +1049,9 @@ this.PlacesUIUtils = {
|
|||
Ci.nsINavHistoryQueryOptions.SORT_BY_TITLE_ASCENDING);
|
||||
|
||||
// All Bookmarks Folder.
|
||||
allBookmarksId = this.create_folder("AllBookmarks", leftPaneRoot, false);
|
||||
|
||||
// All Bookmarks->Bookmarks Toolbar Query.
|
||||
this.create_query("BookmarksToolbar", allBookmarksId,
|
||||
"place:folder=TOOLBAR");
|
||||
|
||||
// All Bookmarks->Bookmarks Menu Query.
|
||||
this.create_query("BookmarksMenu", allBookmarksId,
|
||||
"place:folder=BOOKMARKS_MENU");
|
||||
|
||||
// All Bookmarks->Unfiled Bookmarks Query.
|
||||
this.create_query("UnfiledBookmarks", allBookmarksId,
|
||||
"place:folder=UNFILED_BOOKMARKS");
|
||||
this.create_query("AllBookmarks", leftPaneRoot,
|
||||
"place:type=" +
|
||||
Ci.nsINavHistoryQueryOptions.RESULTS_AS_ROOTS_QUERY);
|
||||
}
|
||||
};
|
||||
bs.runInBatchMode(callback, null);
|
||||
|
@ -1073,16 +1059,6 @@ this.PlacesUIUtils = {
|
|||
return leftPaneRoot;
|
||||
},
|
||||
|
||||
/**
|
||||
* Get the folder id for the organizer left-pane folder.
|
||||
*/
|
||||
get allBookmarksFolderId() {
|
||||
// ensure the left-pane root is initialized;
|
||||
this.leftPaneFolderId;
|
||||
delete this.allBookmarksFolderId;
|
||||
return this.allBookmarksFolderId = this.leftPaneQueries.AllBookmarks;
|
||||
},
|
||||
|
||||
/**
|
||||
* If an item is a left-pane query, returns the name of the query
|
||||
* or an empty string if not.
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
function init() {
|
||||
document.getElementById("bookmarks-view").place =
|
||||
"place:queryType=1&folder=" + window.top.PlacesUIUtils.allBookmarksFolderId;
|
||||
"place:type=" + Ci.nsINavHistoryQueryOptions.RESULTS_AS_ROOTS_QUERY;
|
||||
}
|
||||
|
||||
function searchBookmarks(aSearchString) {
|
||||
|
|
|
@ -1377,7 +1377,8 @@ var PlacesControllerDragHelper = {
|
|||
* @return True if the node can be moved, false otherwise.
|
||||
*/
|
||||
canMoveUnwrappedNode(unwrappedNode) {
|
||||
if (unwrappedNode.id <= 0 || PlacesUtils.isRootItem(unwrappedNode.id)) {
|
||||
if ((unwrappedNode.concreteGuid && PlacesUtils.isRootItem(unwrappedNode.concreteGuid)) ||
|
||||
unwrappedNode.id <= 0 || PlacesUtils.isRootItem(unwrappedNode.id)) {
|
||||
return false;
|
||||
}
|
||||
let parentId = unwrappedNode.parent;
|
||||
|
@ -1392,8 +1393,7 @@ var PlacesControllerDragHelper = {
|
|||
// them first, especially because isCommandEnabled may be called way
|
||||
// before the left pane folder is even necessary.
|
||||
if (typeof Object.getOwnPropertyDescriptor(PlacesUIUtils, "leftPaneFolderId").get != "function" &&
|
||||
(parentId == PlacesUIUtils.leftPaneFolderId ||
|
||||
parentId == PlacesUIUtils.allBookmarksFolderId)) {
|
||||
(parentId == PlacesUIUtils.leftPaneFolderId)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -60,8 +60,7 @@ var gEditItemOverlay = {
|
|||
let folderId = PlacesUtils.getConcreteItemId(parent);
|
||||
isParentReadOnly = folderId == PlacesUtils.placesRootId ||
|
||||
(!("get" in Object.getOwnPropertyDescriptor(PlacesUIUtils, "leftPaneFolderId")) &&
|
||||
(folderId == PlacesUIUtils.leftPaneFolderId ||
|
||||
folderId == PlacesUIUtils.allBookmarksFolderId));
|
||||
(folderId == PlacesUIUtils.leftPaneFolderId));
|
||||
}
|
||||
parentId = parent.itemId;
|
||||
parentGuid = parent.bookmarkGuid;
|
||||
|
@ -704,13 +703,13 @@ var gEditItemOverlay = {
|
|||
// the editable mode set on this tree, together with its collapsed state
|
||||
// breaks the view.
|
||||
const FOLDER_TREE_PLACE_URI =
|
||||
"place:excludeItems=1&excludeQueries=1&excludeReadOnlyFolders=1&folder=" +
|
||||
PlacesUIUtils.allBookmarksFolderId;
|
||||
"place:excludeItems=1&excludeQueries=1&excludeReadOnlyFolders=1&type=" +
|
||||
Ci.nsINavHistoryQueryOptions.RESULTS_AS_ROOTS_QUERY;
|
||||
this._folderTree.place = FOLDER_TREE_PLACE_URI;
|
||||
|
||||
this._element("chooseFolderSeparator").hidden =
|
||||
this._element("chooseFolderMenuItem").hidden = true;
|
||||
this._folderTree.selectItems([this._paneInfo.parentId]);
|
||||
this._folderTree.selectItems([this._paneInfo.parentGuid]);
|
||||
this._folderTree.focus();
|
||||
}
|
||||
},
|
||||
|
@ -929,7 +928,7 @@ var gEditItemOverlay = {
|
|||
let ip = this._folderTree.insertionPoint;
|
||||
|
||||
// default to the bookmarks menu folder
|
||||
if (!ip || ip.itemId == PlacesUIUtils.allBookmarksFolderId) {
|
||||
if (!ip) {
|
||||
ip = new InsertionPoint({
|
||||
parentId: PlacesUtils.bookmarksMenuFolderId,
|
||||
parentGuid: PlacesUtils.bookmarks.menuGuid
|
||||
|
|
|
@ -41,28 +41,63 @@ var PlacesOrganizer = {
|
|||
this._places.place = "place:excludeItems=1&expandQueries=0&folder=" + leftPaneRoot;
|
||||
},
|
||||
|
||||
selectLeftPaneBuiltIn(aQueryName) {
|
||||
var itemId = PlacesUIUtils.leftPaneQueries[aQueryName];
|
||||
this._places.selectItems([itemId]);
|
||||
// Forcefully expand all-bookmarks
|
||||
if (aQueryName == "AllBookmarks" || aQueryName == "History")
|
||||
PlacesUtils.asContainer(this._places.selectedNode).containerOpen = true;
|
||||
/**
|
||||
* Selects a left pane built-in item.
|
||||
*
|
||||
* @param {String} item The built-in item to select, may be one of (case sensitive):
|
||||
* AllBookmarks, BookmarksMenu, BookmarksToolbar,
|
||||
* History, Downloads, Tags, UnfiledBookmarks.
|
||||
*/
|
||||
selectLeftPaneBuiltIn(item) {
|
||||
switch (item) {
|
||||
case "AllBookmarks":
|
||||
case "History":
|
||||
case "Downloads":
|
||||
case "Tags": {
|
||||
var itemId = PlacesUIUtils.leftPaneQueries[item];
|
||||
this._places.selectItems([itemId]);
|
||||
// Forcefully expand all-bookmarks
|
||||
if (item == "AllBookmarks" || item == "History")
|
||||
PlacesUtils.asContainer(this._places.selectedNode).containerOpen = true;
|
||||
break;
|
||||
}
|
||||
case "BookmarksMenu":
|
||||
this.selectLeftPaneContainerByHierarchy([
|
||||
PlacesUIUtils.leftPaneQueries.AllBookmarks,
|
||||
PlacesUtils.bookmarks.virtualMenuGuid
|
||||
]);
|
||||
break;
|
||||
case "BookmarksToolbar":
|
||||
this.selectLeftPaneContainerByHierarchy([
|
||||
PlacesUIUtils.leftPaneQueries.AllBookmarks,
|
||||
PlacesUtils.bookmarks.virtualToolbarGuid
|
||||
]);
|
||||
break;
|
||||
case "UnfiledBookmarks":
|
||||
this.selectLeftPaneContainerByHierarchy([
|
||||
PlacesUIUtils.leftPaneQueries.AllBookmarks,
|
||||
PlacesUtils.bookmarks.virtualUnfiledGuid
|
||||
]);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Unrecognized item ${item} passed to selectLeftPaneRootItem`);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Opens a given hierarchy in the left pane, stopping at the last reachable
|
||||
* container.
|
||||
* container. Note: item ids should be considered deprecated.
|
||||
*
|
||||
* @param aHierarchy A single container or an array of containers, sorted from
|
||||
* the outmost to the innermost in the hierarchy. Each
|
||||
* container may be either an item id, a Places URI string,
|
||||
* or a named query.
|
||||
* or a named query, like:
|
||||
* "BookmarksMenu", "BookmarksToolbar", "UnfiledBookmarks", "AllBookmarks".
|
||||
* @see PlacesUIUtils.leftPaneQueries for supported named queries.
|
||||
*/
|
||||
selectLeftPaneContainerByHierarchy:
|
||||
function PO_selectLeftPaneContainerByHierarchy(aHierarchy) {
|
||||
selectLeftPaneContainerByHierarchy(aHierarchy) {
|
||||
if (!aHierarchy)
|
||||
throw new Error("Invalid containers hierarchy");
|
||||
throw new Error("Containers hierarchy not specified");
|
||||
let hierarchy = [].concat(aHierarchy);
|
||||
let selectWasSuppressed = this._places.view.selection.selectEventsSuppressed;
|
||||
if (!selectWasSuppressed)
|
||||
|
@ -74,12 +109,16 @@ var PlacesOrganizer = {
|
|||
this._places.selectItems([container], false);
|
||||
break;
|
||||
case "string":
|
||||
if (container.substr(0, 6) == "place:")
|
||||
this._places.selectPlaceURI(container);
|
||||
else if (container in PlacesUIUtils.leftPaneQueries)
|
||||
try {
|
||||
this.selectLeftPaneBuiltIn(container);
|
||||
else
|
||||
throw new Error("Invalid container found: " + container);
|
||||
} catch (ex) {
|
||||
if (container.substr(0, 6) == "place:") {
|
||||
this._places.selectPlaceURI(container);
|
||||
} else {
|
||||
// May be a guid.
|
||||
this._places.selectItems([container], false);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new Error("Invalid container type found: " + container);
|
||||
|
|
|
@ -76,7 +76,8 @@
|
|||
// tag containers, so we must fall to the default case.
|
||||
if (PlacesUtils.nodeIsHistoryContainer(queryNode) ||
|
||||
options.resultType == options.RESULTS_AS_TAG_QUERY ||
|
||||
options.resultType == options.RESULTS_AS_TAG_CONTENTS)
|
||||
options.resultType == options.RESULTS_AS_TAG_CONTENTS ||
|
||||
options.resultType == options.RESULTS_AS_ROOTS_QUERY)
|
||||
options.resultType = options.RESULTS_AS_URI;
|
||||
|
||||
var query = PlacesUtils.history.getNewQuery();
|
||||
|
@ -621,8 +622,12 @@
|
|||
checkedGuidsSet.has(concreteGuid))
|
||||
return foundOne;
|
||||
|
||||
// Only follow a query if it has been been explicitly opened by the caller.
|
||||
let shouldOpen = aOpenContainers && PlacesUtils.nodeIsFolder(node);
|
||||
// Only follow a query if it has been been explicitly opened by the
|
||||
// caller. We support the "AllBookmarks" case to allow callers to
|
||||
// specify just the top-level bookmark folders.
|
||||
let shouldOpen = aOpenContainers && (PlacesUtils.nodeIsFolder(node) ||
|
||||
(PlacesUtils.nodeIsQuery(node) && node.itemId == PlacesUIUtils.leftPaneQueries.AllBookmarks));
|
||||
|
||||
PlacesUtils.asContainer(node);
|
||||
if (!node.containerOpen && !shouldOpen)
|
||||
return foundOne;
|
||||
|
|
|
@ -137,6 +137,7 @@ PlacesTreeView.prototype = {
|
|||
case Ci.nsINavHistoryQueryOptions.RESULTS_AS_SITE_QUERY:
|
||||
case Ci.nsINavHistoryQueryOptions.RESULTS_AS_DATE_SITE_QUERY:
|
||||
case Ci.nsINavHistoryQueryOptions.RESULTS_AS_TAG_QUERY:
|
||||
case Ci.nsINavHistoryQueryOptions.RESULTS_AS_ROOTS_QUERY:
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -191,12 +192,16 @@ PlacesTreeView.prototype = {
|
|||
throw new Error("Invisible node passed to _getRowForNode");
|
||||
}
|
||||
|
||||
// Non-plain containers are initially built with their contents.
|
||||
// Non-plain containers, and non-Roots queries are initially built with their
|
||||
// contents.
|
||||
let parent = aNode.parent;
|
||||
let parentIsPlain = this._isPlainContainer(parent);
|
||||
if (!parentIsPlain) {
|
||||
if (parent == this._rootNode)
|
||||
if (!parentIsPlain &&
|
||||
parent.queryOptions.resultType !=
|
||||
Ci.nsINavHistoryQueryOptions.RESULTS_AS_ROOTS_QUERY) {
|
||||
if (parent == this._rootNode) {
|
||||
return this._rows.indexOf(aNode);
|
||||
}
|
||||
|
||||
return this._rows.indexOf(aNode, aParentRow);
|
||||
}
|
||||
|
@ -1276,21 +1281,35 @@ PlacesTreeView.prototype = {
|
|||
properties += " hostContainer";
|
||||
} else if (nodeType == Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER ||
|
||||
nodeType == Ci.nsINavHistoryResultNode.RESULT_TYPE_FOLDER_SHORTCUT) {
|
||||
if (this._controller.hasCachedLivemarkInfo(node)) {
|
||||
properties += " livemark";
|
||||
} else {
|
||||
PlacesUtils.livemarks.getLivemark({ id: node.itemId })
|
||||
.then(aLivemark => {
|
||||
this._controller.cacheLivemarkInfo(node, aLivemark);
|
||||
let livemarkProps = this._cellProperties.get(node);
|
||||
this._cellProperties.set(node, livemarkProps += " livemark");
|
||||
// The livemark attribute is set as a cell property on the title cell.
|
||||
this._invalidateCellValue(node, this.COLUMN_TYPE_TITLE);
|
||||
}, () => undefined);
|
||||
if (itemId != -1) {
|
||||
if (this._controller.hasCachedLivemarkInfo(node)) {
|
||||
properties += " livemark";
|
||||
} else {
|
||||
PlacesUtils.livemarks.getLivemark({ id: itemId })
|
||||
.then(aLivemark => {
|
||||
this._controller.cacheLivemarkInfo(node, aLivemark);
|
||||
let livemarkProps = this._cellProperties.get(node);
|
||||
this._cellProperties.set(node, livemarkProps += " livemark");
|
||||
// The livemark attribute is set as a cell property on the title cell.
|
||||
this._invalidateCellValue(node, this.COLUMN_TYPE_TITLE);
|
||||
}, () => undefined);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (itemId != -1) {
|
||||
if (itemId == -1) {
|
||||
switch (node.bookmarkGuid) {
|
||||
case PlacesUtils.bookmarks.virtualToolbarGuid:
|
||||
properties += ` queryFolder_${PlacesUtils.bookmarks.toolbarGuid}`;
|
||||
break;
|
||||
case PlacesUtils.bookmarks.virtualMenuGuid:
|
||||
properties += ` queryFolder_${PlacesUtils.bookmarks.menuGuid}`;
|
||||
break;
|
||||
case PlacesUtils.bookmarks.virtualUnfiledGuid:
|
||||
properties += ` queryFolder_${PlacesUtils.bookmarks.unfiledGuid}`;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
let queryName = PlacesUIUtils.getLeftPaneQueryNameFromId(itemId);
|
||||
if (queryName)
|
||||
properties += " OrganizerQuery_" + queryName;
|
||||
|
@ -1764,12 +1783,12 @@ PlacesTreeView.prototype = {
|
|||
// Note that concrete itemIds aren't used intentionally. For example, we
|
||||
// have no reason to disallow renaming a shortcut to the Bookmarks Toolbar,
|
||||
// except for the one under All Bookmarks.
|
||||
if (PlacesUtils.nodeIsSeparator(node) || PlacesUtils.isRootItem(itemGuid))
|
||||
if (PlacesUtils.nodeIsSeparator(node) || PlacesUtils.isRootItem(itemGuid) ||
|
||||
PlacesUtils.isQueryGeneratedFolder(itemGuid))
|
||||
return false;
|
||||
|
||||
let parentId = PlacesUtils.getConcreteItemId(node.parent);
|
||||
if (parentId == PlacesUIUtils.leftPaneFolderId ||
|
||||
parentId == PlacesUIUtils.allBookmarksFolderId) {
|
||||
if (parentId == PlacesUIUtils.leftPaneFolderId) {
|
||||
// Note that the for the time being this is the check that actually
|
||||
// blocks renaming places "roots", and not the isRootItem check above.
|
||||
// That's because places root are only exposed through folder shortcuts
|
||||
|
|
|
@ -29,10 +29,6 @@ add_task(async function() {
|
|||
namepicker.blur();
|
||||
bookmark = await PlacesUtils.bookmarks.fetch(PlacesUtils.bookmarks.unfiledGuid);
|
||||
Assert.equal(namepicker.value, bookmark.title, "Root title is correct");
|
||||
// Check the shortcut's title.
|
||||
info(tree.selectedNode.bookmarkGuid);
|
||||
bookmark = await PlacesUtils.bookmarks.fetch(tree.selectedNode.bookmarkGuid);
|
||||
Assert.equal(bookmark.title, "", "Shortcut title is null");
|
||||
}
|
||||
);
|
||||
});
|
||||
|
|
|
@ -85,15 +85,16 @@ add_task(async function() {
|
|||
|
||||
info("Test that special folders and cannot be moved but other shortcuts can.");
|
||||
let roots = [
|
||||
PlacesUtils.bookmarksMenuFolderId,
|
||||
PlacesUtils.unfiledBookmarksFolderId,
|
||||
PlacesUtils.toolbarFolderId,
|
||||
PlacesUtils.bookmarks.menuGuid,
|
||||
PlacesUtils.bookmarks.unfiledGuid,
|
||||
PlacesUtils.bookmarks.toolbarGuid,
|
||||
];
|
||||
|
||||
for (let id of roots) {
|
||||
selectShortcutForRootId(tree, id);
|
||||
for (let guid of roots) {
|
||||
tree.selectItems([guid]);
|
||||
Assert.ok(!PlacesControllerDragHelper.canMoveNode(tree.selectedNode, tree),
|
||||
"shouldn't be able to move default shortcuts to roots");
|
||||
let id = await PlacesUtils.promiseItemId(guid);
|
||||
let s = await PlacesUtils.bookmarks.insert({
|
||||
parentGuid: root.guid,
|
||||
title: "bar",
|
||||
|
@ -107,14 +108,3 @@ add_task(async function() {
|
|||
}
|
||||
});
|
||||
});
|
||||
|
||||
function selectShortcutForRootId(tree, id) {
|
||||
for (let i = 0; i < tree.result.root.childCount; ++i) {
|
||||
let child = tree.result.root.getChild(i);
|
||||
if (PlacesUtils.getConcreteItemId(child) == id) {
|
||||
tree.selectItems([child.itemId]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
Assert.ok(false, "Cannot find shortcut to root");
|
||||
}
|
||||
|
|
|
@ -88,7 +88,7 @@ add_task(async function test_query_on_toolbar() {
|
|||
"We have correctly selected bookmarks toolbar node.");
|
||||
|
||||
// Check that both cut and delete commands are disabled, cause this is a child
|
||||
// of AllBookmarksFolderId.
|
||||
// of the All Bookmarks special query.
|
||||
ok(PO._places.controller.isCommandEnabled("cmd_copy"),
|
||||
"Copy command is enabled");
|
||||
ok(!PO._places.controller.isCommandEnabled("cmd_cut"),
|
||||
|
|
|
@ -60,25 +60,10 @@ function test() {
|
|||
var query = { name: queryName,
|
||||
itemId,
|
||||
correctTitle: PlacesUtils.bookmarks.getItemTitle(itemId) };
|
||||
switch (queryName) {
|
||||
case "BookmarksToolbar":
|
||||
query.concreteId = PlacesUtils.toolbarFolderId;
|
||||
query.concreteTitle = PlacesUtils.bookmarks.getItemTitle(query.concreteId);
|
||||
break;
|
||||
case "BookmarksMenu":
|
||||
query.concreteId = PlacesUtils.bookmarksMenuFolderId;
|
||||
query.concreteTitle = PlacesUtils.bookmarks.getItemTitle(query.concreteId);
|
||||
break;
|
||||
case "UnfiledBookmarks":
|
||||
query.concreteId = PlacesUtils.unfiledBookmarksFolderId;
|
||||
query.concreteTitle = PlacesUtils.bookmarks.getItemTitle(query.concreteId);
|
||||
break;
|
||||
}
|
||||
|
||||
leftPaneQueries.push(query);
|
||||
// Rename to a bad title.
|
||||
PlacesUtils.bookmarks.setItemTitle(query.itemId, "badName");
|
||||
if ("concreteId" in query)
|
||||
PlacesUtils.bookmarks.setItemTitle(query.concreteId, "badName");
|
||||
}
|
||||
|
||||
restoreLeftPaneGetters();
|
||||
|
|
|
@ -20,16 +20,14 @@ add_task(async function() {
|
|||
}],
|
||||
});
|
||||
|
||||
let library = await promiseLibrary("AllBookmarks");
|
||||
let library = await promiseLibrary("UnfiledBookmarks");
|
||||
registerCleanupFunction(async function() {
|
||||
await promiseLibraryClosed(library);
|
||||
await PlacesUtils.bookmarks.eraseEverything();
|
||||
});
|
||||
|
||||
// Select unfiled later, to ensure it's closed.
|
||||
library.PlacesOrganizer.selectLeftPaneBuiltIn("UnfiledBookmarks");
|
||||
ok(!library.PlacesOrganizer._places.selectedNode.containerOpen,
|
||||
"Unfiled container is closed");
|
||||
// Ensure the container is closed.
|
||||
library.PlacesOrganizer._places.selectedNode.containerOpen = false;
|
||||
|
||||
let folderNode = library.ContentTree.view.view.nodeForTreeIndex(0);
|
||||
is(folderNode.bookmarkGuid, bookmarks[0].guid,
|
||||
|
|
|
@ -32,7 +32,7 @@ var gLibrary;
|
|||
|
||||
var testCases = [
|
||||
function allBookmarksScope() {
|
||||
let defScope = getDefaultScope(PlacesUIUtils.allBookmarksFolderId);
|
||||
let defScope = getDefaultScope(PlacesUIUtils.leftPaneQueries.AllBookmarks);
|
||||
search(PlacesUIUtils.allBookmarksFolderId, "dummy", defScope);
|
||||
},
|
||||
|
||||
|
|
|
@ -6,8 +6,7 @@ ChromeUtils.defineModuleGetter(this, "TestUtils",
|
|||
"resource://testing-common/TestUtils.jsm");
|
||||
|
||||
// We need to cache these before test runs...
|
||||
let leftPaneGetters = new Map([["leftPaneFolderId", null],
|
||||
["allBookmarksFolderId", null]]);
|
||||
let leftPaneGetters = new Map([["leftPaneFolderId", null]]);
|
||||
for (let [key, val] of leftPaneGetters) {
|
||||
if (!val) {
|
||||
let getter = Object.getOwnPropertyDescriptor(PlacesUIUtils, key).get;
|
||||
|
|
|
@ -46,8 +46,7 @@
|
|||
function runTest() {
|
||||
// We need to cache and restore the getters in order to simulate
|
||||
// Bug 510634.
|
||||
let leftPaneGetters = new Map([["leftPaneFolderId", null],
|
||||
["allBookmarksFolderId", null]]);
|
||||
let leftPaneGetters = new Map([["leftPaneFolderId", null]]);
|
||||
for (let [key, val] of leftPaneGetters) {
|
||||
if (!val) {
|
||||
let getter = Object.getOwnPropertyDescriptor(PlacesUIUtils, key).get;
|
||||
|
@ -78,20 +77,34 @@
|
|||
// Open All Bookmarks
|
||||
tree.selectItems([PlacesUIUtils.leftPaneQueries["AllBookmarks"]]);
|
||||
PlacesUtils.asContainer(tree.selectedNode).containerOpen = true;
|
||||
is(PlacesUIUtils.allBookmarksFolderId, tree.selectedNode.itemId,
|
||||
is(tree.selectedNode.uri,
|
||||
"place:type=" + Ci.nsINavHistoryQueryOptions.RESULTS_AS_ROOTS_QUERY +
|
||||
"&queryType=" + Ci.nsINavHistoryQueryOptions.QUERY_TYPE_BOOKMARKS,
|
||||
"Opened All Bookmarks");
|
||||
|
||||
["History", "Downloads", "Tags", "AllBookmarks", "BookmarksToolbar",
|
||||
"BookmarksMenu", "UnfiledBookmarks"].forEach(
|
||||
function(aQueryName, aRow) {
|
||||
let found = false;
|
||||
for (let i = 0; i < tree.view.rowCount && !found; i++) {
|
||||
rowProperties = tree.view.getCellProperties(i, titleColumn).split(" ");
|
||||
found = rowProperties.includes("OrganizerQuery_" + aQueryName);
|
||||
}
|
||||
ok(found, "OrganizerQuery_" + aQueryName + " is set");
|
||||
for (let queryName of ["History", "Downloads", "Tags", "AllBookmarks"]) {
|
||||
let found = false;
|
||||
for (let i = 0; i < tree.view.rowCount && !found; i++) {
|
||||
rowProperties = tree.view.getCellProperties(i, titleColumn).split(" ");
|
||||
found = rowProperties.includes("OrganizerQuery_" + queryName);
|
||||
}
|
||||
);
|
||||
ok(found, "OrganizerQuery_" + queryName + " is set");
|
||||
}
|
||||
|
||||
const folderGuids = [
|
||||
PlacesUtils.bookmarks.toolbarGuid,
|
||||
PlacesUtils.bookmarks.menuGuid,
|
||||
PlacesUtils.bookmarks.unfiledGuid,
|
||||
];
|
||||
|
||||
for (let guid of folderGuids) {
|
||||
let found = false;
|
||||
for (let i = 0; i < tree.view.rowCount && !found; i++) {
|
||||
rowProperties = tree.view.getCellProperties(i, titleColumn).split(" ");
|
||||
found = rowProperties.includes("queryFolder_" + guid);
|
||||
}
|
||||
ok(found, "queryFolder_" + guid + " is set");
|
||||
}
|
||||
|
||||
// Close the root node
|
||||
tree.result.root.containerOpen = false;
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
|
||||
// Used to store the original leftPaneFolderId getter.
|
||||
var gLeftPaneFolderIdGetter;
|
||||
var gAllBookmarksFolderIdGetter;
|
||||
// Used to store the original left Pane status as a JSON string.
|
||||
var gReferenceHierarchy;
|
||||
var gLeftPaneFolderId;
|
||||
|
@ -25,8 +24,6 @@ add_task(async function() {
|
|||
// Check getters.
|
||||
gLeftPaneFolderIdGetter = Object.getOwnPropertyDescriptor(PlacesUIUtils, "leftPaneFolderId");
|
||||
Assert.equal(typeof(gLeftPaneFolderIdGetter.get), "function");
|
||||
gAllBookmarksFolderIdGetter = Object.getOwnPropertyDescriptor(PlacesUIUtils, "allBookmarksFolderId");
|
||||
Assert.equal(typeof(gAllBookmarksFolderIdGetter.get), "function");
|
||||
|
||||
registerCleanupFunction(() => PlacesUtils.bookmarks.eraseEverything());
|
||||
});
|
||||
|
@ -52,12 +49,11 @@ add_task(async function() {
|
|||
|
||||
while (gTests.length) {
|
||||
// Run current test.
|
||||
await gTests.shift();
|
||||
await gTests.shift()();
|
||||
|
||||
// Regenerate getters.
|
||||
Object.defineProperty(PlacesUIUtils, "leftPaneFolderId", gLeftPaneFolderIdGetter);
|
||||
gLeftPaneFolderId = PlacesUIUtils.leftPaneFolderId;
|
||||
Object.defineProperty(PlacesUIUtils, "allBookmarksFolderId", gAllBookmarksFolderIdGetter);
|
||||
|
||||
// Check the new left pane folder.
|
||||
let leftPaneHierarchy = folderIdToHierarchy(gLeftPaneFolderId);
|
||||
|
@ -89,13 +85,7 @@ var gTests = [
|
|||
},
|
||||
|
||||
async function test4() {
|
||||
print("4. Delete AllBookmarks.");
|
||||
let guid = await PlacesUtils.promiseItemGuid(PlacesUIUtils.allBookmarksFolderId);
|
||||
await PlacesUtils.bookmarks.remove(guid);
|
||||
},
|
||||
|
||||
async function test5() {
|
||||
print("5. Create a duplicated left pane folder.");
|
||||
print("4. Create a duplicated left pane folder.");
|
||||
let folder = await PlacesUtils.bookmarks.insert({
|
||||
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
|
||||
title: "PlacesRoot",
|
||||
|
@ -109,8 +99,8 @@ var gTests = [
|
|||
PlacesUtils.annotations.EXPIRE_NEVER);
|
||||
},
|
||||
|
||||
async function test6() {
|
||||
print("6. Create a duplicated left pane query.");
|
||||
async function test5() {
|
||||
print("5. Create a duplicated left pane query.");
|
||||
let folder = await PlacesUtils.bookmarks.insert({
|
||||
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
|
||||
title: "AllBookmarks",
|
||||
|
@ -124,25 +114,11 @@ var gTests = [
|
|||
PlacesUtils.annotations.EXPIRE_NEVER);
|
||||
},
|
||||
|
||||
function test7() {
|
||||
print("7. Remove the left pane folder annotation.");
|
||||
function test6() {
|
||||
print("6. Remove the left pane folder annotation.");
|
||||
PlacesUtils.annotations.removeItemAnnotation(gLeftPaneFolderId,
|
||||
ORGANIZER_FOLDER_ANNO);
|
||||
},
|
||||
|
||||
function test8() {
|
||||
print("8. Remove a left pane query annotation.");
|
||||
PlacesUtils.annotations.removeItemAnnotation(PlacesUIUtils.allBookmarksFolderId,
|
||||
ORGANIZER_QUERY_ANNO);
|
||||
},
|
||||
|
||||
async function test9() {
|
||||
print("9. Remove a child of AllBookmarks.");
|
||||
let guid = await PlacesUtils.promiseItemGuid(PlacesUIUtils.allBookmarksFolderId);
|
||||
let bm = await PlacesUtils.bookmarks.fetch({parentGuid: guid, index: 0});
|
||||
await PlacesUtils.bookmarks.remove(bm.guid);
|
||||
}
|
||||
|
||||
];
|
||||
|
||||
/**
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
var SelectBookmarkDialog = {
|
||||
init: function SBD_init() {
|
||||
document.getElementById("bookmarks").place =
|
||||
"place:queryType=1&folder=" + PlacesUIUtils.allBookmarksFolderId;
|
||||
"place:type=" + Ci.nsINavHistoryQueryOptions.RESULTS_AS_ROOTS_QUERY;
|
||||
|
||||
// Initial update of the OK button.
|
||||
this.selectionChanged();
|
||||
|
|
|
@ -37,23 +37,19 @@ treechildren::-moz-tree-image(title, separator) {
|
|||
margin: 0;
|
||||
}
|
||||
|
||||
treechildren::-moz-tree-image(container, OrganizerQuery_AllBookmarks) {
|
||||
list-style-image: url("chrome://browser/skin/places/allBookmarks.png");
|
||||
}
|
||||
|
||||
treechildren::-moz-tree-image(container, livemark) {
|
||||
list-style-image: url("chrome://browser/skin/places/folder-live.svg");
|
||||
}
|
||||
|
||||
treechildren::-moz-tree-image(container, OrganizerQuery_BookmarksToolbar) {
|
||||
treechildren::-moz-tree-image(container, queryFolder_toolbar_____) {
|
||||
list-style-image: url("chrome://browser/skin/places/bookmarksToolbar.svg");
|
||||
}
|
||||
|
||||
treechildren::-moz-tree-image(container, OrganizerQuery_BookmarksMenu) {
|
||||
treechildren::-moz-tree-image(container, queryFolder_menu________) {
|
||||
list-style-image: url("chrome://browser/skin/places/bookmarksMenu.svg");
|
||||
}
|
||||
|
||||
treechildren::-moz-tree-image(container, OrganizerQuery_UnfiledBookmarks) {
|
||||
treechildren::-moz-tree-image(container, queryFolder_unfiled_____) {
|
||||
list-style-image: url("chrome://browser/skin/places/unfiledBookmarks.svg");
|
||||
}
|
||||
|
||||
|
@ -62,6 +58,10 @@ treechildren::-moz-tree-image(query) {
|
|||
list-style-image: url("chrome://browser/skin/places/folder-smart.svg");
|
||||
}
|
||||
|
||||
treechildren::-moz-tree-image(query, OrganizerQuery_AllBookmarks) {
|
||||
list-style-image: url("chrome://browser/skin/places/allBookmarks.png");
|
||||
}
|
||||
|
||||
treechildren::-moz-tree-image(query, OrganizerQuery_Downloads) {
|
||||
list-style-image: url("chrome://browser/skin/places/downloads.png");
|
||||
}
|
||||
|
|
|
@ -280,97 +280,6 @@ add_task(async function test_responder_missing_items() {
|
|||
await cleanup(server);
|
||||
});
|
||||
|
||||
add_task(async function test_non_syncable() {
|
||||
let server = await makeServer();
|
||||
|
||||
await Service.sync(); // to create the collections on the server.
|
||||
|
||||
// Creates the left pane queries as a side effect.
|
||||
let leftPaneId = PlacesUIUtils.leftPaneFolderId;
|
||||
_(`Left pane root ID: ${leftPaneId}`);
|
||||
await PlacesTestUtils.promiseAsyncUpdates();
|
||||
|
||||
// A child folder of the left pane root, containing queries for the menu,
|
||||
// toolbar, and unfiled queries.
|
||||
let allBookmarksId = PlacesUIUtils.leftPaneQueries.AllBookmarks;
|
||||
let allBookmarksGuid = await PlacesUtils.promiseItemGuid(allBookmarksId);
|
||||
|
||||
let unfiledQueryId = PlacesUIUtils.leftPaneQueries.UnfiledBookmarks;
|
||||
let unfiledQueryGuid = await PlacesUtils.promiseItemGuid(unfiledQueryId);
|
||||
|
||||
// Put the "Bookmarks Menu" on the server to simulate old bugs.
|
||||
let bookmarksMenuQueryId = PlacesUIUtils.leftPaneQueries.BookmarksMenu;
|
||||
let bookmarksMenuQueryGuid = await PlacesUtils.promiseItemGuid(bookmarksMenuQueryId);
|
||||
let collection = getServerBookmarks(server);
|
||||
collection.insert(bookmarksMenuQueryGuid, "doesn't matter");
|
||||
|
||||
// Explicitly request the unfiled and allBookmarksGuid queries; these will
|
||||
// get tombstones. Because the BookmarksMenu is already on the server it
|
||||
// should be removed even though it wasn't requested. We should ignore the
|
||||
// toolbar query as it wasn't explicitly requested and isn't on the server.
|
||||
let request = {
|
||||
request: "upload",
|
||||
ids: [allBookmarksGuid, unfiledQueryGuid],
|
||||
flowID: Utils.makeGUID(),
|
||||
};
|
||||
let responder = new BookmarkRepairResponder();
|
||||
await responder.repair(request, null);
|
||||
|
||||
checkRecordedEvents([
|
||||
{ object: "repairResponse",
|
||||
method: "uploading",
|
||||
value: undefined,
|
||||
// Tombstones for the 2 items we requested and for bookmarksMenu
|
||||
extra: {flowID: request.flowID, numIDs: "3"},
|
||||
},
|
||||
]);
|
||||
|
||||
_("Sync to upload tombstones for items");
|
||||
await Service.sync();
|
||||
|
||||
let toolbarQueryId = PlacesUIUtils.leftPaneQueries.BookmarksToolbar;
|
||||
let menuQueryId = PlacesUIUtils.leftPaneQueries.BookmarksMenu;
|
||||
let queryGuids = [
|
||||
allBookmarksGuid,
|
||||
await PlacesUtils.promiseItemGuid(toolbarQueryId),
|
||||
await PlacesUtils.promiseItemGuid(menuQueryId),
|
||||
unfiledQueryGuid,
|
||||
];
|
||||
|
||||
deepEqual(collection.keys().sort(), [
|
||||
// We always upload roots on the first sync.
|
||||
"menu",
|
||||
"mobile",
|
||||
"toolbar",
|
||||
"unfiled",
|
||||
...request.ids,
|
||||
bookmarksMenuQueryGuid,
|
||||
].sort(), "Should upload roots and queries on first sync");
|
||||
|
||||
for (let guid of queryGuids) {
|
||||
let wbo = collection.wbo(guid);
|
||||
if (request.ids.includes(guid) || guid == bookmarksMenuQueryGuid) {
|
||||
// explicitly requested or already on the server, so should have a tombstone.
|
||||
let payload = JSON.parse(JSON.parse(wbo.payload).ciphertext);
|
||||
ok(payload.deleted, `Should upload tombstone for left pane query ${guid}`);
|
||||
} else {
|
||||
// not explicitly requested and not on the server at the start, so should
|
||||
// not be on the server now.
|
||||
ok(!wbo, `Should not upload anything for left pane query ${guid}`);
|
||||
}
|
||||
}
|
||||
|
||||
checkRecordedEvents([
|
||||
{ object: "repairResponse",
|
||||
method: "finished",
|
||||
value: undefined,
|
||||
extra: {flowID: request.flowID, numIDs: "3"},
|
||||
},
|
||||
]);
|
||||
|
||||
await cleanup(server);
|
||||
});
|
||||
|
||||
add_task(async function test_folder_descendants() {
|
||||
let server = await makeServer();
|
||||
|
||||
|
|
|
@ -135,22 +135,42 @@ var Bookmarks = Object.freeze({
|
|||
* Special GUIDs associated with bookmark roots.
|
||||
* It's guaranteed that the roots will always have these guids.
|
||||
*/
|
||||
rootGuid: "root________",
|
||||
menuGuid: "menu________",
|
||||
toolbarGuid: "toolbar_____",
|
||||
unfiledGuid: "unfiled_____",
|
||||
mobileGuid: "mobile______",
|
||||
|
||||
rootGuid: "root________",
|
||||
menuGuid: "menu________",
|
||||
toolbarGuid: "toolbar_____",
|
||||
unfiledGuid: "unfiled_____",
|
||||
mobileGuid: "mobile______",
|
||||
// With bug 424160, tags will stop being bookmarks, thus this root will
|
||||
// be removed. Do not rely on this, rather use the tagging service API.
|
||||
tagsGuid: "tags________",
|
||||
|
||||
// With bug 424160, tags will stop being bookmarks, thus this root will
|
||||
// be removed. Do not rely on this, rather use the tagging service API.
|
||||
tagsGuid: "tags________",
|
||||
/**
|
||||
* The GUIDs of the user content root folders that we support, for easy access
|
||||
* as a set.
|
||||
*/
|
||||
userContentRoots: ["toolbar_____", "menu________", "unfiled_____", "mobile______"],
|
||||
|
||||
/**
|
||||
* The GUIDs of the user content root folders that we support, for easy access
|
||||
* as a set.
|
||||
*/
|
||||
userContentRoots: ["toolbar_____", "menu________", "unfiled_____", "mobile______"],
|
||||
/**
|
||||
* GUIDs associated with virtual queries that are used for display in the left
|
||||
* pane.
|
||||
*/
|
||||
virtualMenuGuid: "menu_______v",
|
||||
virtualToolbarGuid: "toolbar____v",
|
||||
virtualUnfiledGuid: "unfiled___v",
|
||||
virtualMobileGuid: "mobile____v",
|
||||
|
||||
/**
|
||||
* Checks if a guid is a virtual root.
|
||||
*
|
||||
* @param {String} guid The guid of the item to look for.
|
||||
* @returns {Boolean} true if guid is a virtual root, false otherwise.
|
||||
*/
|
||||
isVirtualRootItem(guid) {
|
||||
return guid == PlacesUtils.bookmarks.virtualMenuGuid ||
|
||||
guid == PlacesUtils.bookmarks.virtualToolbarGuid ||
|
||||
guid == PlacesUtils.bookmarks.virtualUnfiledGuid;
|
||||
},
|
||||
|
||||
/**
|
||||
* Inserts a bookmark-item into the bookmarks tree.
|
||||
|
|
|
@ -49,9 +49,6 @@ const { SOURCE_SYNC } = Ci.nsINavBookmarksService;
|
|||
const MICROSECONDS_PER_SECOND = 1000000;
|
||||
const SQLITE_MAX_VARIABLE_NUMBER = 999;
|
||||
|
||||
const ORGANIZER_QUERY_ANNO = "PlacesOrganizer/OrganizerQuery";
|
||||
const ORGANIZER_ALL_BOOKMARKS_ANNO_VALUE = "AllBookmarks";
|
||||
const ORGANIZER_MOBILE_QUERY_ANNO_VALUE = "MobileBookmarks";
|
||||
const MOBILE_BOOKMARKS_PREF = "browser.bookmarks.showMobileBookmarks";
|
||||
|
||||
// These are defined as lazy getters to defer initializing the bookmarks
|
||||
|
@ -1061,70 +1058,15 @@ const BookmarkSyncUtils = PlacesSyncUtils.bookmarks = Object.freeze({
|
|||
|
||||
Services.prefs.setBoolPref(MOBILE_BOOKMARKS_PREF, hasMobileBookmarks);
|
||||
if (hasMobileBookmarks) {
|
||||
await this.upsertMobileQuery(db);
|
||||
} else {
|
||||
await this.removeMobileQuery(db);
|
||||
}
|
||||
},
|
||||
let mobileTitle = PlacesUtils.getString("MobileBookmarksFolderTitle");
|
||||
|
||||
async upsertMobileQuery(db) {
|
||||
let maybeAllBookmarksGuids = await fetchGuidsWithAnno(db,
|
||||
ORGANIZER_QUERY_ANNO, ORGANIZER_ALL_BOOKMARKS_ANNO_VALUE);
|
||||
if (!maybeAllBookmarksGuids.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
let allBookmarksGuid = maybeAllBookmarksGuids[0];
|
||||
let mobileTitle = PlacesUtils.getString("MobileBookmarksFolderTitle");
|
||||
|
||||
let maybeMobileQueryGuids = await fetchGuidsWithAnno(db,
|
||||
ORGANIZER_QUERY_ANNO, ORGANIZER_MOBILE_QUERY_ANNO_VALUE);
|
||||
if (maybeMobileQueryGuids.length) {
|
||||
let mobileQueryGuid = maybeMobileQueryGuids[0];
|
||||
// We have a left pane query for mobile bookmarks, make sure the
|
||||
// query title is correct.
|
||||
// Make sure the mobile root title matches the query.
|
||||
await PlacesUtils.bookmarks.update({
|
||||
guid: mobileQueryGuid,
|
||||
url: "place:folder=MOBILE_BOOKMARKS",
|
||||
guid: PlacesUtils.bookmarks.mobileGuid,
|
||||
title: mobileTitle,
|
||||
source: SOURCE_SYNC,
|
||||
});
|
||||
} else {
|
||||
// We have no left pane query. Create the query.
|
||||
let mobileQuery = await PlacesUtils.bookmarks.insert({
|
||||
parentGuid: allBookmarksGuid,
|
||||
url: "place:folder=MOBILE_BOOKMARKS",
|
||||
title: mobileTitle,
|
||||
source: SOURCE_SYNC,
|
||||
});
|
||||
|
||||
let mobileQueryId = await PlacesUtils.promiseItemId(mobileQuery.guid);
|
||||
|
||||
PlacesUtils.annotations.setItemAnnotation(mobileQueryId,
|
||||
ORGANIZER_QUERY_ANNO, ORGANIZER_MOBILE_QUERY_ANNO_VALUE, 0,
|
||||
PlacesUtils.annotations.EXPIRE_NEVER, SOURCE_SYNC);
|
||||
PlacesUtils.annotations.setItemAnnotation(mobileQueryId,
|
||||
PlacesUtils.EXCLUDE_FROM_BACKUP_ANNO, 1, 0,
|
||||
PlacesUtils.annotations.EXPIRE_NEVER, SOURCE_SYNC);
|
||||
}
|
||||
|
||||
// Make sure the mobile root title matches the query.
|
||||
await PlacesUtils.bookmarks.update({
|
||||
guid: PlacesUtils.bookmarks.mobileGuid,
|
||||
title: mobileTitle,
|
||||
source: SOURCE_SYNC,
|
||||
});
|
||||
},
|
||||
|
||||
async removeMobileQuery(db) {
|
||||
let maybeMobileQueryGuids = await fetchGuidsWithAnno(db,
|
||||
ORGANIZER_QUERY_ANNO, ORGANIZER_MOBILE_QUERY_ANNO_VALUE);
|
||||
if (!maybeMobileQueryGuids.length) {
|
||||
BookmarkSyncLog.warn("Trying to remove non-existent mobile query");
|
||||
return;
|
||||
}
|
||||
let mobileQueryGuid = maybeMobileQueryGuids[0];
|
||||
await PlacesUtils.bookmarks.remove(mobileQueryGuid);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -113,7 +113,11 @@ function serializeNode(aNode, aIsLivemark) {
|
|||
data.instanceId = PlacesUtils.instanceId;
|
||||
|
||||
let guid = aNode.bookmarkGuid;
|
||||
if (guid) {
|
||||
// Some nodes, e.g. the unfiled/menu/toolbar ones can have a virtual guid, so
|
||||
// we ignore any that are a folder shortcut. These will be handled below.
|
||||
if (guid && !PlacesUtils.bookmarks.isVirtualRootItem(guid)) {
|
||||
// TODO: Really guid should be set on everything, however currently this upsets
|
||||
// the drag 'n' drop / cut/copy/paste operations.
|
||||
data.itemGuid = guid;
|
||||
if (aNode.parent)
|
||||
data.parent = aNode.parent.itemId;
|
||||
|
@ -155,6 +159,7 @@ function serializeNode(aNode, aIsLivemark) {
|
|||
data.type = PlacesUtils.TYPE_X_MOZ_PLACE;
|
||||
data.uri = aNode.uri;
|
||||
data.concreteId = concreteId;
|
||||
data.concreteGuid = PlacesUtils.getConcreteItemGuid(aNode);
|
||||
} else {
|
||||
// This is a bookmark folder.
|
||||
data.type = PlacesUtils.TYPE_X_MOZ_PLACE_CONTAINER;
|
||||
|
@ -432,6 +437,18 @@ this.PlacesUtils = {
|
|||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines if a folder is generated from a query.
|
||||
* @param aNode a result true.
|
||||
* @returns true if the node is a folder generated from a query.
|
||||
*/
|
||||
isQueryGeneratedFolder(node) {
|
||||
if (!node.parent) {
|
||||
return false;
|
||||
}
|
||||
return this.nodeIsFolder(node) && this.nodeIsQuery(node.parent);
|
||||
},
|
||||
|
||||
/**
|
||||
* Determines whether or not a ResultNode is a Bookmark folder.
|
||||
* @param aNode
|
||||
|
|
|
@ -1073,6 +1073,14 @@ interface nsINavHistoryQueryOptions : nsISupports
|
|||
*/
|
||||
const unsigned short RESULTS_AS_TAG_CONTENTS = 7;
|
||||
|
||||
/**
|
||||
* This returns nsINavHistoryQueryResultNode nodes for each top-level bookmark
|
||||
* root.
|
||||
*
|
||||
* @note Setting this resultType will force queryType to QUERY_TYPE_BOOKMARKS.
|
||||
*/
|
||||
const unsigned short RESULTS_AS_ROOTS_QUERY = 8;
|
||||
|
||||
/**
|
||||
* The sorting mode to be used for this query.
|
||||
* mode is one of SORT_BY_*
|
||||
|
|
|
@ -105,6 +105,10 @@ using namespace mozilla::places;
|
|||
#define PREF_FREC_RELOAD_VISIT_BONUS "places.frecency.reloadVisitBonus"
|
||||
#define PREF_FREC_RELOAD_VISIT_BONUS_DEF 0
|
||||
|
||||
// This is a hidden pref to determine when to show the mobile bookmarks folder.
|
||||
// Note: the name here matches those used elsewhere in the code, for easier searching.
|
||||
#define MOBILE_BOOKMARKS_PREF "browser.bookmarks.showMobileBookmarks"
|
||||
|
||||
// This is a 'hidden' pref for the purposes of unit tests.
|
||||
#define PREF_FREC_DECAY_RATE "places.frecency.decayRate"
|
||||
#define PREF_FREC_DECAY_RATE_DEF 0.975f
|
||||
|
@ -832,7 +836,9 @@ nsNavHistory::GetUpdateRequirements(const nsCOMArray<nsNavHistoryQuery>& aQuerie
|
|||
}
|
||||
|
||||
if (aOptions->ResultType() ==
|
||||
nsINavHistoryQueryOptions::RESULTS_AS_TAG_QUERY)
|
||||
nsINavHistoryQueryOptions::RESULTS_AS_TAG_QUERY ||
|
||||
aOptions->ResultType() ==
|
||||
nsINavHistoryQueryOptions::RESULTS_AS_ROOTS_QUERY)
|
||||
return QUERYUPDATE_COMPLEX_WITH_BOOKMARKS;
|
||||
|
||||
// Whenever there is a maximum number of results,
|
||||
|
@ -1415,6 +1421,7 @@ private:
|
|||
nsresult SelectAsDay();
|
||||
nsresult SelectAsSite();
|
||||
nsresult SelectAsTag();
|
||||
nsresult SelectAsRoots();
|
||||
|
||||
nsresult Where();
|
||||
nsresult GroupBy();
|
||||
|
@ -1516,6 +1523,11 @@ PlacesSQLQueryBuilder::Select()
|
|||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
break;
|
||||
|
||||
case nsINavHistoryQueryOptions::RESULTS_AS_ROOTS_QUERY:
|
||||
rv = SelectAsRoots();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
break;
|
||||
|
||||
default:
|
||||
NS_NOTREACHED("Invalid result type");
|
||||
}
|
||||
|
@ -1924,6 +1936,49 @@ PlacesSQLQueryBuilder::SelectAsTag()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
PlacesSQLQueryBuilder::SelectAsRoots()
|
||||
{
|
||||
nsNavHistory *history = nsNavHistory::GetHistoryService();
|
||||
NS_ENSURE_STATE(history);
|
||||
|
||||
nsAutoCString toolbarTitle;
|
||||
nsAutoCString menuTitle;
|
||||
nsAutoCString unfiledTitle;
|
||||
|
||||
history->GetStringFromName("BookmarksToolbarFolderTitle", toolbarTitle);
|
||||
history->GetStringFromName("BookmarksMenuFolderTitle", menuTitle);
|
||||
history->GetStringFromName("OtherBookmarksFolderTitle", unfiledTitle);
|
||||
|
||||
nsAutoCString mobileString;
|
||||
|
||||
if (Preferences::GetBool(MOBILE_BOOKMARKS_PREF, false)) {
|
||||
nsAutoCString mobileTitle;
|
||||
history->GetStringFromName("MobileBookmarksFolderTitle", mobileTitle);
|
||||
|
||||
mobileString = nsPrintfCString(","
|
||||
"(null, 'place:folder=MOBILE_BOOKMARKS', '%s', null, null, null, "
|
||||
"null, null, 0, 0, null, null, null, null, 'mobile____v', null) ",
|
||||
mobileTitle.get());
|
||||
}
|
||||
|
||||
mQueryString = nsPrintfCString(
|
||||
"SELECT * FROM ("
|
||||
"VALUES(null, 'place:folder=TOOLBAR', '%s', null, null, null, "
|
||||
"null, null, 0, 0, null, null, null, null, 'toolbar____v', null), "
|
||||
"(null, 'place:folder=BOOKMARKS_MENU', '%s', null, null, null, "
|
||||
"null, null, 0, 0, null, null, null, null, 'menu_______v', null), "
|
||||
"(null, 'place:folder=UNFILED_BOOKMARKS', '%s', null, null, null, "
|
||||
"null, null, 0, 0, null, null, null, null, 'unfiled___v', null) "
|
||||
" %s "
|
||||
")",
|
||||
toolbarTitle.get(),
|
||||
menuTitle.get(),
|
||||
unfiledTitle.get(),
|
||||
mobileString.get());
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
PlacesSQLQueryBuilder::Where()
|
||||
{
|
||||
|
@ -3570,7 +3625,7 @@ nsNavHistory::FilterResultSet(nsNavHistoryQueryResultNode* aQueryNode,
|
|||
// just retain the first result.
|
||||
if (resultType == nsINavHistoryQueryOptions::RESULTS_AS_TAG_CONTENTS &&
|
||||
(!aSet[nodeIndex]->IsURI() ||
|
||||
nodeIndex > 0 && aSet[nodeIndex]->mURI == aSet[nodeIndex-1]->mURI)) {
|
||||
(nodeIndex > 0 && aSet[nodeIndex]->mURI == aSet[nodeIndex-1]->mURI))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -3791,6 +3846,11 @@ nsNavHistory::RowToResult(mozIStorageValueArray* aRow,
|
|||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
if (aOptions->ResultType() == nsNavHistoryQueryOptions::RESULTS_AS_ROOTS_QUERY) {
|
||||
rv = aRow->GetUTF8String(kGetInfoIndex_Guid, guid);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
RefPtr<nsNavHistoryResultNode> resultNode;
|
||||
rv = QueryRowToResult(itemId, guid, url, title, accessCount, time,
|
||||
getter_AddRefs(resultNode));
|
||||
|
@ -3891,8 +3951,11 @@ nsNavHistory::QueryRowToResult(int64_t itemId,
|
|||
PRTime aTime,
|
||||
nsNavHistoryResultNode** aNode)
|
||||
{
|
||||
MOZ_ASSERT((itemId != -1 && !aBookmarkGuid.IsEmpty()) ||
|
||||
(itemId == -1 && aBookmarkGuid.IsEmpty()));
|
||||
// Only assert if the itemId is set. In some cases (e.g. virtual queries), we
|
||||
// have a guid, but not an itemId.
|
||||
if (itemId != -1) {
|
||||
MOZ_ASSERT(!aBookmarkGuid.IsEmpty());
|
||||
}
|
||||
|
||||
nsCOMArray<nsNavHistoryQuery> queries;
|
||||
nsCOMPtr<nsNavHistoryQueryOptions> options;
|
||||
|
|
|
@ -1359,11 +1359,12 @@ nsNavHistoryQueryOptions::GetResultType(uint16_t* aType)
|
|||
NS_IMETHODIMP
|
||||
nsNavHistoryQueryOptions::SetResultType(uint16_t aType)
|
||||
{
|
||||
if (aType > RESULTS_AS_TAG_CONTENTS)
|
||||
if (aType > RESULTS_AS_ROOTS_QUERY)
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
// Tag queries and containers are bookmarks related, so we set the QueryType
|
||||
// accordingly.
|
||||
if (aType == RESULTS_AS_TAG_QUERY || aType == RESULTS_AS_TAG_CONTENTS)
|
||||
// Tag queries, containers and the roots query are bookmarks related, so we
|
||||
// set the QueryType accordingly.
|
||||
if (aType == RESULTS_AS_TAG_QUERY || aType == RESULTS_AS_TAG_CONTENTS ||
|
||||
aType == RESULTS_AS_ROOTS_QUERY)
|
||||
mQueryType = QUERY_TYPE_BOOKMARKS;
|
||||
mResultType = aType;
|
||||
return NS_OK;
|
||||
|
|
|
@ -1828,7 +1828,8 @@ nsNavHistoryQueryResultNode::IsContainersQuery()
|
|||
return resultType == nsINavHistoryQueryOptions::RESULTS_AS_DATE_QUERY ||
|
||||
resultType == nsINavHistoryQueryOptions::RESULTS_AS_DATE_SITE_QUERY ||
|
||||
resultType == nsINavHistoryQueryOptions::RESULTS_AS_TAG_QUERY ||
|
||||
resultType == nsINavHistoryQueryOptions::RESULTS_AS_SITE_QUERY;
|
||||
resultType == nsINavHistoryQueryOptions::RESULTS_AS_SITE_QUERY ||
|
||||
resultType == nsINavHistoryQueryOptions::RESULTS_AS_ROOTS_QUERY;
|
||||
}
|
||||
|
||||
|
||||
|
@ -1899,7 +1900,9 @@ nsNavHistoryQueryResultNode::GetHasChildren(bool* aHasChildren)
|
|||
uint16_t resultType = mOptions->ResultType();
|
||||
|
||||
// Tags are always populated, otherwise they are removed.
|
||||
if (resultType == nsINavHistoryQueryOptions::RESULTS_AS_TAG_CONTENTS) {
|
||||
if (resultType == nsINavHistoryQueryOptions::RESULTS_AS_TAG_CONTENTS ||
|
||||
// AllBookmarks also always has children.
|
||||
resultType == nsINavHistoryQueryOptions::RESULTS_AS_ROOTS_QUERY) {
|
||||
*aHasChildren = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,102 @@
|
|||
"use strict";
|
||||
|
||||
const MOBILE_BOOKMARKS_PREF = "browser.bookmarks.showMobileBookmarks";
|
||||
|
||||
const expectedRoots = [{
|
||||
title: "BookmarksToolbarFolderTitle",
|
||||
uri: "place:folder=TOOLBAR",
|
||||
guid: PlacesUtils.bookmarks.virtualToolbarGuid,
|
||||
}, {
|
||||
title: "BookmarksMenuFolderTitle",
|
||||
uri: "place:folder=BOOKMARKS_MENU",
|
||||
guid: PlacesUtils.bookmarks.virtualMenuGuid,
|
||||
}, {
|
||||
title: "OtherBookmarksFolderTitle",
|
||||
uri: "place:folder=UNFILED_BOOKMARKS",
|
||||
guid: PlacesUtils.bookmarks.virtualUnfiledGuid,
|
||||
}];
|
||||
|
||||
const expectedRootsWithMobile = [...expectedRoots, {
|
||||
title: "MobileBookmarksFolderTitle",
|
||||
uri: "place:folder=MOBILE_BOOKMARKS",
|
||||
guid: PlacesUtils.bookmarks.virtualMobileGuid,
|
||||
}];
|
||||
|
||||
const placesStrings = Services.strings.createBundle("chrome://places/locale/places.properties");
|
||||
|
||||
function getAllBookmarksQuery() {
|
||||
var query = PlacesUtils.history.getNewQuery();
|
||||
|
||||
// Options
|
||||
var options = PlacesUtils.history.getNewQueryOptions();
|
||||
options.sortingMode = options.SORT_BY_VISITCOUNT_ASCENDING;
|
||||
options.resultType = options.RESULTS_AS_ROOTS_QUERY;
|
||||
|
||||
// Results
|
||||
var result = PlacesUtils.history.executeQuery(query, options);
|
||||
return result.root;
|
||||
}
|
||||
|
||||
function assertExpectedChildren(root, expectedChildren) {
|
||||
Assert.equal(root.childCount, expectedChildren.length, "Should have the expected number of children.");
|
||||
|
||||
for (let i = 0; i < root.childCount; i++) {
|
||||
Assert.equal(root.getChild(i).uri, expectedChildren[i].uri,
|
||||
"Should have the correct uri for root ${i}");
|
||||
Assert.equal(root.getChild(i).title, placesStrings.GetStringFromName(expectedChildren[i].title),
|
||||
"Should have the correct title for root ${i}");
|
||||
Assert.equal(root.getChild(i).bookmarkGuid, expectedChildren[i].guid);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This test will test the basic RESULTS_AS_ROOTS_QUERY, that simply returns,
|
||||
* the existing bookmark roots.
|
||||
*/
|
||||
add_task(async function test_results_as_root() {
|
||||
let root = getAllBookmarksQuery();
|
||||
root.containerOpen = true;
|
||||
|
||||
Assert.equal(PlacesUtils.asQuery(root).queryOptions.queryType,
|
||||
Ci.nsINavHistoryQueryOptions.QUERY_TYPE_BOOKMARKS,
|
||||
"Should have a query type of QUERY_TYPE_BOOKMARKS");
|
||||
|
||||
assertExpectedChildren(root, expectedRoots);
|
||||
|
||||
root.containerOpen = false;
|
||||
});
|
||||
|
||||
add_task(async function test_results_as_root_with_mobile() {
|
||||
Services.prefs.setBoolPref(MOBILE_BOOKMARKS_PREF, true);
|
||||
|
||||
let root = getAllBookmarksQuery();
|
||||
root.containerOpen = true;
|
||||
|
||||
assertExpectedChildren(root, expectedRootsWithMobile);
|
||||
|
||||
root.containerOpen = false;
|
||||
Services.prefs.clearUserPref(MOBILE_BOOKMARKS_PREF);
|
||||
});
|
||||
|
||||
add_task(async function test_results_as_root_remove_mobile_dynamic() {
|
||||
Services.prefs.setBoolPref(MOBILE_BOOKMARKS_PREF, true);
|
||||
|
||||
let root = getAllBookmarksQuery();
|
||||
root.containerOpen = true;
|
||||
|
||||
// Now un-set the pref, and poke the database to update the query.
|
||||
Services.prefs.clearUserPref(MOBILE_BOOKMARKS_PREF);
|
||||
|
||||
// We've un-set the pref, but we still expect the mobile folder to be there
|
||||
// until the database is poked.
|
||||
assertExpectedChildren(root, expectedRootsWithMobile);
|
||||
|
||||
await PlacesUtils.bookmarks.insert({
|
||||
parentGuid: PlacesUtils.bookmarks.menuGuid,
|
||||
url: "http://example.com",
|
||||
});
|
||||
|
||||
assertExpectedChildren(root, expectedRoots);
|
||||
|
||||
root.containerOpen = false;
|
||||
});
|
|
@ -17,6 +17,7 @@ skip-if = (os == 'win' && ccov) # Bug 1423667
|
|||
[test_queryMultipleFolder.js]
|
||||
[test_querySerialization.js]
|
||||
[test_redirects.js]
|
||||
[test_results-as-roots.js]
|
||||
[test_results-as-tag-contents-query.js]
|
||||
[test_results-as-visit.js]
|
||||
[test_search_tags.js]
|
||||
|
|
|
@ -2888,16 +2888,9 @@ add_task(async function test_migrateOldTrackerEntries() {
|
|||
});
|
||||
|
||||
add_task(async function test_ensureMobileQuery() {
|
||||
info("Ensure we correctly create the mobile query");
|
||||
|
||||
let PlacesUIUtils;
|
||||
try {
|
||||
PlacesUIUtils = ChromeUtils.import("resource:///modules/PlacesUIUtils.jsm", {}).PlacesUIUtils;
|
||||
PlacesUIUtils.maybeRebuildLeftPane();
|
||||
} catch (ex) {
|
||||
info("Can't build left pane roots; skipping test");
|
||||
return;
|
||||
}
|
||||
info("Ensure we correctly set the showMobileBookmarks preference");
|
||||
const mobilePref = "browser.bookmarks.showMobileBookmarks";
|
||||
Services.prefs.clearUserPref(mobilePref);
|
||||
|
||||
await PlacesUtils.bookmarks.insert({
|
||||
guid: "bookmarkAAAA",
|
||||
|
@ -2913,65 +2906,18 @@ add_task(async function test_ensureMobileQuery() {
|
|||
title: "B",
|
||||
});
|
||||
|
||||
// Creates the organizer queries as a side effect.
|
||||
let leftPaneId = PlacesUIUtils.leftPaneFolderId;
|
||||
info(`Left pane root ID: ${leftPaneId}`);
|
||||
|
||||
let allBookmarksGuids = await PlacesSyncUtils.bookmarks.fetchGuidsWithAnno(
|
||||
"PlacesOrganizer/OrganizerQuery", "AllBookmarks");
|
||||
equal(allBookmarksGuids.length, 1, "Should create folder with all bookmarks queries");
|
||||
let allBookmarkGuid = allBookmarksGuids[0];
|
||||
|
||||
info("Try creating query after organizer is ready");
|
||||
await PlacesSyncUtils.bookmarks.ensureMobileQuery();
|
||||
let queryGuids = await PlacesSyncUtils.bookmarks.fetchGuidsWithAnno(
|
||||
"PlacesOrganizer/OrganizerQuery", "MobileBookmarks");
|
||||
equal(queryGuids.length, 1, "Should create query because we have bookmarks A and B");
|
||||
|
||||
let queryGuid = queryGuids[0];
|
||||
|
||||
let queryInfo = await PlacesUtils.bookmarks.fetch(queryGuid);
|
||||
equal(queryInfo.url, `place:folder=MOBILE_BOOKMARKS`, "Query should point to mobile root");
|
||||
equal(queryInfo.title, "Mobile Bookmarks", "Query title should be localized");
|
||||
equal(queryInfo.parentGuid, allBookmarkGuid, "Should append mobile query to all bookmarks queries");
|
||||
|
||||
info("Rename root and query, then recreate");
|
||||
await PlacesUtils.bookmarks.update({
|
||||
guid: PlacesUtils.bookmarks.mobileGuid,
|
||||
title: "renamed root",
|
||||
});
|
||||
await PlacesUtils.bookmarks.update({
|
||||
guid: queryGuid,
|
||||
title: "renamed query",
|
||||
});
|
||||
await PlacesSyncUtils.bookmarks.ensureMobileQuery();
|
||||
let rootInfo = await PlacesUtils.bookmarks.fetch(PlacesUtils.bookmarks.mobileGuid);
|
||||
equal(rootInfo.title, "Mobile Bookmarks", "Should fix root title");
|
||||
queryInfo = await PlacesUtils.bookmarks.fetch(queryGuid);
|
||||
equal(queryInfo.title, "Mobile Bookmarks", "Should fix query title");
|
||||
|
||||
info("Point query to different folder");
|
||||
await PlacesUtils.bookmarks.update({
|
||||
guid: queryGuid,
|
||||
url: "place:folder=BOOKMARKS_MENU",
|
||||
});
|
||||
await PlacesSyncUtils.bookmarks.ensureMobileQuery();
|
||||
queryInfo = await PlacesUtils.bookmarks.fetch(queryGuid);
|
||||
equal(queryInfo.url.href, `place:folder=MOBILE_BOOKMARKS`,
|
||||
"Should fix query URL to point to mobile root");
|
||||
|
||||
info("We shouldn't track the query or the left pane root");
|
||||
|
||||
let changes = await PlacesSyncUtils.bookmarks.pullChanges();
|
||||
ok(!(queryGuid in changes), "Should not track mobile query");
|
||||
Assert.ok(Services.prefs.getBoolPref(mobilePref),
|
||||
"Pref should be true where there are bookmarks in the folder.");
|
||||
|
||||
await PlacesUtils.bookmarks.remove("bookmarkAAAA");
|
||||
await PlacesUtils.bookmarks.remove("bookmarkBBBB");
|
||||
|
||||
await PlacesSyncUtils.bookmarks.ensureMobileQuery();
|
||||
|
||||
queryGuids = await PlacesSyncUtils.bookmarks.fetchGuidsWithAnno(
|
||||
"PlacesOrganizer/OrganizerQuery", "MobileBookmarks");
|
||||
equal(queryGuids.length, 0, "Should delete query since there are no bookmarks");
|
||||
Assert.ok(!Services.prefs.getBoolPref(mobilePref),
|
||||
"Pref should be false where there are no bookmarks in the folder.");
|
||||
|
||||
await PlacesUtils.bookmarks.eraseEverything();
|
||||
await PlacesSyncUtils.bookmarks.reset();
|
||||
|
|
Загрузка…
Ссылка в новой задаче