Chromium Code Reviews| Index: chrome/browser/resources/history/history.js |
| diff --git a/chrome/browser/resources/history/history.js b/chrome/browser/resources/history/history.js |
| index a71592de4ee5d70587681b99c7b513c00db04f3a..946d90224514e7bbd087e401a03c38138dcd4bfe 100644 |
| --- a/chrome/browser/resources/history/history.js |
| +++ b/chrome/browser/resources/history/history.js |
| @@ -250,6 +250,10 @@ Visit.prototype.getResultDOM = function(propertyBag) { |
| e.preventDefault(); |
| }.bind(this)); |
| } |
| + |
| + if (focusless) |
| + bookmarkSection.tabIndex = -1; |
| + |
| entryBox.appendChild(bookmarkSection); |
| var visitEntryWrapper = /** @type {HTMLElement} */( |
| @@ -884,69 +888,95 @@ HistoryModel.prototype.getGroupByDomain = function() { |
| }; |
| /////////////////////////////////////////////////////////////////////////////// |
| -// HistoryFocusObserver: |
| +// HistoryFocusRow: |
| /** |
| + * Provides an implementation for a single column grid. |
| * @constructor |
| - * @implements {cr.ui.FocusRow.Observer} |
| + * @extends {cr.ui.FocusRow} |
| + */ |
| +HistoryFocusRow = function() {}; |
|
Dan Beam
2015/01/27 22:32:23
why did you change from function Declaration() {}
hcarmona
2015/01/29 00:00:37
Must have happened when I moved the code around. C
|
| + |
| +/** |
| + * Decorates |rowElement| so that it can be treated as a HistoryFocusRow item. |
| + * @param {Element} rowElement The element representing this row. |
| + * @param {Node} boundary Focus events are ignored outside of this node. |
| */ |
| -function HistoryFocusObserver() {} |
| +HistoryFocusRow.decorate = function(rowElement, boundary) { |
| + rowElement.__proto__ = HistoryFocusRow.prototype; |
| + rowElement.decorate(boundary); |
| + |
| + /** |
| + * Both of these elements are checkboxes and a history focusRow will only |
| + * have 1 of the two. By giving them both the same type we can ensure |
| + * that a checkbox remains focused when focus changes. |
| + */ |
| + rowElement.addFocusRow_('.entry-box input', 'checkbox'); |
| + rowElement.addFocusRow_('.domain-checkbox', 'checkbox'); |
| + |
| + // Add the remaining elements. |
| + rowElement.addFocusRow_('.bookmark-section.starred', 'star'); |
| + rowElement.addFocusRow_('[is="action-link"]', 'domain'); |
| + rowElement.addFocusRow_('.title a', 'title'); |
| + rowElement.addFocusRow_('.drop-down', 'menu'); |
| +}; |
| + |
| +HistoryFocusRow.prototype = { |
| + __proto__: cr.ui.FocusRow.prototype, |
| -HistoryFocusObserver.prototype = { |
| /** @override */ |
| - onActivate: function(row) { |
| - this.getActiveRowElement_(row).classList.add('active'); |
| + onActiveStateChanged: function(state) { |
| + this.classList.toggle('active', state); |
| }, |
| /** @override */ |
| - onDeactivate: function(row) { |
| - this.getActiveRowElement_(row).classList.remove('active'); |
| + getEquivalentElement: function(element) { |
| + if (this.contains(element)) |
| + return element; |
| + |
| + // All elements default to another element with the same type. |
| + var ret = this.getColumn_(element.getAttribute('column-type')); |
| + |
| + if (!ret) { |
| + switch (element.getAttribute('column-type')) { |
| + case 'star': |
| + ret = this.getColumn_('title') || this.getColumn_('domain'); |
| + break; |
| + case 'domain': |
| + ret = this.getColumn_('title'); |
| + break; |
| + case 'title': |
| + ret = this.getColumn_('domain'); |
| + break; |
| + case 'menu': |
| + ret = this.focusableElements[this.focusableElements.length - 1]; |
| + } |
| + } |
| + |
| + return ret || this.focusableElements[0]; |
| }, |
| /** |
| - * @param {cr.ui.FocusRow} row The row to find an element for. |
| - * @return {Element} |row|'s "active" element. |
| + * @param {string} type The type of column to return. |
| + * @return {Element?} The column matching the type. |
|
Dan Beam
2015/01/27 22:32:23
nit: ?Element
hcarmona
2015/01/29 00:00:37
Done.
|
| * @private |
| */ |
| - getActiveRowElement_: function(row) { |
| - return findAncestorByClass(row.items[0], 'entry') || |
| - findAncestorByClass(row.items[0], 'site-domain-wrapper'); |
| + getColumn_: function(type) { |
| + return this.querySelector('[column-type=' + type + ']'); |
| }, |
| -}; |
| - |
| -/////////////////////////////////////////////////////////////////////////////// |
| -// HistoryFocusGrid: |
| - |
| -/** |
| - * @param {Node=} opt_boundary |
| - * @param {cr.ui.FocusRow.Observer=} opt_observer |
| - * @constructor |
| - * @extends {cr.ui.FocusGrid} |
| - */ |
| -function HistoryFocusGrid(opt_boundary, opt_observer) { |
| - cr.ui.FocusGrid.apply(this, arguments); |
| -} |
| -HistoryFocusGrid.prototype = { |
| - __proto__: cr.ui.FocusGrid.prototype, |
| - |
| - /** @override */ |
| - onMousedown: function(row, e) { |
| - // TODO(dbeam): Can cr.ui.FocusGrid know about cr.ui.MenuButton? If so, bake |
| - // this logic into the base class directly. |
| - var menuButton = findAncestorByClass(e.target, 'menu-button'); |
| - if (menuButton) { |
| - // Deactivate any other active row. |
| - this.rows.some(function(r) { |
| - if (r.activeIndex >= 0 && r != row) { |
| - r.activeIndex = -1; |
| - return true; |
| - } |
| - }); |
| - // Activate only the row with a pressed menu button. |
| - row.activeIndex = row.items.indexOf(menuButton); |
| + /** |
| + * Add a focusable element if it exists in this FocusRow. |
| + * @param {string} query A query to select the appropriate element. |
| + * @param {string} type The type to use for the element. |
| + * @private |
| + */ |
| + addFocusRow_: function(query, type) { |
| + var element = this.querySelector(query); |
| + if (element) { |
| + this.addFocusableElement(element); |
| + element.setAttribute('column-type', type); |
| } |
| - return !!menuButton; |
| }, |
| }; |
| @@ -964,8 +994,7 @@ function HistoryView(model) { |
| this.editButtonTd_ = $('edit-button'); |
| this.editingControlsDiv_ = $('editing-controls'); |
| this.resultDiv_ = $('results-display'); |
| - this.focusGrid_ = new HistoryFocusGrid(this.resultDiv_, |
| - new HistoryFocusObserver); |
| + this.focusGrid_ = new cr.ui.FocusGrid(); |
| this.pageDiv_ = $('results-pagination'); |
| this.model_ = model; |
| this.pageIndex_ = 0; |
| @@ -1197,14 +1226,14 @@ HistoryView.prototype.showNotification = function(innerHTML, isWarning) { |
| HistoryView.prototype.onBeforeRemove = function(visit) { |
| assert(this.currentVisits_.indexOf(visit) >= 0); |
| - var pos = this.focusGrid_.getPositionForTarget(document.activeElement); |
| - if (!pos) |
| + var rowIndex = this.focusGrid_.getRowIndexForTarget(document.activeElement); |
| + if (rowIndex == -1) |
| return; |
| - var row = this.focusGrid_.rows[pos.row + 1] || |
| - this.focusGrid_.rows[pos.row - 1]; |
| - if (row) |
| - row.focusIndex(Math.min(pos.col, row.items.length - 1)); |
| + var rowToFocus = this.focusGrid_.rows[rowIndex + 1] || |
| + this.focusGrid_.rows[rowIndex - 1]; |
| + if (rowToFocus) |
| + rowToFocus.getEquivalentElement(document.activeElement).focus(); |
| }; |
| /** @param {Visit} visit The visit about to be unstarred. */ |
| @@ -1212,9 +1241,14 @@ HistoryView.prototype.onBeforeUnstarred = function(visit) { |
| assert(this.currentVisits_.indexOf(visit) >= 0); |
| assert(visit.bookmarkStar == document.activeElement); |
| - var pos = this.focusGrid_.getPositionForTarget(document.activeElement); |
| - var row = this.focusGrid_.rows[pos.row]; |
| - row.focusIndex(Math.min(pos.col + 1, row.items.length - 1)); |
| + var rowIndex = this.focusGrid_.getRowIndexForTarget(document.activeElement); |
| + var row = this.focusGrid_.rows[rowIndex]; |
| + |
| + // Focus the title or domain when the bookmarked star is removed because the |
| + // star will no longer be focusable. |
| + var newFocus = row.querySelector('[column-type="title"]') || |
| + row.querySelector('[column-type="domain"]'); |
|
Dan Beam
2015/01/27 22:32:23
nit: arguably combine querySelector() calls into 1
hcarmona
2015/01/29 00:00:37
Done.
|
| + newFocus.focus(); |
| }; |
| /** @param {Visit} visit The visit that was just unstarred. */ |
| @@ -1312,7 +1346,7 @@ HistoryView.prototype.positionNotificationBar = function() { |
| * @return {boolean} Whether |el| is in |this.focusGrid_|. |
| */ |
| HistoryView.prototype.isInFocusGrid = function(el) { |
| - return !!this.focusGrid_.getPositionForTarget(el); |
| + return this.focusGrid_.getRowIndexForTarget(el) != -1; |
| }; |
| // HistoryView, private: ------------------------------------------------------ |
| @@ -1674,26 +1708,16 @@ var focusGridRowSelector = [ |
| '.site-domain-wrapper' |
| ].join(', '); |
| -var focusGridColumnSelector = [ |
| - '.entry-box input', |
| - '.bookmark-section.starred', |
| - '.title a', |
| - '.drop-down', |
| - '.domain-checkbox', |
| - '[is="action-link"]', |
| -].join(', '); |
| - |
| /** @private */ |
| HistoryView.prototype.updateFocusGrid_ = function() { |
| var rows = this.resultDiv_.querySelectorAll(focusGridRowSelector); |
| - var grid = []; |
| + this.focusGrid_.destroy(); |
| for (var i = 0; i < rows.length; ++i) { |
| assert(rows[i].parentNode); |
| - grid.push(rows[i].querySelectorAll(focusGridColumnSelector)); |
| + HistoryFocusRow.decorate(rows[i], this.resultDiv_); |
| + this.focusGrid_.addRow(rows[i]); |
| } |
| - |
| - this.focusGrid_.setGrid(grid); |
| }; |
| /** |