Index: ui/webui/resources/js/cr/ui/focus_grid.js |
diff --git a/ui/webui/resources/js/cr/ui/focus_grid.js b/ui/webui/resources/js/cr/ui/focus_grid.js |
index 2e76ca10c03009f2d5d72e5a781989e1754a00f4..7752ddf9b58186c4fe2e81b7820d62fbd0498c44 100644 |
--- a/ui/webui/resources/js/cr/ui/focus_grid.js |
+++ b/ui/webui/resources/js/cr/ui/focus_grid.js |
@@ -18,7 +18,7 @@ cr.define('cr.ui', function() { |
* focusable [focused] focusable (row: 1, col: 1) |
* focusable focusable focusable |
* |
- * And pressing right at this point would move the focus to: |
+ * And pressing right or tab at this point would move the focus to: |
* |
* focusable focusable focusable |
* focusable focusable [focused] (row: 1, col: 2) |
@@ -26,7 +26,6 @@ cr.define('cr.ui', function() { |
* |
* @param {Node=} opt_boundary Ignore focus events outside this node. |
* @param {cr.ui.FocusRow.Observer=} opt_observer An observer of rows. |
- * @implements {cr.ui.FocusRow.Delegate} |
* @constructor |
*/ |
function FocusGrid(opt_boundary, opt_observer) { |
@@ -38,8 +37,45 @@ cr.define('cr.ui', function() { |
/** @type {!Array.<!cr.ui.FocusRow>} */ |
this.rows = []; |
+ |
+ /** @private {!EventTracker} */ |
+ this.eventTracker_ = new EventTracker; |
+ this.eventTracker_.add(cr.doc, 'keydown', this.onKeydown_.bind(this)); |
+ |
+ /** @private {cr.ui.FocusRow.Delegate} */ |
+ this.delegate_ = new FocusGrid.RowDelegate(this); |
} |
+ /** |
+ * Row delegate to overwrite the behavior of a mouse click to deselect any row |
+ * that wasn't clicked. |
+ * @param {cr.ui.FocusGrid} focusGrid |
+ * @implements {cr.ui.FocusRow.Delegate} |
+ */ |
+ FocusGrid.RowDelegate = function(focusGrid) { |
+ /** @private {cr.ui.FocusGrid} */ |
+ this.focusGrid_ = focusGrid; |
+ }; |
+ FocusGrid.RowDelegate.prototype = { |
+ /** @override */ |
+ onKeydown: function(row, e) { return false; }, |
+ |
+ /** @override */ |
+ onMousedown: function(row, e) { |
+ // Only care about left mouse click. |
+ if (e.button) |
+ return false; |
+ |
+ // Focus the clicked row, unfocus all others. |
+ var rows = this.focusGrid_.rows; |
+ for (var i = 0; i < rows.length; ++i) |
+ rows[i].onFocusIdChange(rows[i].getElementId(e.target)); |
+ |
+ e.preventDefault(); |
+ return true; |
+ }, |
+ }; |
+ |
FocusGrid.prototype = { |
/** |
* Unregisters event handlers and removes all |this.rows|. |
@@ -51,63 +87,85 @@ cr.define('cr.ui', function() { |
/** |
* @param {EventTarget} target A target item to find in this grid. |
- * @return {?{row: number, col: number}} A position or null if not found. |
+ * @return {?{row: number, elementId: string}} A position or null if not |
+ * found. |
*/ |
getPositionForTarget: function(target) { |
for (var i = 0; i < this.rows.length; ++i) { |
- for (var j = 0; j < this.rows[i].items.length; ++j) { |
- if (target == this.rows[i].items[j]) |
- return {row: i, col: j}; |
- } |
+ var elementId = this.rows[i].getElementId(target); |
+ if (elementId) |
+ return { row: i, elementId: elementId }; |
} |
return null; |
}, |
- /** @override */ |
- onKeydown: function(keyRow, e) { |
- var rowIndex = this.rows.indexOf(keyRow); |
- assert(rowIndex >= 0); |
+ /** |
+ * Handles keyboard shortcuts to move up/down in the grid. |
+ * @param {Event} e The key event. |
+ */ |
+ onKeydown_: function(e) { |
+ var pos = this.getPositionForTarget(e.target); |
+ if (!pos) |
+ return; |
var row = -1; |
if (e.keyIdentifier == 'Up') |
- row = rowIndex - 1; |
+ row = pos.row - 1; |
else if (e.keyIdentifier == 'Down') |
- row = rowIndex + 1; |
+ row = pos.row + 1; |
else if (e.keyIdentifier == 'PageUp') |
row = 0; |
else if (e.keyIdentifier == 'PageDown') |
row = this.rows.length - 1; |
if (!this.rows[row]) |
- return false; |
+ return; |
- var colIndex = keyRow.items.indexOf(e.target); |
- var col = Math.min(colIndex, this.rows[row].items.length - 1); |
- |
- this.rows[row].focusIndex(col); |
+ // Allow a grid to remember the elementId if a column is missing from a |
+ // row. The elementId is reset if the column focus changed while the row |
+ // was focused. |
+ if (!this.rememberedId || this.rows[pos.row].focusChanged()) |
+ this.rememberedId = pos.elementId; |
+ this.rows[row].setFocusId(this.rememberedId); |
+ this.rows[row].trackFocus(); |
e.preventDefault(); |
- return true; |
}, |
- /** @override */ |
- onMousedown: function(row, e) { |
- return false; |
+ /** |
+ * Create a new FocusRow for this grid and return it. |
+ * This row will need to be added to the grid using addRow. |
+ * @return {cr.ui.FocusRow} The row that was added to the grid. |
+ */ |
+ createRow: function() { |
+ return new cr.ui.FocusRow(this.boundary_, this.delegate_, this.observer_); |
}, |
/** |
- * @param {!Array.<!NodeList|!Array.<!Element>>} grid A 2D array of nodes. |
+ * Add a FocusRow to this grid. This needs to be called AFTER adding columns |
+ * to the row. This is so that TAB focus can be properly enabled in the |
+ * columns. |
+ * @param {cr.ui.FocusRow} row The row that needs to be added to this grid. |
*/ |
- setGrid: function(grid) { |
- this.destroy(); |
- |
- this.rows = grid.map(function(row) { |
- return new cr.ui.FocusRow(row, this.boundary_, this, this.observer_); |
- }, this); |
+ addRow: function(row) { |
+ if (this.rows.length == 0) { |
+ // Focus the first row. |
+ row.setInitialFocus(true); |
+ } |
+ else { |
+ if (row.getElementId(document.activeElement)) { |
+ // Update focus if the current row is active. |
+ this.rows[0].setInitialFocus(false); |
+ row.setInitialFocus(true); |
+ } else { |
+ // Make sure initial focus is false if the row isn't active. |
+ row.setInitialFocus(false); |
+ } |
+ } |
- if (!this.getPositionForTarget(document.activeElement) && this.rows[0]) |
- this.rows[0].activeIndex = 0; |
+ // Add the row after its initial focus is set. |
+ this.rows.push(row); |
}, |
}; |