Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / resources / bookmark_manager / js / bmm.js
blob06fd50d97ea7d7332dbf273e7dcbacc0df0f52f0
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 cr.define('bmm', function() {
6   'use strict';
8   /**
9    * Whether a node contains another node.
10    * TODO(yosin): Once JavaScript style guide is updated and linter follows
11    * that, we'll remove useless documentations for |parent| and |descendant|.
12    * TODO(yosin): bmm.contains() should be method of BookmarkTreeNode.
13    * @param {!BookmarkTreeNode} parent .
14    * @param {!BookmarkTreeNode} descendant .
15    * @return {boolean} Whether the parent contains the descendant.
16    */
17   function contains(parent, descendant) {
18     if (descendant.parentId == parent.id)
19       return true;
20     // the bmm.treeLookup contains all folders
21     var parentTreeItem = bmm.treeLookup[descendant.parentId];
22     if (!parentTreeItem || !parentTreeItem.bookmarkNode)
23       return false;
24     return this.contains(parent, parentTreeItem.bookmarkNode);
25   }
27   /**
28    * @param {!BookmarkTreeNode} node The node to test.
29    * @return {boolean} Whether a bookmark node is a folder.
30    */
31   function isFolder(node) {
32     return !('url' in node);
33   }
35   var loadingPromises = {};
37   /**
38    * Promise version of chrome.bookmarkManagerPrivate.getSubtree.
39    * @param {string} id .
40    * @param {boolean} foldersOnly .
41    * @return {!Promise<!Array<!BookmarkTreeNode>>} .
42    */
43   function getSubtreePromise(id, foldersOnly) {
44     return new Promise(function(resolve, reject) {
45       chrome.bookmarkManagerPrivate.getSubtree(id, foldersOnly, function(node) {
46         if (chrome.runtime.lastError) {
47           reject(new Error(chrome.runtime.lastError.message));
48           return;
49         }
50         resolve(node);
51       });
52     });
53   }
55   /**
56    * Loads a subtree of the bookmark tree and returns a {@code Promise} that
57    * will be fulfilled when done. This reuses multiple loads so that we do not
58    * load the same subtree more than once at the same time.
59    * @return {!Promise<!BookmarkTreeNode>} The future promise for the load.
60    */
61   function loadSubtree(id) {
62     if (!loadingPromises[id]) {
63       loadingPromises[id] = getSubtreePromise(id, false).then(function(nodes) {
64         return nodes && nodes[0];
65       }, function(error) {
66         console.error(error.message);
67       });
68       loadingPromises[id].then(function() {
69         delete loadingPromises[id];
70       });
71     }
72     return loadingPromises[id];
73   }
75   /**
76    * Loads the entire bookmark tree and returns a {@code Promise} that will
77    * be fulfilled when done. This reuses multiple loads so that we do not load
78    * the same tree more than once at the same time.
79    * @return {!Promise<!BookmarkTreeNode>} The future promise for the load.
80    */
81   function loadTree() {
82     return loadSubtree('');
83   }
85   var bookmarkCache = {
86     /**
87      * Removes the cached item from both the list and tree lookups.
88      */
89     remove: function(id) {
90       var treeItem = bmm.treeLookup[id];
91       if (treeItem) {
92         var items = treeItem.items; // is an HTMLCollection
93         for (var i = 0; i < items.length; ++i) {
94           var item = items[i];
95           var bookmarkNode = item.bookmarkNode;
96           delete bmm.treeLookup[bookmarkNode.id];
97         }
98         delete bmm.treeLookup[id];
99       }
100     },
102     /**
103      * Updates the underlying bookmark node for the tree items and list items by
104      * querying the bookmark backend.
105      * @param {string} id The id of the node to update the children for.
106      * @param {Function=} opt_f A funciton to call when done.
107      */
108     updateChildren: function(id, opt_f) {
109       function updateItem(bookmarkNode) {
110         var treeItem = bmm.treeLookup[bookmarkNode.id];
111         if (treeItem) {
112           treeItem.bookmarkNode = bookmarkNode;
113         }
114       }
116       chrome.bookmarks.getChildren(id, function(children) {
117         if (children)
118           children.forEach(updateItem);
120         if (opt_f)
121           opt_f(children);
122       });
123     }
124   };
126   /**
127    * Called when the title of a bookmark changes.
128    * @param {string} id The id of changed bookmark node.
129    * @param {!Object} changeInfo The information about how the node changed.
130    */
131   function handleBookmarkChanged(id, changeInfo) {
132     if (bmm.tree)
133       bmm.tree.handleBookmarkChanged(id, changeInfo);
134     if (bmm.list)
135       bmm.list.handleBookmarkChanged(id, changeInfo);
136   }
138   /**
139    * Callback for when the user reorders by title.
140    * @param {string} id The id of the bookmark folder that was reordered.
141    * @param {!Object} reorderInfo The information about how the items where
142    *     reordered.
143    */
144   function handleChildrenReordered(id, reorderInfo) {
145     if (bmm.tree)
146       bmm.tree.handleChildrenReordered(id, reorderInfo);
147     if (bmm.list)
148       bmm.list.handleChildrenReordered(id, reorderInfo);
149     bookmarkCache.updateChildren(id);
150   }
152   /**
153    * Callback for when a bookmark node is created.
154    * @param {string} id The id of the newly created bookmark node.
155    * @param {!Object} bookmarkNode The new bookmark node.
156    */
157   function handleCreated(id, bookmarkNode) {
158     if (bmm.list)
159       bmm.list.handleCreated(id, bookmarkNode);
160     if (bmm.tree)
161       bmm.tree.handleCreated(id, bookmarkNode);
162     bookmarkCache.updateChildren(bookmarkNode.parentId);
163   }
165   /**
166    * Callback for when a bookmark node is moved.
167    * @param {string} id The id of the moved bookmark node.
168    * @param {!Object} moveInfo The information about move.
169    */
170   function handleMoved(id, moveInfo) {
171     if (bmm.list)
172       bmm.list.handleMoved(id, moveInfo);
173     if (bmm.tree)
174       bmm.tree.handleMoved(id, moveInfo);
176     bookmarkCache.updateChildren(moveInfo.parentId);
177     if (moveInfo.parentId != moveInfo.oldParentId)
178       bookmarkCache.updateChildren(moveInfo.oldParentId);
179   }
181   /**
182    * Callback for when a bookmark node is removed.
183    * @param {string} id The id of the removed bookmark node.
184    * @param {!Object} removeInfo The information about removed.
185    */
186   function handleRemoved(id, removeInfo) {
187     if (bmm.list)
188       bmm.list.handleRemoved(id, removeInfo);
189     if (bmm.tree)
190       bmm.tree.handleRemoved(id, removeInfo);
192     bookmarkCache.updateChildren(removeInfo.parentId);
193     bookmarkCache.remove(id);
194   }
196   /**
197    * Callback for when all bookmark nodes have been deleted.
198    */
199   function handleRemoveAll() {
200     // Reload the list and the tree.
201     if (bmm.list)
202       bmm.list.reload();
203     if (bmm.tree)
204       bmm.tree.reload();
205   }
207   /**
208    * Callback for when importing bookmark is started.
209    */
210   function handleImportBegan() {
211     chrome.bookmarks.onCreated.removeListener(handleCreated);
212     chrome.bookmarks.onChanged.removeListener(handleBookmarkChanged);
213   }
215   /**
216    * Callback for when importing bookmark node is finished.
217    */
218   function handleImportEnded() {
219     // When importing is done we reload the tree and the list.
221     function f() {
222       bmm.tree.removeEventListener('load', f);
224       chrome.bookmarks.onCreated.addListener(handleCreated);
225       chrome.bookmarks.onChanged.addListener(handleBookmarkChanged);
227       if (!bmm.list)
228         return;
230       // TODO(estade): this should navigate to the newly imported folder, which
231       // may be the bookmark bar if there were no previous bookmarks.
232       bmm.list.reload();
233     }
235     if (bmm.tree) {
236       bmm.tree.addEventListener('load', f);
237       bmm.tree.reload();
238     }
239   }
241   /**
242    * Adds the listeners for the bookmark model change events.
243    */
244   function addBookmarkModelListeners() {
245     chrome.bookmarks.onChanged.addListener(handleBookmarkChanged);
246     chrome.bookmarks.onChildrenReordered.addListener(handleChildrenReordered);
247     chrome.bookmarks.onCreated.addListener(handleCreated);
248     chrome.bookmarks.onMoved.addListener(handleMoved);
249     chrome.bookmarks.onRemoved.addListener(handleRemoved);
250     chrome.bookmarks.onImportBegan.addListener(handleImportBegan);
251     chrome.bookmarks.onImportEnded.addListener(handleImportEnded);
252   };
254   return {
255     contains: contains,
256     isFolder: isFolder,
257     loadSubtree: loadSubtree,
258     loadTree: loadTree,
259     addBookmarkModelListeners: addBookmarkModelListeners
260   };