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

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 Initial Feedback Created 6 years 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 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
84 */ 84 */
85 function Downloads() { 85 function Downloads() {
86 /** 86 /**
87 * @type {!Object.<string, Download>} 87 * @type {!Object.<string, Download>}
88 * @private 88 * @private
89 */ 89 */
90 this.downloads_ = {}; 90 this.downloads_ = {};
91 this.node_ = $('downloads-display'); 91 this.node_ = $('downloads-display');
92 this.summary_ = $('downloads-summary-text'); 92 this.summary_ = $('downloads-summary-text');
93 this.searchText_ = ''; 93 this.searchText_ = '';
94 this.focusGrid_ = new cr.ui.FocusGrid(this.node_,
95 new DownloadFocusObserver());
94 96
95 // Keep track of the dates of the newest and oldest downloads so that we 97 // Keep track of the dates of the newest and oldest downloads so that we
96 // know where to insert them. 98 // know where to insert them.
97 this.newestTime_ = -1; 99 this.newestTime_ = -1;
98 100
99 // Icon load request queue. 101 // Icon load request queue.
100 this.iconLoadQueue_ = []; 102 this.iconLoadQueue_ = [];
101 this.isIconLoading_ = false; 103 this.isIconLoading_ = false;
102 104
103 this.progressForeground1_ = new Image(); 105 this.progressForeground1_ = new Image();
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
169 var noDownloadsOrResults = $('no-downloads-or-results'); 171 var noDownloadsOrResults = $('no-downloads-or-results');
170 noDownloadsOrResults.textContent = loadTimeData.getString( 172 noDownloadsOrResults.textContent = loadTimeData.getString(
171 this.searchText_ ? 'no_search_results' : 'no_downloads'); 173 this.searchText_ ? 'no_search_results' : 'no_downloads');
172 174
173 var hasDownloads = this.size() > 0; 175 var hasDownloads = this.size() > 0;
174 this.node_.hidden = !hasDownloads; 176 this.node_.hidden = !hasDownloads;
175 noDownloadsOrResults.hidden = hasDownloads; 177 noDownloadsOrResults.hidden = hasDownloads;
176 178
177 if (loadTimeData.getBoolean('allow_deleting_history')) 179 if (loadTimeData.getBoolean('allow_deleting_history'))
178 $('clear-all').hidden = !hasDownloads || this.searchText_.length > 0; 180 $('clear-all').hidden = !hasDownloads || this.searchText_.length > 0;
181
182 var grid = [];
183 for (var node = this.node_.firstChild; node; node = node.nextSibling) {
184 // Add all clickable elements as a row into the grid.
185 grid.push(node.getElementsByClassName('row-item'));
Dan Beam 2014/12/22 23:19:59 use querySelectorAll('.row-item') unless you want
hcarmona 2015/01/13 00:04:40 Elements are now added explicitly, so there's no n
186 }
187 this.focusGrid_.setGrid(grid);
179 }; 188 };
180 189
181 /** 190 /**
191 * Decorate elem so that it can be added to the focusGrid_.
192 * @param {!Element} elem The element that should be decorated.
193 */
194 Downloads.makeFocusable = function(elem) {
dmazzoni 2014/12/22 23:14:07 Maybe makePartOfFocusGrid or addFocusGridItemClass
Dan Beam 2014/12/22 23:19:59 what happens if this class is added after the focu
hcarmona 2015/01/13 00:04:40 Created the rebuildFocusGrid_ method to make it mo
hcarmona 2015/01/13 00:04:40 Done.
195 elem.classList.add('row-item');
196 };
197
198 /**
182 * Returns the number of downloads in the model. Used by tests. 199 * Returns the number of downloads in the model. Used by tests.
183 * @return {number} Returns the number of downloads shown on the page. 200 * @return {number} Returns the number of downloads shown on the page.
184 */ 201 */
185 Downloads.prototype.size = function() { 202 Downloads.prototype.size = function() {
186 return Object.keys(this.downloads_).length; 203 return Object.keys(this.downloads_).length;
187 }; 204 };
188 205
189 /** 206 /**
190 * Called whenever the downloads lists items have changed (either by being 207 * Called whenever the downloads lists items have changed (either by being
191 * updated, added, or removed). 208 * updated, added, or removed).
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
297 * @private 314 * @private
298 */ 315 */
299 Downloads.prototype.onCommand_ = function(e) { 316 Downloads.prototype.onCommand_ = function(e) {
300 if (e.command.id == 'undo-command') 317 if (e.command.id == 'undo-command')
301 chrome.send('undo'); 318 chrome.send('undo');
302 else if (e.command.id == 'clear-all-command') 319 else if (e.command.id == 'clear-all-command')
303 clearAll(); 320 clearAll();
304 }; 321 };
305 322
306 /////////////////////////////////////////////////////////////////////////////// 323 ///////////////////////////////////////////////////////////////////////////////
324 // DownloadFocusObserver
325
326 /**
327 * @constructor
328 * @implements {cr.ui.FocusRow.Observer}
329 */
330 function DownloadFocusObserver() {}
Dan Beam 2014/12/22 23:19:59 you could probably make the HistoryFocusObserver i
hcarmona 2015/01/13 00:04:40 Observer will now handle the case when a column mi
331
332 DownloadFocusObserver.prototype = {
333 /** @override */
334 onActivate: function(row) {
335 this.getActiveRowElement_(row).classList.add('active');
336 },
337
338 /** @override */
339 onDeactivate: function(row) {
340 this.getActiveRowElement_(row).classList.remove('active');
341 },
342
343 /**
344 * @param {cr.ui.FocusRow} row The row to find an element for.
345 * @return {Element} |row|'s "active" element.
346 * @private
347 */
348 getActiveRowElement_: function(row) {
349 return findAncestorByClass(row.items[0], 'download');
350 },
351 };
352
353 ///////////////////////////////////////////////////////////////////////////////
307 // Download 354 // Download
308 /** 355 /**
309 * A download and the DOM representation for that download. 356 * A download and the DOM representation for that download.
310 * @param {DownloadItem} download Info about the download. 357 * @param {DownloadItem} download Info about the download.
311 * @constructor 358 * @constructor
312 */ 359 */
313 function Download(download) { 360 function Download(download) {
314 // Create DOM 361 // Create DOM
315 this.node = createElementWithClassName( 362 this.node = createElementWithClassName(
316 'div', 'download' + (download.otr ? ' otr' : '')); 363 'div', 'download' + (download.otr ? ' otr' : ''));
(...skipping 30 matching lines...) Expand all
347 this.nodeImg_.alt = ''; 394 this.nodeImg_.alt = '';
348 this.safe_.appendChild(this.nodeImg_); 395 this.safe_.appendChild(this.nodeImg_);
349 396
350 // FileLink is used for completed downloads, otherwise we show FileName. 397 // FileLink is used for completed downloads, otherwise we show FileName.
351 this.nodeTitleArea_ = createElementWithClassName('div', 'title-area'); 398 this.nodeTitleArea_ = createElementWithClassName('div', 'title-area');
352 this.safe_.appendChild(this.nodeTitleArea_); 399 this.safe_.appendChild(this.nodeTitleArea_);
353 400
354 this.nodeFileLink_ = createActionLink(this.openFile_.bind(this)); 401 this.nodeFileLink_ = createActionLink(this.openFile_.bind(this));
355 this.nodeFileLink_.className = 'name'; 402 this.nodeFileLink_.className = 'name';
356 this.nodeFileLink_.style.display = 'none'; 403 this.nodeFileLink_.style.display = 'none';
404 Downloads.makeFocusable(this.nodeFileLink_);
357 this.nodeTitleArea_.appendChild(this.nodeFileLink_); 405 this.nodeTitleArea_.appendChild(this.nodeFileLink_);
358 406
359 this.nodeFileName_ = createElementWithClassName('span', 'name'); 407 this.nodeFileName_ = createElementWithClassName('span', 'name');
360 this.nodeFileName_.style.display = 'none'; 408 this.nodeFileName_.style.display = 'none';
361 this.nodeTitleArea_.appendChild(this.nodeFileName_); 409 this.nodeTitleArea_.appendChild(this.nodeFileName_);
362 410
363 this.nodeStatus_ = createElementWithClassName('span', 'status'); 411 this.nodeStatus_ = createElementWithClassName('span', 'status');
364 this.nodeTitleArea_.appendChild(this.nodeStatus_); 412 this.nodeTitleArea_.appendChild(this.nodeStatus_);
365 413
366 var nodeURLDiv = createElementWithClassName('div', 'url-container'); 414 var nodeURLDiv = createElementWithClassName('div', 'url-container');
367 this.safe_.appendChild(nodeURLDiv); 415 this.safe_.appendChild(nodeURLDiv);
368 416
369 this.nodeURL_ = createElementWithClassName('a', 'src-url'); 417 this.nodeURL_ = createElementWithClassName('a', 'src-url');
370 this.nodeURL_.target = '_blank'; 418 this.nodeURL_.target = '_blank';
419 Downloads.makeFocusable(this.nodeURL_);
371 nodeURLDiv.appendChild(this.nodeURL_); 420 nodeURLDiv.appendChild(this.nodeURL_);
372 421
373 // Controls. 422 // Controls.
374 this.nodeControls_ = createElementWithClassName('div', 'controls'); 423 this.nodeControls_ = createElementWithClassName('div', 'controls');
375 this.safe_.appendChild(this.nodeControls_); 424 this.safe_.appendChild(this.nodeControls_);
376 425
377 // We don't need 'show in folder' in chromium os. See download_ui.cc and 426 // We don't need 'show in folder' in chromium os. See download_ui.cc and
378 // http://code.google.com/p/chromium-os/issues/detail?id=916. 427 // http://code.google.com/p/chromium-os/issues/detail?id=916.
379 if (loadTimeData.valueExists('control_showinfolder')) { 428 if (loadTimeData.valueExists('control_showinfolder')) {
380 this.controlShow_ = createActionLink(this.show_.bind(this), 429 this.controlShow_ = createActionLink(this.show_.bind(this),
381 loadTimeData.getString('control_showinfolder')); 430 loadTimeData.getString('control_showinfolder'));
431 Downloads.makeFocusable(this.controlShow_);
382 this.nodeControls_.appendChild(this.controlShow_); 432 this.nodeControls_.appendChild(this.controlShow_);
383 } else { 433 } else {
384 this.controlShow_ = null; 434 this.controlShow_ = null;
385 } 435 }
386 436
387 this.controlRetry_ = document.createElement('a'); 437 this.controlRetry_ = document.createElement('a');
388 this.controlRetry_.download = ''; 438 this.controlRetry_.download = '';
389 this.controlRetry_.textContent = loadTimeData.getString('control_retry'); 439 this.controlRetry_.textContent = loadTimeData.getString('control_retry');
440 Downloads.makeFocusable(this.controlRetry_);
390 this.nodeControls_.appendChild(this.controlRetry_); 441 this.nodeControls_.appendChild(this.controlRetry_);
391 442
392 // Pause/Resume are a toggle. 443 // Pause/Resume are a toggle.
393 this.controlPause_ = createActionLink(this.pause_.bind(this), 444 this.controlPause_ = createActionLink(this.pause_.bind(this),
394 loadTimeData.getString('control_pause')); 445 loadTimeData.getString('control_pause'));
446 Downloads.makeFocusable(this.controlPause_);
395 this.nodeControls_.appendChild(this.controlPause_); 447 this.nodeControls_.appendChild(this.controlPause_);
396 448
397 this.controlResume_ = createActionLink(this.resume_.bind(this), 449 this.controlResume_ = createActionLink(this.resume_.bind(this),
398 loadTimeData.getString('control_resume')); 450 loadTimeData.getString('control_resume'));
451 Downloads.makeFocusable(this.controlResume_);
399 this.nodeControls_.appendChild(this.controlResume_); 452 this.nodeControls_.appendChild(this.controlResume_);
400 453
401 if (loadTimeData.getBoolean('allow_deleting_history')) { 454 if (loadTimeData.getBoolean('allow_deleting_history')) {
402 this.controlRemove_ = createActionLink(this.remove_.bind(this), 455 this.controlRemove_ = createActionLink(this.remove_.bind(this),
403 loadTimeData.getString('control_removefromlist')); 456 loadTimeData.getString('control_removefromlist'));
404 this.controlRemove_.classList.add('control-remove-link'); 457 this.controlRemove_.classList.add('control-remove-link');
458 Downloads.makeFocusable(this.controlRemove_);
405 this.nodeControls_.appendChild(this.controlRemove_); 459 this.nodeControls_.appendChild(this.controlRemove_);
406 } 460 }
407 461
408 this.controlCancel_ = createActionLink(this.cancel_.bind(this), 462 this.controlCancel_ = createActionLink(this.cancel_.bind(this),
409 loadTimeData.getString('control_cancel')); 463 loadTimeData.getString('control_cancel'));
464 Downloads.makeFocusable(this.controlCancel_);
410 this.nodeControls_.appendChild(this.controlCancel_); 465 this.nodeControls_.appendChild(this.controlCancel_);
411 466
412 this.controlByExtension_ = document.createElement('span'); 467 this.controlByExtension_ = document.createElement('span');
413 this.nodeControls_.appendChild(this.controlByExtension_); 468 this.nodeControls_.appendChild(this.controlByExtension_);
414 469
415 // Container for 'unsafe download' UI. 470 // Container for 'unsafe download' UI.
416 this.danger_ = createElementWithClassName('div', 'show-dangerous'); 471 this.danger_ = createElementWithClassName('div', 'show-dangerous');
417 this.node.appendChild(this.danger_); 472 this.node.appendChild(this.danger_);
418 473
419 this.dangerNodeImg_ = createElementWithClassName('img', 'icon'); 474 this.dangerNodeImg_ = createElementWithClassName('img', 'icon');
420 this.dangerNodeImg_.alt = ''; 475 this.dangerNodeImg_.alt = '';
421 this.danger_.appendChild(this.dangerNodeImg_); 476 this.danger_.appendChild(this.dangerNodeImg_);
422 477
423 this.dangerDesc_ = document.createElement('div'); 478 this.dangerDesc_ = document.createElement('div');
424 this.danger_.appendChild(this.dangerDesc_); 479 this.danger_.appendChild(this.dangerDesc_);
425 480
426 // Buttons for the malicious case. 481 // Buttons for the malicious case.
427 this.malwareNodeControls_ = createElementWithClassName('div', 'controls'); 482 this.malwareNodeControls_ = createElementWithClassName('div', 'controls');
428 this.malwareSave_ = createActionLink( 483 this.malwareSave_ = createActionLink(
429 this.saveDangerous_.bind(this), 484 this.saveDangerous_.bind(this),
430 loadTimeData.getString('danger_restore')); 485 loadTimeData.getString('danger_restore'));
486 Downloads.makeFocusable(this.malwareSave_);
431 this.malwareNodeControls_.appendChild(this.malwareSave_); 487 this.malwareNodeControls_.appendChild(this.malwareSave_);
432 this.malwareDiscard_ = createActionLink( 488 this.malwareDiscard_ = createActionLink(
433 this.discardDangerous_.bind(this), 489 this.discardDangerous_.bind(this),
434 loadTimeData.getString('control_removefromlist')); 490 loadTimeData.getString('control_removefromlist'));
491 Downloads.makeFocusable(this.malwareDiscard_);
435 this.malwareNodeControls_.appendChild(this.malwareDiscard_); 492 this.malwareNodeControls_.appendChild(this.malwareDiscard_);
436 this.danger_.appendChild(this.malwareNodeControls_); 493 this.danger_.appendChild(this.malwareNodeControls_);
437 494
438 // Buttons for the dangerous but not malicious case. 495 // Buttons for the dangerous but not malicious case.
439 this.dangerSave_ = createButton( 496 this.dangerSave_ = createButton(
440 this.saveDangerous_.bind(this), 497 this.saveDangerous_.bind(this),
441 loadTimeData.getString('danger_save')); 498 loadTimeData.getString('danger_save'));
442 this.danger_.appendChild(this.dangerSave_); 499 this.danger_.appendChild(this.dangerSave_);
443 500
444 this.dangerDiscard_ = createButton( 501 this.dangerDiscard_ = createButton(
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after
639 // Format 'control_by_extension' with a link instead of plain text by 696 // Format 'control_by_extension' with a link instead of plain text by
640 // splitting the formatted string into pieces. 697 // splitting the formatted string into pieces.
641 var slug = 'XXXXX'; 698 var slug = 'XXXXX';
642 var formatted = loadTimeData.getStringF('control_by_extension', slug); 699 var formatted = loadTimeData.getStringF('control_by_extension', slug);
643 var slugIndex = formatted.indexOf(slug); 700 var slugIndex = formatted.indexOf(slug);
644 this.controlByExtension_.textContent = formatted.substr(0, slugIndex); 701 this.controlByExtension_.textContent = formatted.substr(0, slugIndex);
645 this.controlByExtensionLink_ = document.createElement('a'); 702 this.controlByExtensionLink_ = document.createElement('a');
646 this.controlByExtensionLink_.href = 703 this.controlByExtensionLink_.href =
647 'chrome://extensions#' + this.byExtensionId_; 704 'chrome://extensions#' + this.byExtensionId_;
648 this.controlByExtensionLink_.textContent = this.byExtensionName_; 705 this.controlByExtensionLink_.textContent = this.byExtensionName_;
706 Downloads.makeFocusable(this.controlByExtensionLink_);
649 this.controlByExtension_.appendChild(this.controlByExtensionLink_); 707 this.controlByExtension_.appendChild(this.controlByExtensionLink_);
650 if (slugIndex < (formatted.length - slug.length)) 708 if (slugIndex < (formatted.length - slug.length))
651 this.controlByExtension_.appendChild(document.createTextNode( 709 this.controlByExtension_.appendChild(document.createTextNode(
652 formatted.substr(slugIndex + 1))); 710 formatted.substr(slugIndex + 1)));
653 } 711 }
654 712
655 this.nodeSince_.textContent = this.since_; 713 this.nodeSince_.textContent = this.since_;
656 this.nodeDate_.textContent = this.date_; 714 this.nodeDate_.textContent = this.date_;
657 // Don't unnecessarily update the url, as doing so will remove any 715 // Don't unnecessarily update the url, as doing so will remove any
658 // text selection the user has started (http://crbug.com/44982). 716 // text selection the user has started (http://crbug.com/44982).
(...skipping 319 matching lines...) Expand 10 before | Expand all | Expand 10 after
978 if (Date.now() - start > 50) { 1036 if (Date.now() - start > 50) {
979 clearTimeout(resultsTimeout); 1037 clearTimeout(resultsTimeout);
980 resultsTimeout = setTimeout(tryDownloadUpdatedPeriodically, 5); 1038 resultsTimeout = setTimeout(tryDownloadUpdatedPeriodically, 5);
981 break; 1039 break;
982 } 1040 }
983 } 1041 }
984 } 1042 }
985 1043
986 // Add handlers to HTML elements. 1044 // Add handlers to HTML elements.
987 window.addEventListener('DOMContentLoaded', load); 1045 window.addEventListener('DOMContentLoaded', load);
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698