| // 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 |
| }; |
| }); |