OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 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('downloads', function() { |
| 6 /** |
| 7 * Class to own and manage download items. |
| 8 * @constructor |
| 9 */ |
| 10 function Manager() {} |
| 11 |
| 12 cr.addSingletonGetter(Manager); |
| 13 |
| 14 Manager.prototype = { |
| 15 /** @private {string} */ |
| 16 searchText_: '', |
| 17 |
| 18 /** |
| 19 * Sets the search text, updates related UIs, and tells the browser. |
| 20 * @param {string} searchText Text we're searching for. |
| 21 */ |
| 22 setSearchText: function(searchText) { |
| 23 this.searchText_ = searchText; |
| 24 |
| 25 $('downloads-summary-text').textContent = this.searchText_ ? |
| 26 loadTimeData.getStringF('searchresultsfor', this.searchText_) : ''; |
| 27 |
| 28 // Split quoted terms (e.g., 'The "lazy" dog' => ['The', 'lazy', 'dog']). |
| 29 function trim(s) { return s.trim(); } |
| 30 chrome.send('getDownloads', searchText.split(/"([^"]*)"/).map(trim)); |
| 31 }, |
| 32 |
| 33 /** |
| 34 * Called when all items need to be updated. |
| 35 * @param {!Array<!downloads.Data>} list A list of new download data. |
| 36 */ |
| 37 updateAll: function(list) { |
| 38 var oldIdMap = this.idMap_ || {}; |
| 39 |
| 40 /** @private {!Object<!downloads.Item>} */ |
| 41 this.idMap_ = {}; |
| 42 |
| 43 /** @private {!Array<!downloads.Item>} */ |
| 44 this.items_ = []; |
| 45 |
| 46 for (var i = 0; i < list.length; ++i) { |
| 47 var data = list[i]; |
| 48 var id = data.id; |
| 49 |
| 50 // Re-use old items when possible (saves work, preserves focus). |
| 51 var item = oldIdMap[id] || new downloads.Item; |
| 52 |
| 53 this.idMap_[id] = item; // Associated by ID for fast lookup. |
| 54 this.items_.push(item); // Add to sorted list for order. |
| 55 |
| 56 // Render |item| but don't actually add to the DOM yet. |this.items_| |
| 57 // must be fully created to be able to find the right spot to insert. |
| 58 item.render(data); |
| 59 |
| 60 // Collapse redundant dates. |
| 61 var prev = list[i - 1]; |
| 62 item.view.dateContainer.hidden = |
| 63 prev && prev.date_string == data.date_string; |
| 64 |
| 65 delete oldIdMap[id]; |
| 66 } |
| 67 |
| 68 // Remove stale, previously rendered items from the DOM. |
| 69 for (var id in oldIdMap) { |
| 70 oldIdMap[id].unrender(); |
| 71 delete oldIdMap[id]; |
| 72 } |
| 73 |
| 74 for (var i = 0; i < this.items_.length; ++i) { |
| 75 var item = this.items_[i]; |
| 76 if (item.view.node.parentNode) // Already in the DOM; skip. |
| 77 continue; |
| 78 |
| 79 var before = null; |
| 80 // Find the next rendered item after this one, and insert before it. |
| 81 for (var j = i + 1; !before && j < this.items_.length; ++j) { |
| 82 if (this.items_[j].view.node.parentNode) |
| 83 before = this.items_[j].view.node; |
| 84 } |
| 85 // If |before| is null, |item| will just get added at the end. |
| 86 this.node_.insertBefore(item.view.node, before); |
| 87 } |
| 88 |
| 89 var noDownloadsOrResults = $('no-downloads-or-results'); |
| 90 noDownloadsOrResults.textContent = loadTimeData.getString( |
| 91 this.searchText_ ? 'no_search_results' : 'no_downloads'); |
| 92 |
| 93 var hasDownloads = this.size() > 0; |
| 94 this.node_.hidden = !hasDownloads; |
| 95 noDownloadsOrResults.hidden = hasDownloads; |
| 96 |
| 97 if (loadTimeData.getBoolean('allow_deleting_history')) |
| 98 $('clear-all').hidden = !hasDownloads || this.searchText_.length > 0; |
| 99 |
| 100 this.rebuildFocusGrid_(); |
| 101 }, |
| 102 |
| 103 /** @param {!downloads.Data} data Info about the item to update. */ |
| 104 updateItem: function(data) { |
| 105 this.idMap_[data.id].render(data); |
| 106 }, |
| 107 |
| 108 /** |
| 109 * Rebuild the focusGrid_ using the elements that each download will have. |
| 110 * @private |
| 111 */ |
| 112 rebuildFocusGrid_: function() { |
| 113 var activeElement = document.activeElement; |
| 114 |
| 115 /** @private {!cr.ui.FocusGrid} */ |
| 116 this.focusGrid_ = this.focusGrid_ || new cr.ui.FocusGrid(); |
| 117 this.focusGrid_.destroy(); |
| 118 |
| 119 this.items_.forEach(function(item) { |
| 120 downloads.FocusRow.decorate(item.view.node, item.view, this.node_); |
| 121 var focusRow = assertInstanceof(item.view.node, downloads.FocusRow); |
| 122 this.focusGrid_.addRow(focusRow); |
| 123 |
| 124 // Focus the equivalent element in the focusRow because the active |
| 125 // element may no longer be visible. |
| 126 if (focusRow.contains(activeElement)) |
| 127 focusRow.getEquivalentElement(activeElement).focus(); |
| 128 }, this); |
| 129 }, |
| 130 |
| 131 /** @return {number} The number of downloads shown on the page. */ |
| 132 size: function() { |
| 133 return this.items_.length; |
| 134 }, |
| 135 |
| 136 clearAll: function() { |
| 137 if (loadTimeData.getBoolean('allow_deleting_history')) { |
| 138 chrome.send('clearAll'); |
| 139 this.setSearchText(''); |
| 140 } |
| 141 }, |
| 142 |
| 143 onLoad: function() { |
| 144 this.node_ = $('downloads-display'); |
| 145 |
| 146 $('clear-all').onclick = function() { |
| 147 this.clearAll(); |
| 148 }.bind(this); |
| 149 |
| 150 $('open-downloads-folder').onclick = function() { |
| 151 chrome.send('openDownloadsFolder'); |
| 152 }; |
| 153 |
| 154 $('term').onsearch = function(e) { |
| 155 this.setSearchText($('term').value); |
| 156 }.bind(this); |
| 157 |
| 158 cr.ui.decorate('command', cr.ui.Command); |
| 159 document.addEventListener('canExecute', this.onCanExecute_.bind(this)); |
| 160 document.addEventListener('command', this.onCommand_.bind(this)); |
| 161 |
| 162 this.setSearchText(''); |
| 163 |
| 164 chrome.send('onPageLoaded'); |
| 165 }, |
| 166 |
| 167 /** |
| 168 * @param {Event} e |
| 169 * @private |
| 170 */ |
| 171 onCanExecute_: function(e) { |
| 172 e = /** @type {cr.ui.CanExecuteEvent} */(e); |
| 173 e.canExecute = document.activeElement != $('term'); |
| 174 }, |
| 175 |
| 176 /** |
| 177 * @param {Event} e |
| 178 * @private |
| 179 */ |
| 180 onCommand_: function(e) { |
| 181 if (e.command.id == 'undo-command') |
| 182 chrome.send('undo'); |
| 183 else if (e.command.id == 'clear-all-command') |
| 184 this.clearAll(); |
| 185 }, |
| 186 }; |
| 187 |
| 188 Manager.updateAll = function(list) { |
| 189 Manager.getInstance().updateAll(list); |
| 190 }; |
| 191 |
| 192 Manager.updateItem = function(item) { |
| 193 Manager.getInstance().updateItem(item); |
| 194 }; |
| 195 |
| 196 Manager.setSearchText = function(searchText) { |
| 197 Manager.getInstance().setSearchText(searchText); |
| 198 }; |
| 199 |
| 200 Manager.onLoad = function() { |
| 201 Manager.getInstance().onLoad(); |
| 202 }; |
| 203 |
| 204 Manager.size = function() { |
| 205 return Manager.getInstance().size(); |
| 206 }; |
| 207 |
| 208 return {Manager: Manager}; |
| 209 }); |
| 210 |
| 211 window.addEventListener('DOMContentLoaded', downloads.Manager.onLoad); |
OLD | NEW |