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

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: Apply feedback Created 5 years, 10 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 // TODO(hcarmona): This file is big: it may be good to split it up.
6 7
7 /** 8 /**
8 * The type of the download object. The definition is based on 9 * The type of the download object. The definition is based on
9 * chrome/browser/ui/webui/downloads_dom_handler.cc:CreateDownloadItemValue() 10 * chrome/browser/ui/webui/downloads_dom_handler.cc:CreateDownloadItemValue()
10 * @typedef {{by_ext_id: (string|undefined), 11 * @typedef {{by_ext_id: (string|undefined),
11 * by_ext_name: (string|undefined), 12 * by_ext_name: (string|undefined),
12 * danger_type: (string|undefined), 13 * danger_type: (string|undefined),
13 * date_string: string, 14 * date_string: string,
14 * file_externally_removed: boolean, 15 * file_externally_removed: boolean,
15 * file_name: string, 16 * file_name: string,
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
70 */ 71 */
71 function createButton(onclick, value) { 72 function createButton(onclick, value) {
72 var button = document.createElement('input'); 73 var button = document.createElement('input');
73 button.type = 'button'; 74 button.type = 'button';
74 button.value = value; 75 button.value = value;
75 button.onclick = onclick; 76 button.onclick = onclick;
76 return button; 77 return button;
77 } 78 }
78 79
79 /////////////////////////////////////////////////////////////////////////////// 80 ///////////////////////////////////////////////////////////////////////////////
81 // DownloadFocusRow:
82
83 /**
84 * Provides an implementation for a single column grid.
85 * @constructor
86 * @extends {cr.ui.FocusRow}
87 */
88 DownloadFocusRow = function() {};
Dan Beam 2015/01/27 22:32:23 function DownloadFocusRow() {} is the more typica
hcarmona 2015/01/29 00:00:37 Done.
89
90 /**
91 * Decorates |focusRow| so that it can be treated as a DownloadFocusRow.
92 * @param {Element} focusRow The element that has all the columns represented
93 * by |download|.
94 * @param {Download} download The Download representing this row.
95 * @param {Node} boundary Focus events are ignored outside of this node.
96 */
97 DownloadFocusRow.decorate = function(focusRow, download, boundary) {
98 focusRow.__proto__ = DownloadFocusRow.prototype;
99 focusRow.decorate(boundary);
100
101 // Add all clickable elements as a row into the grid.
102 focusRow.addFocusRow_(download.nodeFileLink_, 'name');
103 focusRow.addFocusRow_(download.nodeURL_, 'url');
104 focusRow.addFocusRow_(download.controlShow_, 'show');
105 focusRow.addFocusRow_(download.controlRetry_, 'retry');
106 focusRow.addFocusRow_(download.controlPause_, 'pause');
107 focusRow.addFocusRow_(download.controlResume_, 'resume');
108 focusRow.addFocusRow_(download.controlRemove_, 'remove');
109 focusRow.addFocusRow_(download.controlCancel_, 'cancel');
110
111 // Only one set of these two buttons will be added to a download row at a
112 // time. They have the same type so that focus is handled well in case
113 // there is a dangerous download right next to a malicious download.
114 focusRow.addFocusRow_(download.malwareSave_, 'save');
115 focusRow.addFocusRow_(download.malwareDiscard_, 'discard');
116 focusRow.addFocusRow_(download.dangerSave_, 'save');
117 focusRow.addFocusRow_(download.dangerDiscard_, 'discard');
118
119 focusRow.addFocusRow_(download.controlByExtensionLink_, 'extension');
120 };
121
122 DownloadFocusRow.prototype = {
123 __proto__: cr.ui.FocusRow.prototype,
124
125 /** @override */
126 getEquivalentElement: function(element) {
127 if (this.contains(element))
128 return element;
129
130 // All elements default to another element with the same type.
Dan Beam 2015/01/27 22:32:23 nit: arguably var columnType = element.getAttribu
hcarmona 2015/01/29 00:00:37 Done.
131 var query = '[column-type=' + element.getAttribute('column-type') + ']';
132 var ret = this.querySelector(query);
Dan Beam 2015/01/27 22:32:23 nit: ret -> el, element, equiv, equivalent (all se
hcarmona 2015/01/29 00:00:37 Done.
133
134 if (!ret) {
135 // The following element types are at the same UI level.
136 var grayLinks = ['show', 'retry', 'pause', 'resume', 'remove', 'cancel'];
Dan Beam 2015/01/27 22:32:23 nit: grayLinks -> equivalents (or rename so this i
hcarmona 2015/01/29 00:00:37 Done.
137 if (grayLinks.indexOf(element.getAttribute('column-type')) != -1) {
138 ret = this.querySelector(
139 '[column-type=show], [column-type=retry], ' +
140 '[column-type=pause], [column-type=resume], ' +
141 '[column-type=remove], [column-type=cancel]');
Dan Beam 2015/01/27 22:32:23 why are we duplicating this list of types?
hcarmona 2015/01/29 00:00:37 Done. Not duplicated anymore.
142 }
143 }
144
145 // Any other miss should return the first focusable element.
Dan Beam 2015/01/27 22:32:23 nit: // Return the first focusable element if no e
hcarmona 2015/01/29 00:00:37 Done.
146 return ret || this.focusableElements[0];
147 },
148
149 /**
150 * Add an element if it exists in this FocusRow and is focusable.
151 * @param {Element} element The element that should be added.
152 * @param {string} type The type to use for the element.
Dan Beam 2015/01/27 22:32:23 can we make these doc strings more useful or remov
hcarmona 2015/01/29 00:00:37 Done.
153 * @private
154 */
155 addFocusRow_: function(element, type) {
156 if (this.shouldFocus_(element)) {
157 this.addFocusableElement(element);
158 element.setAttribute('column-type', type);
159 }
160 },
161
162 /**
163 * Determines if element should be focusable.
164 * @param {!Element} element
165 * @return {boolean}
166 * @private
167 */
168 shouldFocus_: function(element) {
169 if (!element)
170 return false;
171
172 // Hidden elements are not focusable.
173 var style = window.getComputedStyle(element);
174 if (style.visibility == 'hidden' || style.display == 'none')
Dan Beam 2015/01/27 22:32:23 here's the full amount of checks that blink does,
hcarmona 2015/01/29 00:00:37 This check is sufficient for the downloads page. D
175 return false;
176
177 // Verify that all ancestors are focusable. This is necessary because of the
178 // case where a node has display set to something other than 'none', but it
179 // has an ancestor with display == 'none'.
180 if (element.parentElement)
181 return this.shouldFocus_(element.parentElement);
182
183 return true;
Dan Beam 2015/01/27 22:32:23 nit: // Verify all ancestors are focusable. r
hcarmona 2015/01/29 00:00:37 Done.
184 },
185 };
186
187 ///////////////////////////////////////////////////////////////////////////////
80 // Downloads 188 // Downloads
81 /** 189 /**
82 * Class to hold all the information about the visible downloads. 190 * Class to hold all the information about the visible downloads.
83 * @constructor 191 * @constructor
84 */ 192 */
85 function Downloads() { 193 function Downloads() {
86 /** 194 /**
87 * @type {!Object.<string, Download>} 195 * @type {!Object.<string, Download>}
88 * @private 196 * @private
89 */ 197 */
90 this.downloads_ = {}; 198 this.downloads_ = {};
91 this.node_ = $('downloads-display'); 199 this.node_ = $('downloads-display');
92 this.summary_ = $('downloads-summary-text'); 200 this.summary_ = $('downloads-summary-text');
93 this.searchText_ = ''; 201 this.searchText_ = '';
202 this.focusGrid_ = new cr.ui.FocusGrid();
94 203
95 // Keep track of the dates of the newest and oldest downloads so that we 204 // Keep track of the dates of the newest and oldest downloads so that we
96 // know where to insert them. 205 // know where to insert them.
97 this.newestTime_ = -1; 206 this.newestTime_ = -1;
98 207
99 // Icon load request queue. 208 // Icon load request queue.
100 this.iconLoadQueue_ = []; 209 this.iconLoadQueue_ = [];
101 this.isIconLoading_ = false; 210 this.isIconLoading_ = false;
102 211
103 this.progressForeground1_ = new Image(); 212 this.progressForeground1_ = new Image();
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
169 var noDownloadsOrResults = $('no-downloads-or-results'); 278 var noDownloadsOrResults = $('no-downloads-or-results');
170 noDownloadsOrResults.textContent = loadTimeData.getString( 279 noDownloadsOrResults.textContent = loadTimeData.getString(
171 this.searchText_ ? 'no_search_results' : 'no_downloads'); 280 this.searchText_ ? 'no_search_results' : 'no_downloads');
172 281
173 var hasDownloads = this.size() > 0; 282 var hasDownloads = this.size() > 0;
174 this.node_.hidden = !hasDownloads; 283 this.node_.hidden = !hasDownloads;
175 noDownloadsOrResults.hidden = hasDownloads; 284 noDownloadsOrResults.hidden = hasDownloads;
176 285
177 if (loadTimeData.getBoolean('allow_deleting_history')) 286 if (loadTimeData.getBoolean('allow_deleting_history'))
178 $('clear-all').hidden = !hasDownloads || this.searchText_.length > 0; 287 $('clear-all').hidden = !hasDownloads || this.searchText_.length > 0;
288
289 this.rebuildFocusGrid_();
179 }; 290 };
180 291
181 /** 292 /**
293 * Rebuild the focusGrid_ using the elements that each download will have.
294 * @private
295 */
296 Downloads.prototype.rebuildFocusGrid_ = function() {
297 this.focusGrid_.destroy();
298
299 // Keys for downloads are in the reverse order of what is displayed.
300 var keys = Object.keys(this.downloads_);
Dan Beam 2015/01/27 22:32:23 I'm not sure that the order of keys returned from
hcarmona 2015/01/29 00:00:37 The order does matter. Updated code so that it is
301 for (var i = keys.length - 1; i >= 0; --i) {
302 var download = this.downloads_[keys[i]];
303 DownloadFocusRow.decorate(download.node, download, this.node_);
Dan Beam 2015/01/27 22:32:23 are all the rows always blasted away and rebuilt?
hcarmona 2015/01/29 00:00:37 Changed so that rows are only decorated once.
304 this.focusGrid_.addRow(download.node);
305 }
306 };
307
308 /**
182 * Returns the number of downloads in the model. Used by tests. 309 * Returns the number of downloads in the model. Used by tests.
183 * @return {number} Returns the number of downloads shown on the page. 310 * @return {number} Returns the number of downloads shown on the page.
184 */ 311 */
185 Downloads.prototype.size = function() { 312 Downloads.prototype.size = function() {
186 return Object.keys(this.downloads_).length; 313 return Object.keys(this.downloads_).length;
187 }; 314 };
188 315
189 /** 316 /**
190 * Called whenever the downloads lists items have changed (either by being 317 * Called whenever the downloads lists items have changed (either by being
191 * updated, added, or removed). 318 * updated, added, or removed).
(...skipping 786 matching lines...) Expand 10 before | Expand all | Expand 10 after
978 if (Date.now() - start > 50) { 1105 if (Date.now() - start > 50) {
979 clearTimeout(resultsTimeout); 1106 clearTimeout(resultsTimeout);
980 resultsTimeout = setTimeout(tryDownloadUpdatedPeriodically, 5); 1107 resultsTimeout = setTimeout(tryDownloadUpdatedPeriodically, 5);
981 break; 1108 break;
982 } 1109 }
983 } 1110 }
984 } 1111 }
985 1112
986 // Add handlers to HTML elements. 1113 // Add handlers to HTML elements.
987 window.addEventListener('DOMContentLoaded', load); 1114 window.addEventListener('DOMContentLoaded', load);
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698