- add sources.
[platform/framework/web/crosswalk.git] / src / chrome / browser / resources / bookmark_manager / js / bmm.js
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.
4
5 cr.define('bmm', function() {
6   var Promise = cr.Promise;
7
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   }
26
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   }
34
35   var loadingPromises = {};
36
37   /**
38    * Loads a subtree of the bookmark tree and returns a {@code cr.Promise} that
39    * will be fulfilled when done. This reuses multiple loads so that we do not
40    * load the same subtree more than once at the same time.
41    * @return {!cr.Promise} The future promise for the load.
42    */
43   function loadSubtree(id) {
44     var p = new Promise;
45     if (!(id in loadingPromises)) {
46       loadingPromises[id] = new Promise;
47       loadingPromises[id].addListener(function(n) {
48         p.value = n;
49       });
50       chrome.bookmarkManagerPrivate.getSubtree(id, false, function(nodes) {
51         loadingPromises[id].value = nodes && nodes[0];
52         delete loadingPromises[id];
53       });
54     } else {
55       loadingPromises[id].addListener(function(n) {
56         p.value = n;
57       });
58     }
59     return p;
60   }
61
62   /**
63    * Loads the entire bookmark tree and returns a {@code cr.Promise} that will
64    * be fulfilled when done. This reuses multiple loads so that we do not load
65    * the same tree more than once at the same time.
66    * @return {!cr.Promise} The future promise for the load.
67    */
68   function loadTree() {
69     return loadSubtree('');
70   }
71
72   var bookmarkCache = {
73     /**
74      * Removes the cached item from both the list and tree lookups.
75      */
76     remove: function(id) {
77       var treeItem = bmm.treeLookup[id];
78       if (treeItem) {
79         var items = treeItem.items; // is an HTMLCollection
80         for (var i = 0; i < items.length; ++i) {
81           var item = items[i];
82           var bookmarkNode = item.bookmarkNode;
83           delete bmm.treeLookup[bookmarkNode.id];
84         }
85         delete bmm.treeLookup[id];
86       }
87     },
88
89     /**
90      * Updates the underlying bookmark node for the tree items and list items by
91      * querying the bookmark backend.
92      * @param {string} id The id of the node to update the children for.
93      * @param {Function=} opt_f A funciton to call when done.
94      */
95     updateChildren: function(id, opt_f) {
96       function updateItem(bookmarkNode) {
97         var treeItem = bmm.treeLookup[bookmarkNode.id];
98         if (treeItem) {
99           treeItem.bookmarkNode = bookmarkNode;
100         }
101       }
102
103       chrome.bookmarks.getChildren(id, function(children) {
104         if (children)
105           children.forEach(updateItem);
106
107         if (opt_f)
108           opt_f(children);
109       });
110     }
111   };
112
113   /**
114    * Called when the title of a bookmark changes.
115    * @param {string} id The id of changed bookmark node.
116    * @param {!Object} changeInfo The information about how the node changed.
117    */
118   function handleBookmarkChanged(id, changeInfo) {
119     if (bmm.tree)
120       bmm.tree.handleBookmarkChanged(id, changeInfo);
121     if (bmm.list)
122       bmm.list.handleBookmarkChanged(id, changeInfo);
123   }
124
125   /**
126    * Callback for when the user reorders by title.
127    * @param {string} id The id of the bookmark folder that was reordered.
128    * @param {!Object} reorderInfo The information about how the items where
129    *     reordered.
130    */
131   function handleChildrenReordered(id, reorderInfo) {
132     if (bmm.tree)
133       bmm.tree.handleChildrenReordered(id, reorderInfo);
134     if (bmm.list)
135       bmm.list.handleChildrenReordered(id, reorderInfo);
136     bookmarkCache.updateChildren(id);
137   }
138
139   /**
140    * Callback for when a bookmark node is created.
141    * @param {string} id The id of the newly created bookmark node.
142    * @param {!Object} bookmarkNode The new bookmark node.
143    */
144   function handleCreated(id, bookmarkNode) {
145     if (bmm.list)
146       bmm.list.handleCreated(id, bookmarkNode);
147     if (bmm.tree)
148       bmm.tree.handleCreated(id, bookmarkNode);
149     bookmarkCache.updateChildren(bookmarkNode.parentId);
150   }
151
152   /**
153    * Callback for when a bookmark node is moved.
154    * @param {string} id The id of the moved bookmark node.
155    * @param {!Object} moveInfo The information about move.
156    */
157   function handleMoved(id, moveInfo) {
158     if (bmm.list)
159       bmm.list.handleMoved(id, moveInfo);
160     if (bmm.tree)
161       bmm.tree.handleMoved(id, moveInfo);
162
163     bookmarkCache.updateChildren(moveInfo.parentId);
164     if (moveInfo.parentId != moveInfo.oldParentId)
165       bookmarkCache.updateChildren(moveInfo.oldParentId);
166   }
167
168   /**
169    * Callback for when a bookmark node is removed.
170    * @param {string} id The id of the removed bookmark node.
171    * @param {!Object} bookmarkNode The information about removed.
172    */
173   function handleRemoved(id, removeInfo) {
174     if (bmm.list)
175       bmm.list.handleRemoved(id, removeInfo);
176     if (bmm.tree)
177       bmm.tree.handleRemoved(id, removeInfo);
178
179     bookmarkCache.updateChildren(removeInfo.parentId);
180     bookmarkCache.remove(id);
181   }
182
183   /**
184    * Callback for when all bookmark nodes have been deleted.
185    */
186   function handleRemoveAll() {
187     // Reload the list and the tree.
188     if (bmm.list)
189       bmm.list.reload();
190     if (bmm.tree)
191       bmm.tree.reload();
192   }
193
194   /**
195    * Callback for when importing bookmark is started.
196    */
197   function handleImportBegan() {
198     chrome.bookmarks.onCreated.removeListener(handleCreated);
199     chrome.bookmarks.onChanged.removeListener(handleBookmarkChanged);
200   }
201
202   /**
203    * Callback for when importing bookmark node is finished.
204    */
205   function handleImportEnded() {
206     // When importing is done we reload the tree and the list.
207
208     function f() {
209       bmm.tree.removeEventListener('load', f);
210
211       chrome.bookmarks.onCreated.addListener(handleCreated);
212       chrome.bookmarks.onChanged.addListener(handleBookmarkChanged);
213
214       if (!bmm.list)
215         return;
216
217       // TODO(estade): this should navigate to the newly imported folder, which
218       // may be the bookmark bar if there were no previous bookmarks.
219       bmm.list.reload();
220     }
221
222     if (bmm.tree) {
223       bmm.tree.addEventListener('load', f);
224       bmm.tree.reload();
225     }
226   }
227
228   /**
229    * Adds the listeners for the bookmark model change events.
230    */
231   function addBookmarkModelListeners() {
232     chrome.bookmarks.onChanged.addListener(handleBookmarkChanged);
233     chrome.bookmarks.onChildrenReordered.addListener(handleChildrenReordered);
234     chrome.bookmarks.onCreated.addListener(handleCreated);
235     chrome.bookmarks.onMoved.addListener(handleMoved);
236     chrome.bookmarks.onRemoved.addListener(handleRemoved);
237     chrome.bookmarks.onImportBegan.addListener(handleImportBegan);
238     chrome.bookmarks.onImportEnded.addListener(handleImportEnded);
239   };
240
241   return {
242     contains: contains,
243     isFolder: isFolder,
244     loadSubtree: loadSubtree,
245     loadTree: loadTree,
246     addBookmarkModelListeners: addBookmarkModelListeners
247   };
248 });