Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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); |
| OLD | NEW |