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

Side by Side Diff: chrome/browser/resources/downloads/downloads.js

Issue 807593005: Make downloads list keyboard shortcuts more consistent. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fix tests Created 5 years, 11 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 (c) 2012 The Chromium Authors. All rights reserved. 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 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 // TODO(jhawkins): Use hidden instead of showInline* and display:none. 5 // TODO(jhawkins): Use hidden instead of showInline* and display:none.
6 6
7 /** 7 /**
8 * The type of the download object. The definition is based on 8 * The type of the download object. The definition is based on
9 * chrome/browser/ui/webui/downloads_dom_handler.cc:CreateDownloadItemValue() 9 * chrome/browser/ui/webui/downloads_dom_handler.cc:CreateDownloadItemValue()
10 * @typedef {{by_ext_id: (string|undefined), 10 * @typedef {{by_ext_id: (string|undefined),
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
70 */ 70 */
71 function createButton(onclick, value) { 71 function createButton(onclick, value) {
72 var button = document.createElement('input'); 72 var button = document.createElement('input');
73 button.type = 'button'; 73 button.type = 'button';
74 button.value = value; 74 button.value = value;
75 button.onclick = onclick; 75 button.onclick = onclick;
76 return button; 76 return button;
77 } 77 }
78 78
79 /////////////////////////////////////////////////////////////////////////////// 79 ///////////////////////////////////////////////////////////////////////////////
80 // DownloadFocusObserver:
81
82 /**
83 * @constructor
84 * @implements {cr.ui.FocusRow.Observer}
85 */
86 function DownloadFocusObserver() {}
87
88 DownloadFocusObserver.prototype = {
89 /** @override */
90 onActivate: function(row) {},
91
92 /** @override */
93 onDeactivate: function(row) {},
94
95 /**
96 * @param {Element} item The row item to find a a row element for.
97 * @return {Element} |row|'s "active" element.
98 * @override
99 */
100 getRowElement: function(item) {
101 return findAncestorByClass(item, 'download');
102 },
103
104 /** @override */
105 onElementIdMiss: function(row, expectedId) {
106 // These are at the same level visually, so focus the first available one if
107 // it exists.
108 var remaining = ['show', 'retry', 'pause', 'resume', 'remove', 'cancel'];
109 if (remaining.indexOf(expectedId) > -1) {
110 for (var i = 0; i < remaining.length; ++i) {
111 if (row.elementIds.indexOf(remaining[i]) > -1)
112 return remaining[i];
113 }
114 }
115
116 // Select the first item that is focusable if nothing else worked.
117 return row.elementIds[0];
118 },
119 };
120
121 ///////////////////////////////////////////////////////////////////////////////
80 // Downloads 122 // Downloads
81 /** 123 /**
82 * Class to hold all the information about the visible downloads. 124 * Class to hold all the information about the visible downloads.
83 * @constructor 125 * @constructor
84 */ 126 */
85 function Downloads() { 127 function Downloads() {
86 /** 128 /**
87 * @type {!Object.<string, Download>} 129 * @type {!Object.<string, Download>}
88 * @private 130 * @private
89 */ 131 */
90 this.downloads_ = {}; 132 this.downloads_ = {};
91 this.node_ = $('downloads-display'); 133 this.node_ = $('downloads-display');
92 this.summary_ = $('downloads-summary-text'); 134 this.summary_ = $('downloads-summary-text');
93 this.searchText_ = ''; 135 this.searchText_ = '';
136 this.focusGrid_ = new cr.ui.FocusGrid(this.node_,
137 new DownloadFocusObserver());
94 138
95 // Keep track of the dates of the newest and oldest downloads so that we 139 // Keep track of the dates of the newest and oldest downloads so that we
96 // know where to insert them. 140 // know where to insert them.
97 this.newestTime_ = -1; 141 this.newestTime_ = -1;
98 142
99 // Icon load request queue. 143 // Icon load request queue.
100 this.iconLoadQueue_ = []; 144 this.iconLoadQueue_ = [];
101 this.isIconLoading_ = false; 145 this.isIconLoading_ = false;
102 146
103 this.progressForeground1_ = new Image(); 147 this.progressForeground1_ = new Image();
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
169 var noDownloadsOrResults = $('no-downloads-or-results'); 213 var noDownloadsOrResults = $('no-downloads-or-results');
170 noDownloadsOrResults.textContent = loadTimeData.getString( 214 noDownloadsOrResults.textContent = loadTimeData.getString(
171 this.searchText_ ? 'no_search_results' : 'no_downloads'); 215 this.searchText_ ? 'no_search_results' : 'no_downloads');
172 216
173 var hasDownloads = this.size() > 0; 217 var hasDownloads = this.size() > 0;
174 this.node_.hidden = !hasDownloads; 218 this.node_.hidden = !hasDownloads;
175 noDownloadsOrResults.hidden = hasDownloads; 219 noDownloadsOrResults.hidden = hasDownloads;
176 220
177 if (loadTimeData.getBoolean('allow_deleting_history')) 221 if (loadTimeData.getBoolean('allow_deleting_history'))
178 $('clear-all').hidden = !hasDownloads || this.searchText_.length > 0; 222 $('clear-all').hidden = !hasDownloads || this.searchText_.length > 0;
223
224 this.rebuildFocusGrid_();
179 }; 225 };
180 226
181 /** 227 /**
228 * Determines if element should be focusable.
229 * @param {!Element} element
230 * @return {bool}
231 * @private
232 */
233 Downloads.shouldFocus_ = function(element) {
234 if (!element)
235 return false;
236
237 // Hidden elements are not focusable.
238 var style = window.getComputedStyle(element);
239 if (style.visibility == 'hidden' || style.display == 'none')
240 return false;
241
242 // Verify that all ancestors are focusable.
243 if (element.parentElement)
244 return Downloads.shouldFocus_(element.parentElement);
245
246 return true;
247 };
248
249 /**
250 * Will add an element to |focusRow| if it can be focused.
251 * @param {cr.ui.FocusRow} focusRow The row to add the element to.
252 * @param {Element} element The element to add.
253 * @param {string} elementId The elementId used for selecting in a grid.
254 * @private
255 */
256 Downloads.prototype.addRowElement_ = function(focusRow, element, elementId) {
257 if (Downloads.shouldFocus_(element))
258 focusRow.setFocusableElementId(element, elementId);
259 };
260
261 /**
262 * Rebuild the focusGrid_ using the elements that each download will have.
263 * @private
264 */
265 Downloads.prototype.rebuildFocusGrid_ = function() {
266 this.focusGrid_.destroy();
267
268 // Keys for downloads are in the reverse order of what is displayed.
269 var keys = Object.keys(this.downloads_);
270 for (var i = keys.length - 1; i >= 0; --i) {
271 var node = this.downloads_[keys[i]];
272 var focusRow = this.focusGrid_.createRow();
273
274 // Add all clickable elements as a row into the grid.
275 this.addRowElement_(focusRow, node.nodeFileLink_, 'name');
276 this.addRowElement_(focusRow, node.nodeURL_, 'url');
277 this.addRowElement_(focusRow, node.controlShow_, 'show');
278 this.addRowElement_(focusRow, node.controlRetry_, 'retry');
279 this.addRowElement_(focusRow, node.controlPause_, 'pause');
280 this.addRowElement_(focusRow, node.controlResume_, 'resume');
281 this.addRowElement_(focusRow, node.controlRemove_, 'remove');
282 this.addRowElement_(focusRow, node.controlCancel_, 'cancel');
283
284 // These buttons are mutually exclusive, but they are visually the same.
285 this.addRowElement_(focusRow, node.malwareSave_, 'save');
286 this.addRowElement_(focusRow, node.dangerSave_, 'save');
287 this.addRowElement_(focusRow, node.malwareDiscard_, 'discard');
288 this.addRowElement_(focusRow, node.dangerDiscard_, 'discard');
289
290 this.addRowElement_(focusRow, node.controlByExtensionLink_, 'extension');
291
292 this.focusGrid_.addRow(focusRow);
293 }
294 };
295
296 /**
182 * Returns the number of downloads in the model. Used by tests. 297 * Returns the number of downloads in the model. Used by tests.
183 * @return {number} Returns the number of downloads shown on the page. 298 * @return {number} Returns the number of downloads shown on the page.
184 */ 299 */
185 Downloads.prototype.size = function() { 300 Downloads.prototype.size = function() {
186 return Object.keys(this.downloads_).length; 301 return Object.keys(this.downloads_).length;
187 }; 302 };
188 303
189 /** 304 /**
190 * Called whenever the downloads lists items have changed (either by being 305 * Called whenever the downloads lists items have changed (either by being
191 * updated, added, or removed). 306 * updated, added, or removed).
(...skipping 786 matching lines...) Expand 10 before | Expand all | Expand 10 after
978 if (Date.now() - start > 50) { 1093 if (Date.now() - start > 50) {
979 clearTimeout(resultsTimeout); 1094 clearTimeout(resultsTimeout);
980 resultsTimeout = setTimeout(tryDownloadUpdatedPeriodically, 5); 1095 resultsTimeout = setTimeout(tryDownloadUpdatedPeriodically, 5);
981 break; 1096 break;
982 } 1097 }
983 } 1098 }
984 } 1099 }
985 1100
986 // Add handlers to HTML elements. 1101 // Add handlers to HTML elements.
987 window.addEventListener('DOMContentLoaded', load); 1102 window.addEventListener('DOMContentLoaded', load);
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698