| Index: chrome/browser/resources/downloads/downloads.js
|
| diff --git a/chrome/browser/resources/downloads/downloads.js b/chrome/browser/resources/downloads/downloads.js
|
| index fd7ccc9e6dee71dd48d02317fc2fb38d95c60fa6..381da60542b130eec5592551f5bf8db094703f13 100644
|
| --- a/chrome/browser/resources/downloads/downloads.js
|
| +++ b/chrome/browser/resources/downloads/downloads.js
|
| @@ -77,6 +77,112 @@ function createButton(onclick, value) {
|
| }
|
|
|
| ///////////////////////////////////////////////////////////////////////////////
|
| +// DownloadFocusRow:
|
| +
|
| +/**
|
| + * Provides an implementation for a single column grid.
|
| + * @param {Node} boundary Focus events are ignored outside of this node.
|
| + * @param {Download} node The Download representing this row.
|
| + * @extends {cr.ui.FocusRow}
|
| + */
|
| +DownloadFocusRow = function(boundary, node) {
|
| + cr.ui.FocusRow.call(this, boundary, node.node);
|
| +
|
| + // Add all clickable elements as a row into the grid.
|
| + this.addFocusRow_(node.nodeFileLink_, 'name');
|
| + this.addFocusRow_(node.nodeURL_, 'url');
|
| + this.addFocusRow_(node.controlShow_, 'show');
|
| + this.addFocusRow_(node.controlRetry_, 'retry');
|
| + this.addFocusRow_(node.controlPause_, 'pause');
|
| + this.addFocusRow_(node.controlResume_, 'resume');
|
| + this.addFocusRow_(node.controlRemove_, 'remove');
|
| + this.addFocusRow_(node.controlCancel_, 'cancel');
|
| +
|
| + // Only one set of these two buttons will be added to a download row at a
|
| + // time. They have the same type so that focus is handled well in case
|
| + // there is a dangerous download right next to a malicious download.
|
| + this.addFocusRow_(node.malwareSave_, 'save');
|
| + this.addFocusRow_(node.malwareDiscard_, 'discard');
|
| + this.addFocusRow_(node.dangerSave_, 'save');
|
| + this.addFocusRow_(node.dangerDiscard_, 'discard');
|
| +
|
| + this.addFocusRow_(node.controlByExtensionLink_, 'extension');
|
| +};
|
| +
|
| +DownloadFocusRow.prototype = {
|
| + __proto__: cr.ui.FocusRow.prototype,
|
| +
|
| + /** @override */
|
| + getEquivalentElement: function(element) {
|
| + if (this.contains(element))
|
| + return element;
|
| +
|
| + // All elements default to another element with the same type.
|
| + var query = '[column-type="' + element.getAttribute('column-type') + '"]';
|
| + var ret = this.getMatch(query);
|
| +
|
| + // The following element types are at the same UI level.
|
| + if (!ret) {
|
| + switch (element.getAttribute('column-type')) {
|
| + case ('show'):
|
| + case ('retry'):
|
| + case ('pause'):
|
| + case ('resume'):
|
| + case ('remove'):
|
| + case ('cancel'):
|
| + ret = this.getMatch('[column-type="show"]') ||
|
| + this.getMatch('[column-type="retry"]') ||
|
| + this.getMatch('[column-type="pause"]') ||
|
| + this.getMatch('[column-type="resume"]') ||
|
| + this.getMatch('[column-type="remove"]') ||
|
| + this.getMatch('[column-type="cancel"]');
|
| + break;
|
| + }
|
| + }
|
| +
|
| + // Any other miss should return the first rowElement.
|
| + return ret || this.rowElements[0];
|
| + },
|
| +
|
| + /**
|
| + * Add an element if it exists in this FocusRow and is focusable.
|
| + * @param {Element} element The element that should be added.
|
| + * @param {string} type The type to use for the element.
|
| + * @private
|
| + */
|
| + addFocusRow_: function(element, type) {
|
| + if (this.shouldFocus_(element)) {
|
| + this.setFocusableElement(element);
|
| + element.setAttribute('column-type', type);
|
| + }
|
| + },
|
| +
|
| + /**
|
| + * Determines if element should be focusable.
|
| + * @param {!Element} element
|
| + * @return {bool}
|
| + * @private
|
| + */
|
| + shouldFocus_: function(element) {
|
| + if (!element)
|
| + return false;
|
| +
|
| + // Hidden elements are not focusable.
|
| + var style = window.getComputedStyle(element);
|
| + if (style.visibility == 'hidden' || style.display == 'none')
|
| + return false;
|
| +
|
| + // Verify that all ancestors are focusable. This is necessary because of the
|
| + // case where a node has display set to something other than 'none', but it
|
| + // has an ancestor with display == 'none'.
|
| + if (element.parentElement)
|
| + return this.shouldFocus_(element.parentElement);
|
| +
|
| + return true;
|
| + },
|
| +};
|
| +
|
| +///////////////////////////////////////////////////////////////////////////////
|
| // Downloads
|
| /**
|
| * Class to hold all the information about the visible downloads.
|
| @@ -91,6 +197,7 @@ function Downloads() {
|
| this.node_ = $('downloads-display');
|
| this.summary_ = $('downloads-summary-text');
|
| this.searchText_ = '';
|
| + this.focusGrid_ = new cr.ui.FocusGrid();
|
|
|
| // Keep track of the dates of the newest and oldest downloads so that we
|
| // know where to insert them.
|
| @@ -176,6 +283,23 @@ Downloads.prototype.updateResults = function() {
|
|
|
| if (loadTimeData.getBoolean('allow_deleting_history'))
|
| $('clear-all').hidden = !hasDownloads || this.searchText_.length > 0;
|
| +
|
| + this.rebuildFocusGrid_();
|
| +};
|
| +
|
| +/**
|
| + * Rebuild the focusGrid_ using the elements that each download will have.
|
| + * @private
|
| + */
|
| +Downloads.prototype.rebuildFocusGrid_ = function() {
|
| + this.focusGrid_.destroy();
|
| +
|
| + // Keys for downloads are in the reverse order of what is displayed.
|
| + var keys = Object.keys(this.downloads_);
|
| + for (var i = keys.length - 1; i >= 0; --i) {
|
| + this.focusGrid_.addRow(new DownloadFocusRow(this.node_,
|
| + this.downloads_[keys[i]]));
|
| + }
|
| };
|
|
|
| /**
|
|
|