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

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: nit 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 // DownloadFocusRow:
81
82 /**
83 * Provides an implementation for a single column grid.
84 * @constructor
85 * @param {Download} download The Download representing this row.
86 * @param {Node} boundary Focus events are ignored outside of this node.
87 * @extends {cr.ui.FocusRow}
88 */
89 DownloadFocusRow = function(download, boundary) {
90 var self = download.node;
91 self.__proto__ = DownloadFocusRow.prototype;
92 self.download_ = download;
93 self.decorate(boundary);
94 return self;
Dan Beam 2015/01/24 02:37:07 what's the point to this pattern of returning some
hcarmona 2015/01/27 18:30:39 I had seen this in the code when a constructor wou
95 };
96
97 DownloadFocusRow.prototype = {
98 __proto__: cr.ui.FocusRow.prototype,
99
100 /** @override */
101 decorate: function(boundary, opt_delegate) {
102 cr.ui.FocusRow.prototype.decorate.apply(this, arguments);
103
104 // Add all clickable elements as a row into the grid.
105 this.addFocusRow_(this.download_.nodeFileLink_, 'name');
Dan Beam 2015/01/24 02:37:08 i understand @private is file-level in closure, bu
hcarmona 2015/01/27 18:30:39 Done.
106 this.addFocusRow_(this.download_.nodeURL_, 'url');
107 this.addFocusRow_(this.download_.controlShow_, 'show');
108 this.addFocusRow_(this.download_.controlRetry_, 'retry');
109 this.addFocusRow_(this.download_.controlPause_, 'pause');
110 this.addFocusRow_(this.download_.controlResume_, 'resume');
111 this.addFocusRow_(this.download_.controlRemove_, 'remove');
112 this.addFocusRow_(this.download_.controlCancel_, 'cancel');
113
114 // Only one set of these two buttons will be added to a download row at a
115 // time. They have the same type so that focus is handled well in case
116 // there is a dangerous download right next to a malicious download.
117 this.addFocusRow_(this.download_.malwareSave_, 'save');
118 this.addFocusRow_(this.download_.malwareDiscard_, 'discard');
119 this.addFocusRow_(this.download_.dangerSave_, 'save');
120 this.addFocusRow_(this.download_.dangerDiscard_, 'discard');
121
122 this.addFocusRow_(this.download_.controlByExtensionLink_, 'extension');
123 },
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.
131 var query = '[column-type="' + element.getAttribute('column-type') + '"]';
132 var ret = this.querySelector(query);
133
134 // The following element types are at the same UI level.
135 if (!ret) {
136 switch (element.getAttribute('column-type')) {
Dan Beam 2015/01/24 02:37:08 what is this entire switch trying to accomplish?
hcarmona 2015/01/27 18:30:39 Got rid of switch to make it more clear what's hap
137 case ('show'):
Dan Beam 2015/01/24 02:37:07 no parens case 'show':
hcarmona 2015/01/27 18:30:39 Done.
138 case ('retry'):
139 case ('pause'):
140 case ('resume'):
141 case ('remove'):
142 case ('cancel'):
143 ret = this.querySelector('[column-type="show"]') ||
144 this.querySelector('[column-type="retry"]') ||
145 this.querySelector('[column-type="pause"]') ||
146 this.querySelector('[column-type="resume"]') ||
147 this.querySelector('[column-type="remove"]') ||
148 this.querySelector('[column-type="cancel"]');
Dan Beam 2015/01/24 02:37:07 querySelector('[column-type=show], [column-type=re
hcarmona 2015/01/27 18:30:39 Done.
149 break;
150 }
151 }
152
153 // Any other miss should return the first focusable element.
154 return ret || this.focusableElements[0];
155 },
156
157 /**
158 * Add an element if it exists in this FocusRow and is focusable.
159 * @param {Element} element The element that should be added.
160 * @param {string} type The type to use for the element.
161 * @private
162 */
163 addFocusRow_: function(element, type) {
164 if (this.shouldFocus_(element)) {
165 this.addFocusableElement(element);
166 element.setAttribute('column-type', type);
167 }
168 },
169
170 /**
171 * Determines if element should be focusable.
172 * @param {!Element} element
173 * @return {boolean}
174 * @private
175 */
176 shouldFocus_: function(element) {
177 if (!element)
178 return false;
179
180 // Hidden elements are not focusable.
181 var style = window.getComputedStyle(element);
182 if (style.visibility == 'hidden' || style.display == 'none')
183 return false;
184
185 // Verify that all ancestors are focusable. This is necessary because of the
186 // case where a node has display set to something other than 'none', but it
187 // has an ancestor with display == 'none'.
188 if (element.parentElement)
189 return this.shouldFocus_(element.parentElement);
190
191 return true;
192 },
193 };
194
195 ///////////////////////////////////////////////////////////////////////////////
80 // Downloads 196 // Downloads
81 /** 197 /**
82 * Class to hold all the information about the visible downloads. 198 * Class to hold all the information about the visible downloads.
83 * @constructor 199 * @constructor
84 */ 200 */
85 function Downloads() { 201 function Downloads() {
86 /** 202 /**
87 * @type {!Object.<string, Download>} 203 * @type {!Object.<string, Download>}
88 * @private 204 * @private
89 */ 205 */
90 this.downloads_ = {}; 206 this.downloads_ = {};
91 this.node_ = $('downloads-display'); 207 this.node_ = $('downloads-display');
92 this.summary_ = $('downloads-summary-text'); 208 this.summary_ = $('downloads-summary-text');
93 this.searchText_ = ''; 209 this.searchText_ = '';
210 this.focusGrid_ = new cr.ui.FocusGrid();
94 211
95 // Keep track of the dates of the newest and oldest downloads so that we 212 // Keep track of the dates of the newest and oldest downloads so that we
96 // know where to insert them. 213 // know where to insert them.
97 this.newestTime_ = -1; 214 this.newestTime_ = -1;
98 215
99 // Icon load request queue. 216 // Icon load request queue.
100 this.iconLoadQueue_ = []; 217 this.iconLoadQueue_ = [];
101 this.isIconLoading_ = false; 218 this.isIconLoading_ = false;
102 219
103 this.progressForeground1_ = new Image(); 220 this.progressForeground1_ = new Image();
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
169 var noDownloadsOrResults = $('no-downloads-or-results'); 286 var noDownloadsOrResults = $('no-downloads-or-results');
170 noDownloadsOrResults.textContent = loadTimeData.getString( 287 noDownloadsOrResults.textContent = loadTimeData.getString(
171 this.searchText_ ? 'no_search_results' : 'no_downloads'); 288 this.searchText_ ? 'no_search_results' : 'no_downloads');
172 289
173 var hasDownloads = this.size() > 0; 290 var hasDownloads = this.size() > 0;
174 this.node_.hidden = !hasDownloads; 291 this.node_.hidden = !hasDownloads;
175 noDownloadsOrResults.hidden = hasDownloads; 292 noDownloadsOrResults.hidden = hasDownloads;
176 293
177 if (loadTimeData.getBoolean('allow_deleting_history')) 294 if (loadTimeData.getBoolean('allow_deleting_history'))
178 $('clear-all').hidden = !hasDownloads || this.searchText_.length > 0; 295 $('clear-all').hidden = !hasDownloads || this.searchText_.length > 0;
296
297 this.rebuildFocusGrid_();
179 }; 298 };
180 299
181 /** 300 /**
301 * Rebuild the focusGrid_ using the elements that each download will have.
302 * @private
303 */
304 Downloads.prototype.rebuildFocusGrid_ = function() {
305 this.focusGrid_.destroy();
306
307 // Keys for downloads are in the reverse order of what is displayed.
308 var keys = Object.keys(this.downloads_);
309 for (var i = keys.length - 1; i >= 0; --i) {
310 this.focusGrid_.addRow(new DownloadFocusRow(this.downloads_[keys[i]],
311 this.node_));
312 }
313 };
314
315 /**
182 * Returns the number of downloads in the model. Used by tests. 316 * Returns the number of downloads in the model. Used by tests.
183 * @return {number} Returns the number of downloads shown on the page. 317 * @return {number} Returns the number of downloads shown on the page.
184 */ 318 */
185 Downloads.prototype.size = function() { 319 Downloads.prototype.size = function() {
186 return Object.keys(this.downloads_).length; 320 return Object.keys(this.downloads_).length;
187 }; 321 };
188 322
189 /** 323 /**
190 * Called whenever the downloads lists items have changed (either by being 324 * Called whenever the downloads lists items have changed (either by being
191 * updated, added, or removed). 325 * updated, added, or removed).
(...skipping 786 matching lines...) Expand 10 before | Expand all | Expand 10 after
978 if (Date.now() - start > 50) { 1112 if (Date.now() - start > 50) {
979 clearTimeout(resultsTimeout); 1113 clearTimeout(resultsTimeout);
980 resultsTimeout = setTimeout(tryDownloadUpdatedPeriodically, 5); 1114 resultsTimeout = setTimeout(tryDownloadUpdatedPeriodically, 5);
981 break; 1115 break;
982 } 1116 }
983 } 1117 }
984 } 1118 }
985 1119
986 // Add handlers to HTML elements. 1120 // Add handlers to HTML elements.
987 window.addEventListener('DOMContentLoaded', load); 1121 window.addEventListener('DOMContentLoaded', load);
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698