OLD | NEW |
1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * @fileoverview Listener functions which translate events from the | 6 * @fileoverview Listener functions which translate events from the |
7 * chrome.bookmarks API into actions to modify the local page state. | 7 * chrome.bookmarks API into actions to modify the local page state. |
8 */ | 8 */ |
9 | 9 |
10 cr.define('bookmarks.ApiListener', function() { | 10 cr.define('bookmarks.ApiListener', function() { |
11 | 11 |
12 /** @type {?number} */ | 12 /** @type {boolean} */ |
13 var timerHandle; | 13 var trackUpdates = false; |
| 14 /** @type {!Array<string>} */ |
| 15 var updatedItems = []; |
| 16 |
| 17 var debouncer; |
14 | 18 |
15 /** | 19 /** |
16 * Batches UI updates so that no changes will be made to UI until the next | 20 * Batches UI updates so that no changes will be made to UI until the next |
17 * task after the last call to this method. This is useful for listeners which | 21 * task after the last call to this method. This is useful for listeners which |
18 * can be called in a tight loop by UI actions. | 22 * can be called in a tight loop by UI actions. |
19 */ | 23 */ |
20 function batchUIUpdates() { | 24 function batchUIUpdates() { |
21 if (timerHandle) | 25 if (!debouncer || debouncer.done()) { |
22 clearTimeout(timerHandle); | |
23 else | |
24 bookmarks.Store.getInstance().beginBatchUpdate(); | 26 bookmarks.Store.getInstance().beginBatchUpdate(); |
| 27 debouncer = new bookmarks.Debouncer( |
| 28 () => bookmarks.Store.getInstance().endBatchUpdate()); |
| 29 } |
25 | 30 |
26 timerHandle = setTimeout(function() { | 31 debouncer.resetTimeout(); |
27 bookmarks.Store.getInstance().endBatchUpdate(); | 32 } |
28 timerHandle = null; | 33 |
29 }); | 34 /** |
| 35 * Tracks any items that are created or moved. |
| 36 */ |
| 37 function trackUpdatedItems() { |
| 38 trackUpdates = true; |
| 39 } |
| 40 |
| 41 function highlightUpdatedItemsImpl() { |
| 42 if (!trackUpdates) |
| 43 return; |
| 44 |
| 45 document.dispatchEvent(new CustomEvent('highlight-items', { |
| 46 detail: updatedItems, |
| 47 })); |
| 48 updatedItems = []; |
| 49 trackUpdates = false; |
| 50 } |
| 51 |
| 52 /** |
| 53 * Highlights any items that have been updated since |trackUpdatedItems| was |
| 54 * called. Should be called after a user action causes new items to appear in |
| 55 * the main list. |
| 56 */ |
| 57 function highlightUpdatedItems() { |
| 58 // Ensure that the items are highlighted after the current batch update (if |
| 59 // there is one) is completed. |
| 60 assert(debouncer); |
| 61 debouncer.promise.then(highlightUpdatedItemsImpl); |
30 } | 62 } |
31 | 63 |
32 /** @param {Action} action */ | 64 /** @param {Action} action */ |
33 function dispatch(action) { | 65 function dispatch(action) { |
34 bookmarks.Store.getInstance().dispatch(action); | 66 bookmarks.Store.getInstance().dispatch(action); |
35 } | 67 } |
36 | 68 |
37 /** | 69 /** |
38 * @param {string} id | 70 * @param {string} id |
39 * @param {{title: string, url: (string|undefined)}} changeInfo | 71 * @param {{title: string, url: (string|undefined)}} changeInfo |
40 */ | 72 */ |
41 function onBookmarkChanged(id, changeInfo) { | 73 function onBookmarkChanged(id, changeInfo) { |
42 dispatch(bookmarks.actions.editBookmark(id, changeInfo)); | 74 dispatch(bookmarks.actions.editBookmark(id, changeInfo)); |
43 } | 75 } |
44 | 76 |
45 /** | 77 /** |
46 * @param {string} id | 78 * @param {string} id |
47 * @param {BookmarkTreeNode} treeNode | 79 * @param {BookmarkTreeNode} treeNode |
48 */ | 80 */ |
49 function onBookmarkCreated(id, treeNode) { | 81 function onBookmarkCreated(id, treeNode) { |
50 batchUIUpdates(); | 82 batchUIUpdates(); |
| 83 if (trackUpdatedItems) |
| 84 updatedItems.push(id); |
51 dispatch(bookmarks.actions.createBookmark(id, treeNode)); | 85 dispatch(bookmarks.actions.createBookmark(id, treeNode)); |
52 } | 86 } |
53 | 87 |
54 /** | 88 /** |
55 * @param {string} id | 89 * @param {string} id |
56 * @param {{parentId: string, index: number}} removeInfo | 90 * @param {{parentId: string, index: number}} removeInfo |
57 */ | 91 */ |
58 function onBookmarkRemoved(id, removeInfo) { | 92 function onBookmarkRemoved(id, removeInfo) { |
59 batchUIUpdates(); | 93 batchUIUpdates(); |
60 var nodes = bookmarks.Store.getInstance().data.nodes; | 94 var nodes = bookmarks.Store.getInstance().data.nodes; |
61 dispatch(bookmarks.actions.removeBookmark( | 95 dispatch(bookmarks.actions.removeBookmark( |
62 id, removeInfo.parentId, removeInfo.index, nodes)); | 96 id, removeInfo.parentId, removeInfo.index, nodes)); |
63 } | 97 } |
64 | 98 |
65 /** | 99 /** |
66 * @param {string} id | 100 * @param {string} id |
67 * @param {{ | 101 * @param {{ |
68 * parentId: string, | 102 * parentId: string, |
69 * index: number, | 103 * index: number, |
70 * oldParentId: string, | 104 * oldParentId: string, |
71 * oldIndex: number | 105 * oldIndex: number |
72 * }} moveInfo | 106 * }} moveInfo |
73 */ | 107 */ |
74 function onBookmarkMoved(id, moveInfo) { | 108 function onBookmarkMoved(id, moveInfo) { |
75 batchUIUpdates(); | 109 batchUIUpdates(); |
| 110 if (trackUpdatedItems) |
| 111 updatedItems.push(id); |
76 dispatch(bookmarks.actions.moveBookmark( | 112 dispatch(bookmarks.actions.moveBookmark( |
77 id, moveInfo.parentId, moveInfo.index, moveInfo.oldParentId, | 113 id, moveInfo.parentId, moveInfo.index, moveInfo.oldParentId, |
78 moveInfo.oldIndex)); | 114 moveInfo.oldIndex)); |
79 } | 115 } |
80 | 116 |
81 /** | 117 /** |
82 * @param {string} id | 118 * @param {string} id |
83 * @param {{childIds: !Array<string>}} reorderInfo | 119 * @param {{childIds: !Array<string>}} reorderInfo |
84 */ | 120 */ |
85 function onChildrenReordered(id, reorderInfo) { | 121 function onChildrenReordered(id, reorderInfo) { |
(...skipping 23 matching lines...) Expand all Loading... |
109 dispatch(bookmarks.actions.setIncognitoAvailability(availability)); | 145 dispatch(bookmarks.actions.setIncognitoAvailability(availability)); |
110 } | 146 } |
111 | 147 |
112 /** | 148 /** |
113 * @param {boolean} canEdit | 149 * @param {boolean} canEdit |
114 */ | 150 */ |
115 function onCanEditBookmarksChanged(canEdit) { | 151 function onCanEditBookmarksChanged(canEdit) { |
116 dispatch(bookmarks.actions.setCanEditBookmarks(canEdit)); | 152 dispatch(bookmarks.actions.setCanEditBookmarks(canEdit)); |
117 } | 153 } |
118 | 154 |
| 155 var listeners = [ |
| 156 {api: chrome.bookmarks.onChanged, fn: onBookmarkChanged}, |
| 157 {api: chrome.bookmarks.onChildrenReordered, fn: onChildrenReordered}, |
| 158 {api: chrome.bookmarks.onCreated, fn: onBookmarkCreated}, |
| 159 {api: chrome.bookmarks.onMoved, fn: onBookmarkMoved}, |
| 160 {api: chrome.bookmarks.onRemoved, fn: onBookmarkRemoved}, |
| 161 {api: chrome.bookmarks.onImportBegan, fn: onImportBegan}, |
| 162 {api: chrome.bookmarks.onImportEnded, fn: onImportEnded}, |
| 163 ]; |
| 164 |
119 function init() { | 165 function init() { |
120 chrome.bookmarks.onChanged.addListener(onBookmarkChanged); | 166 listeners.forEach((listener) => listener.api.addListener(listener.fn)); |
121 chrome.bookmarks.onChildrenReordered.addListener(onChildrenReordered); | |
122 chrome.bookmarks.onCreated.addListener(onBookmarkCreated); | |
123 chrome.bookmarks.onMoved.addListener(onBookmarkMoved); | |
124 chrome.bookmarks.onRemoved.addListener(onBookmarkRemoved); | |
125 chrome.bookmarks.onImportBegan.addListener(onImportBegan); | |
126 chrome.bookmarks.onImportEnded.addListener(onImportEnded); | |
127 | 167 |
128 cr.sendWithPromise('getIncognitoAvailability') | 168 cr.sendWithPromise('getIncognitoAvailability') |
129 .then(onIncognitoAvailabilityChanged); | 169 .then(onIncognitoAvailabilityChanged); |
130 cr.addWebUIListener( | 170 cr.addWebUIListener( |
131 'incognito-availability-changed', onIncognitoAvailabilityChanged); | 171 'incognito-availability-changed', onIncognitoAvailabilityChanged); |
132 | 172 |
133 cr.sendWithPromise('getCanEditBookmarks').then(onCanEditBookmarksChanged); | 173 cr.sendWithPromise('getCanEditBookmarks').then(onCanEditBookmarksChanged); |
134 cr.addWebUIListener( | 174 cr.addWebUIListener( |
135 'can-edit-bookmarks-changed', onCanEditBookmarksChanged); | 175 'can-edit-bookmarks-changed', onCanEditBookmarksChanged); |
136 } | 176 } |
137 | 177 |
| 178 function destroy() { |
| 179 listeners.forEach((listener) => listener.api.removeListener(listener.fn)); |
| 180 cr.removeWebUIListener( |
| 181 'incognito-availability-changed', onIncognitoAvailabilityChanged); |
| 182 cr.removeWebUIListener( |
| 183 'can-edit-bookmarks-changed', onCanEditBookmarksChanged); |
| 184 } |
| 185 |
138 return { | 186 return { |
139 init: init, | 187 init: init, |
| 188 destroy: destroy, |
| 189 trackUpdatedItems: trackUpdatedItems, |
| 190 highlightUpdatedItems: highlightUpdatedItems, |
140 }; | 191 }; |
141 }); | 192 }); |
OLD | NEW |