blob: b238f4deabe0d6e3528147a1a971428af8be9698 [file] [log] [blame]
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
cr.define('bmm', function() {
var Promise = cr.Promise;
/**
* Whether a node contains another node.
* TODO(yosin): Once JavaScript style guide is updated and linter follows
* that, we'll remove useless documentations for |parent| and |descendant|.
* TODO(yosin): bmm.contains() should be method of BookmarkTreeNode.
* @param {!BookmarkTreeNode} parent .
* @param {!BookmarkTreeNode} descendant .
* @return {boolean} Whether the parent contains the descendant.
*/
function contains(parent, descendant) {
if (descendant.parentId == parent.id)
return true;
// the bmm.treeLookup contains all folders
var parentTreeItem = bmm.treeLookup[descendant.parentId];
if (!parentTreeItem || !parentTreeItem.bookmarkNode)
return false;
return this.contains(parent, parentTreeItem.bookmarkNode);
}
/**
* @param {!BookmarkTreeNode} node The node to test.
* @return {boolean} Whether a bookmark node is a folder.
*/
function isFolder(node) {
return !('url' in node);
}
var loadingPromises = {};
/**
* Loads a subtree of the bookmark tree and returns a {@code cr.Promise} that
* will be fulfilled when done. This reuses multiple loads so that we do not
* load the same subtree more than once at the same time.
* @return {!cr.Promise} The future promise for the load.
*/
function loadSubtree(id) {
var p = new Promise;
if (!(id in loadingPromises)) {
loadingPromises[id] = new Promise;
loadingPromises[id].addListener(function(n) {
p.value = n;
});
chrome.bookmarkManagerPrivate.getSubtree(id, false, function(nodes) {
loadingPromises[id].value = nodes && nodes[0];
delete loadingPromises[id];
});
} else {
loadingPromises[id].addListener(function(n) {
p.value = n;
});
}
return p;
}
/**
* Loads the entire bookmark tree and returns a {@code cr.Promise} that will
* be fulfilled when done. This reuses multiple loads so that we do not load
* the same tree more than once at the same time.
* @return {!cr.Promise} The future promise for the load.
*/
function loadTree() {
return loadSubtree('');
}
var bookmarkCache = {
/**
* Removes the cached item from both the list and tree lookups.
*/
remove: function(id) {
var treeItem = bmm.treeLookup[id];
if (treeItem) {
var items = treeItem.items; // is an HTMLCollection
for (var i = 0; i < items.length; ++i) {
var item = items[i];
var bookmarkNode = item.bookmarkNode;
delete bmm.treeLookup[bookmarkNode.id];
}
delete bmm.treeLookup[id];
}
},
/**
* Updates the underlying bookmark node for the tree items and list items by
* querying the bookmark backend.
* @param {string} id The id of the node to update the children for.
* @param {Function=} opt_f A funciton to call when done.
*/
updateChildren: function(id, opt_f) {
function updateItem(bookmarkNode) {
var treeItem = bmm.treeLookup[bookmarkNode.id];
if (treeItem) {
treeItem.bookmarkNode = bookmarkNode;
}
}
chrome.bookmarks.getChildren(id, function(children) {
if (children)
children.forEach(updateItem);
if (opt_f)
opt_f(children);
});
}
};
/**
* Called when the title of a bookmark changes.
* @param {string} id The id of changed bookmark node.
* @param {!Object} changeInfo The information about how the node changed.
*/
function handleBookmarkChanged(id, changeInfo) {
if (bmm.tree)
bmm.tree.handleBookmarkChanged(id, changeInfo);
if (bmm.list)
bmm.list.handleBookmarkChanged(id, changeInfo);
}
/**
* Callback for when the user reorders by title.
* @param {string} id The id of the bookmark folder that was reordered.
* @param {!Object} reorderInfo The information about how the items where
* reordered.
*/
function handleChildrenReordered(id, reorderInfo) {
if (bmm.tree)
bmm.tree.handleChildrenReordered(id, reorderInfo);
if (bmm.list)
bmm.list.handleChildrenReordered(id, reorderInfo);
bookmarkCache.updateChildren(id);
}
/**
* Callback for when a bookmark node is created.
* @param {string} id The id of the newly created bookmark node.
* @param {!Object} bookmarkNode The new bookmark node.
*/
function handleCreated(id, bookmarkNode) {
if (bmm.list)
bmm.list.handleCreated(id, bookmarkNode);
if (bmm.tree)
bmm.tree.handleCreated(id, bookmarkNode);
bookmarkCache.updateChildren(bookmarkNode.parentId);
}
/**
* Callback for when a bookmark node is moved.
* @param {string} id The id of the moved bookmark node.
* @param {!Object} moveInfo The information about move.
*/
function handleMoved(id, moveInfo) {
if (bmm.list)
bmm.list.handleMoved(id, moveInfo);
if (bmm.tree)
bmm.tree.handleMoved(id, moveInfo);
bookmarkCache.updateChildren(moveInfo.parentId);
if (moveInfo.parentId != moveInfo.oldParentId)
bookmarkCache.updateChildren(moveInfo.oldParentId);
}
/**
* Callback for when a bookmark node is removed.
* @param {string} id The id of the removed bookmark node.
* @param {!Object} bookmarkNode The information about removed.
*/
function handleRemoved(id, removeInfo) {
if (bmm.list)
bmm.list.handleRemoved(id, removeInfo);
if (bmm.tree)
bmm.tree.handleRemoved(id, removeInfo);
bookmarkCache.updateChildren(removeInfo.parentId);
bookmarkCache.remove(id);
}
/**
* Callback for when all bookmark nodes have been deleted.
*/
function handleRemoveAll() {
// Reload the list and the tree.
if (bmm.list)
bmm.list.reload();
if (bmm.tree)
bmm.tree.reload();
}
/**
* Callback for when importing bookmark is started.
*/
function handleImportBegan() {
chrome.bookmarks.onCreated.removeListener(handleCreated);
chrome.bookmarks.onChanged.removeListener(handleBookmarkChanged);
}
/**
* Callback for when importing bookmark node is finished.
*/
function handleImportEnded() {
// When importing is done we reload the tree and the list.
function f() {
bmm.tree.removeEventListener('load', f);
chrome.bookmarks.onCreated.addListener(handleCreated);
chrome.bookmarks.onChanged.addListener(handleBookmarkChanged);
if (!bmm.list)
return;
// TODO(estade): this should navigate to the newly imported folder, which
// may be the bookmark bar if there were no previous bookmarks.
bmm.list.reload();
}
if (bmm.tree) {
bmm.tree.addEventListener('load', f);
bmm.tree.reload();
}
}
/**
* Adds the listeners for the bookmark model change events.
*/
function addBookmarkModelListeners() {
chrome.bookmarks.onChanged.addListener(handleBookmarkChanged);
chrome.bookmarks.onChildrenReordered.addListener(handleChildrenReordered);
chrome.bookmarks.onCreated.addListener(handleCreated);
chrome.bookmarks.onMoved.addListener(handleMoved);
chrome.bookmarks.onRemoved.addListener(handleRemoved);
chrome.bookmarks.onImportBegan.addListener(handleImportBegan);
chrome.bookmarks.onImportEnded.addListener(handleImportEnded);
};
return {
contains: contains,
isFolder: isFolder,
loadSubtree: loadSubtree,
loadTree: loadTree,
addBookmarkModelListeners: addBookmarkModelListeners
};
});