Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(81)

Side by Side Diff: chrome/browser/resources/md_downloads/manager.js

Issue 1240853002: Slice MD downloads into more components (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: compile Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 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 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 cr.define('downloads', function() { 5 cr.define('downloads', function() {
6 /** 6 /**
7 * Class to own and manage download items. 7 * Class to own and manage download items.
8 * @constructor 8 * @constructor
9 * @implements {downloads.ActionService}
9 */ 10 */
10 function Manager() {} 11 function Manager() {}
11 12
12 cr.addSingletonGetter(Manager); 13 cr.addSingletonGetter(Manager);
13 14
15 /**
16 * @param {string} chromeSendName
17 * @return {function(string):void} A chrome.send() callback with curried name.
18 */
19 function chromeSendWithId(chromeSendName) {
20 return function(id) { chrome.send(chromeSendName, [id]); };
21 }
22
14 Manager.prototype = { 23 Manager.prototype = {
15 /** @private {string} */ 24 /** @override */
16 searchText_: '', 25 cancel: chromeSendWithId('cancel'),
17 26
18 /** 27 /** @override */
19 * Sets the search text, updates related UIs, and tells the browser. 28 clearAll: function() {
20 * @param {string} searchText Text we're searching for. 29 if (loadTimeData.getBoolean('allowDeletingHistory')) {
21 * @private 30 chrome.send('clearAll');
22 */ 31 this.search('');
23 setSearchText_: function(searchText) { 32 }
24 this.searchText_ = searchText; 33 },
25 34
26 $('downloads-summary-text').textContent = this.searchText_ ? 35 /** @override */
27 loadTimeData.getStringF('searchResultsFor', this.searchText_) : ''; 36 discardDangerous: chromeSendWithId('discardDangerous'),
28 37
38 /** @override */
39 drag: chromeSendWithId('drag'),
40
41 /** @override */
42 openDownloadsFolder: function() {
43 chrome.send('openDownloadsFolder');
44 },
45
46 /** @override */
47 openFile: chromeSendWithId('openFile'),
48
49 /** @override */
50 pause: chromeSendWithId('pause'),
51
52 /** @override */
53 remove: chromeSendWithId('remove'),
54
55 /** @override */
56 resume: chromeSendWithId('resume'),
57
58 /** @override */
59 saveDangerous: chromeSendWithId('saveDangerous'),
60
61 /** @override */
62 search: function(searchText) {
29 // Split quoted terms (e.g., 'The "lazy" dog' => ['The', 'lazy', 'dog']). 63 // Split quoted terms (e.g., 'The "lazy" dog' => ['The', 'lazy', 'dog']).
30 function trim(s) { return s.trim(); } 64 function trim(s) { return s.trim(); }
31 chrome.send('getDownloads', searchText.split(/"([^"]*)"/).map(trim)); 65 chrome.send('getDownloads', searchText.split(/"([^"]*)"/).map(trim));
32 }, 66 },
33 67
68 /** @override */
69 show: chromeSendWithId('show'),
70
71 /**
72 * @return {boolean} Whether all can be cleared.
73 * @private
74 */
75 canClearAll_: function() {
76 return loadTimeData.getBoolean('allowDeletingHistory') &&
77 this.size_() > 0;
78 },
79
34 /** 80 /**
35 * @return {number} A guess at how many items could be visible at once. 81 * @return {number} A guess at how many items could be visible at once.
36 * @private 82 * @private
37 */ 83 */
38 guesstimateNumberOfVisibleItems_: function() { 84 guesstimateNumberOfVisibleItems_: function() {
39 var toolbarHeight = $('downloads-toolbar').offsetHeight; 85 var toolbarHeight = this.toolbar_.offsetHeight;
40 var summaryHeight = $('downloads-summary').offsetHeight; 86 return Math.floor((window.innerHeight - toolbarHeight) / 46) + 1;
41 var nonItemSpace = toolbarHeight + summaryHeight;
42 return Math.floor((window.innerHeight - nonItemSpace) / 46) + 1;
43 }, 87 },
44 88
45 /** 89 /**
46 * Called when all items need to be updated. 90 * Called when all items need to be updated.
47 * @param {!Array<!downloads.Data>} list A list of new download data. 91 * @param {!Array<!downloads.Data>} list A list of new download data.
48 * @private 92 * @private
49 */ 93 */
50 updateAll_: function(list) { 94 updateAll_: function(list) {
51 var oldIdMap = this.idMap_ || {}; 95 var oldIdMap = this.idMap_ || {};
52 96
53 /** @private {!Object<!downloads.ItemView>} */ 97 /** @private {!Object<!downloads.ItemView>} */
54 this.idMap_ = {}; 98 this.idMap_ = {};
55 99
56 /** @private {!Array<!downloads.ItemView>} */ 100 /** @private {!Array<!downloads.ItemView>} */
57 this.items_ = []; 101 this.items_ = [];
58 102
59 if (!this.iconLoader_) { 103 if (!this.iconLoader_) {
60 var guesstimate = Math.max(this.guesstimateNumberOfVisibleItems_(), 1); 104 var guesstimate = Math.max(this.guesstimateNumberOfVisibleItems_(), 1);
61 /** @private {downloads.ThrottledIconLoader} */ 105 /** @private {downloads.ThrottledIconLoader} */
62 this.iconLoader_ = new downloads.ThrottledIconLoader(guesstimate); 106 this.iconLoader_ = new downloads.ThrottledIconLoader(guesstimate);
63 } 107 }
64 108
65 for (var i = 0; i < list.length; ++i) { 109 for (var i = 0; i < list.length; ++i) {
66 var data = list[i]; 110 var data = list[i];
67 var id = data.id; 111 var id = data.id;
68 112
69 // Re-use old items when possible (saves work, preserves focus). 113 // Re-use old items when possible (saves work, preserves focus).
70 var item = oldIdMap[id] || new downloads.ItemView(this.iconLoader_); 114 var item =
115 oldIdMap[id] || new downloads.ItemView(this.iconLoader_, this);
71 116
72 this.idMap_[id] = item; // Associated by ID for fast lookup. 117 this.idMap_[id] = item; // Associated by ID for fast lookup.
73 this.items_.push(item); // Add to sorted list for order. 118 this.items_.push(item); // Add to sorted list for order.
74 119
75 // Render |item| but don't actually add to the DOM yet. |this.items_| 120 // Render |item| but don't actually add to the DOM yet. |this.items_|
76 // must be fully created to be able to find the right spot to insert. 121 // must be fully created to be able to find the right spot to insert.
77 item.update(data); 122 item.update(data);
78 123
79 // Collapse redundant dates. 124 // Collapse redundant dates.
80 var prev = list[i - 1]; 125 var prev = list[i - 1];
(...skipping 14 matching lines...) Expand all
95 if (item.parentNode) // Already in the DOM; skip. 140 if (item.parentNode) // Already in the DOM; skip.
96 continue; 141 continue;
97 142
98 var before = null; 143 var before = null;
99 // Find the next rendered item after this one, and insert before it. 144 // Find the next rendered item after this one, and insert before it.
100 for (var j = i + 1; !before && j < this.items_.length; ++j) { 145 for (var j = i + 1; !before && j < this.items_.length; ++j) {
101 if (this.items_[j].parentNode) 146 if (this.items_[j].parentNode)
102 before = this.items_[j]; 147 before = this.items_[j];
103 } 148 }
104 // If |before| is null, |item| will just get added at the end. 149 // If |before| is null, |item| will just get added at the end.
105 this.node_.insertBefore(item, before); 150 this.list_.insertBefore(item, before);
106 } 151 }
107 152
108 var noDownloadsOrResults = $('no-downloads-or-results');
109 noDownloadsOrResults.textContent = loadTimeData.getString(
110 this.searchText_ ? 'noSearchResults' : 'noDownloads');
111
112 var hasDownloads = this.size_() > 0; 153 var hasDownloads = this.size_() > 0;
113 this.node_.hidden = !hasDownloads; 154 this.list_.hidden = !hasDownloads;
114 noDownloadsOrResults.hidden = hasDownloads; 155 $('no-downloads').hidden = hasDownloads;
115 156
116 if (loadTimeData.getBoolean('allowDeletingHistory')) 157 if (loadTimeData.getBoolean('allowDeletingHistory'))
117 $('clear-all').hidden = !hasDownloads || this.searchText_.length > 0; 158 this.toolbar_.canClearAll = hasDownloads;
118 }, 159 },
119 160
120 /** 161 /**
121 * @param {!downloads.Data} data 162 * @param {!downloads.Data} data
122 * @private 163 * @private
123 */ 164 */
124 updateItem_: function(data) { 165 updateItem_: function(data) {
125 this.idMap_[data.id].update(data); 166 this.idMap_[data.id].update(data);
126 }, 167 },
127 168
128 /** 169 /**
129 * @return {number} The number of downloads shown on the page. 170 * @return {number} The number of downloads shown on the page.
130 * @private 171 * @private
131 */ 172 */
132 size_: function() { 173 size_: function() {
133 return this.items_.length; 174 return this.items_.length;
134 }, 175 },
135 176
136 /** @private */
137 clearAll_: function() {
138 if (loadTimeData.getBoolean('allowDeletingHistory')) {
139 chrome.send('clearAll');
140 this.setSearchText_('');
141 }
142 },
143
144 /** @private */
145 onLoad_: function() {
146 this.node_ = $('downloads-display');
147
148 $('clear-all').onclick = function() {
149 this.clearAll_();
150 }.bind(this);
151
152 $('open-downloads-folder').onclick = function() {
153 chrome.send('openDownloadsFolder');
154 };
155
156 $('search-button').onclick = function() {
157 if (!$('search-term').hidden)
158 return;
159 $('clear-search').hidden = false;
160 $('search-term').hidden = false;
161 };
162
163 $('clear-search').onclick = function() {
164 $('clear-search').hidden = true;
165 $('search-term').hidden = true;
166 $('search-term').value = '';
167 this.setSearchText_('');
168 }.bind(this);
169
170 // TODO(dbeam): this previously used onsearch, which batches keystrokes
171 // together. This should probably be re-instated eventually.
172 $('search-term').oninput = function(e) {
173 this.setSearchText_($('search-term').value);
174 }.bind(this);
175
176 cr.ui.decorate('command', cr.ui.Command);
177 document.addEventListener('canExecute', this.onCanExecute_.bind(this));
178 document.addEventListener('command', this.onCommand_.bind(this));
179
180 this.setSearchText_('');
181 },
182
183 /** 177 /**
184 * @param {Event} e 178 * @param {Event} e
185 * @private 179 * @private
186 */ 180 */
187 onCanExecute_: function(e) { 181 onCanExecute_: function(e) {
188 e = /** @type {cr.ui.CanExecuteEvent} */(e); 182 e = /** @type {cr.ui.CanExecuteEvent} */(e);
189 switch (e.command.id) { 183 switch (e.command.id) {
190 case 'undo-command': 184 case 'undo-command':
191 e.canExecute = !$('search-term').contains(document.activeElement); 185 var activeElement = document.activeElement;
186 var searchTerm = this.toolbar_ && this.toolbar_.searchTerm;
187 e.canExecute = searchTerm && !searchTerm.contains(activeElement);
Jeremy Klein 2015/07/16 18:54:53 This is a cool trick for determining focus. I've n
Dan Beam 2015/07/18 01:02:20 Acknowledged.
192 break; 188 break;
193 case 'clear-all-command': 189 case 'clear-all-command':
194 e.canExecute = true; 190 e.canExecute = true;
195 break; 191 break;
196 } 192 }
197 }, 193 },
198 194
199 /** 195 /**
200 * @param {Event} e 196 * @param {Event} e
201 * @private 197 * @private
202 */ 198 */
203 onCommand_: function(e) { 199 onCommand_: function(e) {
204 if (e.command.id == 'undo-command') 200 if (e.command.id == 'undo-command')
205 chrome.send('undo'); 201 chrome.send('undo');
206 else if (e.command.id == 'clear-all-command') 202 else if (e.command.id == 'clear-all-command')
207 this.clearAll_(); 203 this.clearAll();
204 },
205
206 /** @private */
207 onLoad_: function() {
208 this.list_ = $('downloads-list');
209
210 var toolbar = document.querySelector('downloads-toolbar');
211 /** @private {!downloads.Toolbar} */
212 this.toolbar_ = assertInstanceof(toolbar, downloads.Toolbar);
213 this.toolbar_.setActionService(this);
Jeremy Klein 2015/07/16 18:54:53 This creates a circular dependency that makes thes
Dan Beam 2015/07/18 01:02:20 Done.
214
215 cr.ui.decorate('command', cr.ui.Command);
216 document.addEventListener('canExecute', this.onCanExecute_.bind(this));
217 document.addEventListener('command', this.onCommand_.bind(this));
218
219 // Shows all downloads.
220 this.search('');
208 }, 221 },
209 }; 222 };
210 223
211 Manager.updateAll = function(list) {
212 Manager.getInstance().updateAll_(list);
213 };
214
215 Manager.updateItem = function(item) {
216 Manager.getInstance().updateItem_(item);
217 };
218
219 Manager.setSearchText = function(searchText) {
220 Manager.getInstance().setSearchText_(searchText);
221 };
222
223 Manager.onLoad = function() { 224 Manager.onLoad = function() {
224 Manager.getInstance().onLoad_(); 225 Manager.getInstance().onLoad_();
225 }; 226 };
226 227
227 Manager.size = function() { 228 Manager.size = function() {
228 return Manager.getInstance().size_(); 229 return Manager.getInstance().size_();
229 }; 230 };
230 231
232 Manager.updateAll = function(list) {
233 Manager.getInstance().updateAll_(list);
234 };
235
236 Manager.updateItem = function(item) {
237 Manager.getInstance().updateItem_(item);
238 };
239
231 return {Manager: Manager}; 240 return {Manager: Manager};
232 }); 241 });
233 242
234 window.addEventListener('load', downloads.Manager.onLoad); 243 window.addEventListener('load', downloads.Manager.onLoad);
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698