cygprofile: increase timeouts to allow showing web contents
[chromium-blink-merge.git] / chrome / browser / resources / chromeos / chromevox / walkers / table_walker.js
blobcd6f3c885d78d7026b0533abb7282634b5762d19
1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 /**
6 * @fileoverview A class for walking tables.
7 * NOTE: This class has a very different interface than the other walkers.
8 * This means it does not lend itself easily to e.g. decorators.
9 * TODO (stoarca): This might be able to be fixed by breaking it up into
10 * separate walkers for cell, row and column.
14 goog.provide('cvox.TableWalker');
16 goog.require('cvox.AbstractWalker');
17 goog.require('cvox.BrailleUtil');
18 goog.require('cvox.DescriptionUtil');
19 goog.require('cvox.DomUtil');
20 goog.require('cvox.NavDescription');
21 goog.require('cvox.QueueMode');
22 goog.require('cvox.TraverseTable');
24 /**
25 * @constructor
26 * @extends {cvox.AbstractWalker}
28 cvox.TableWalker = function() {
29 cvox.AbstractWalker.call(this);
31 /**
32 * Only used as a cache for faster lookup.
33 * @type {!cvox.TraverseTable}
35 this.tt = new cvox.TraverseTable(null);
37 goog.inherits(cvox.TableWalker, cvox.AbstractWalker);
39 /**
40 * @override
42 cvox.TableWalker.prototype.next = function(sel) {
43 // TODO (stoarca): See bug 6677953
44 return this.nextRow(sel);
47 /**
48 * @override
50 cvox.TableWalker.prototype.sync = function(sel) {
51 return this.goTo_(sel, goog.bind(function(position) {
52 return this.tt.goToCell(position);
53 }, this));
56 /**
57 * @override
58 * @suppress {checkTypes} actual parameter 2 of
59 * cvox.Msgs.prototype.getMsg does not match formal parameter
60 * found : Array<number>
61 * required: (Array<string>|null|undefined)
63 cvox.TableWalker.prototype.getDescription = function(prevSel, sel) {
64 var position = this.syncPosition_(sel);
65 if (!position) {
66 return [];
68 this.tt.goToCell(position);
69 var descs = cvox.DescriptionUtil.getCollectionDescription(prevSel, sel);
70 if (descs.length == 0) {
71 descs.push(new cvox.NavDescription({
72 annotation: cvox.ChromeVox.msgs.getMsg('empty_cell')
73 }));
75 return descs;
78 /**
79 * @override
81 cvox.TableWalker.prototype.getBraille = function(prevSel, sel) {
82 var ret = new cvox.NavBraille({});
83 var position = this.syncPosition_(sel);
84 if (position) {
85 var text =
86 cvox.BrailleUtil.getTemplated(prevSel.start.node, sel.start.node);
87 text.append(' ' + ++position[0] + '/' + ++position[1]);
89 return new cvox.NavBraille({text: text});
92 /**
93 * @override
95 cvox.TableWalker.prototype.getGranularityMsg = goog.abstractMethod;
98 /** Table Actions. */
102 * Returns the first cell of the table that this selection is inside.
103 * @param {!cvox.CursorSelection} sel The selection.
104 * @return {cvox.CursorSelection} The selection for first cell of the table.
105 * @export
107 cvox.TableWalker.prototype.goToFirstCell = function(sel) {
108 return this.goTo_(sel, goog.bind(function(position) {
109 return this.tt.goToCell([0, 0]);
110 }, this));
114 * Returns the last cell of the table that this selection is inside.
115 * @param {!cvox.CursorSelection} sel The selection.
116 * @return {cvox.CursorSelection} The selection for the last cell of the table.
117 * @export
119 cvox.TableWalker.prototype.goToLastCell = function(sel) {
120 return this.goTo_(sel, goog.bind(function(position) {
121 return this.tt.goToLastCell();
122 }, this));
126 * Returns the first cell of the row that the selection is in.
127 * @param {!cvox.CursorSelection} sel The selection.
128 * @return {cvox.CursorSelection} The selection for the first cell in the row.
129 * @export
131 cvox.TableWalker.prototype.goToRowFirstCell = function(sel) {
132 return this.goTo_(sel, goog.bind(function(position) {
133 return this.tt.goToCell([position[0], 0]);
134 }, this));
138 * Returns the last cell of the row that the selection is in.
139 * @param {!cvox.CursorSelection} sel The selection.
140 * @return {cvox.CursorSelection} The selection for the last cell in the row.
141 * @export
143 cvox.TableWalker.prototype.goToRowLastCell = function(sel) {
144 return this.goTo_(sel, goog.bind(function(position) {
145 return this.tt.goToRowLastCell();
146 }, this));
150 * Returns the first cell of the column that the selection is in.
151 * @param {!cvox.CursorSelection} sel The selection.
152 * @return {cvox.CursorSelection} The selection for the first cell in the col.
153 * @export
155 cvox.TableWalker.prototype.goToColFirstCell = function(sel) {
156 return this.goTo_(sel, goog.bind(function(position) {
157 return this.tt.goToCell([0, position[1]]);
158 }, this));
162 * Returns the last cell of the column that the selection is in.
163 * @param {!cvox.CursorSelection} sel The selection.
164 * @return {cvox.CursorSelection} The selection for the last cell in the col.
165 * @export
167 cvox.TableWalker.prototype.goToColLastCell = function(sel) {
168 return this.goTo_(sel, goog.bind(function(position) {
169 return this.tt.goToColLastCell();
170 }, this));
174 * Returns the first cell in the row after the current selection.
175 * @param {!cvox.CursorSelection} sel The selection.
176 * @return {cvox.CursorSelection} The selection for the first cell in the next
177 * row.
178 * @export
180 cvox.TableWalker.prototype.nextRow = function(sel) {
181 return this.goTo_(sel, goog.bind(function(position) {
182 return this.tt.goToCell([position[0] + (sel.isReversed() ? -1 : 1),
183 position[1]]);
184 }, this));
188 * Returns the first cell in the column after the current selection.
189 * @param {!cvox.CursorSelection} sel The selection.
190 * @return {cvox.CursorSelection} The selection for the first cell in the
191 * next col.
192 * @export
194 cvox.TableWalker.prototype.nextCol = function(sel) {
195 return this.goTo_(sel, goog.bind(function(position) {
196 return this.tt.goToCell([position[0],
197 position[1] + (sel.isReversed() ? -1 : 1)]);
198 }, this));
202 * @param {!cvox.CursorSelection} sel The current selection.
203 * @return {cvox.CursorSelection} The resulting selection.
204 * @export
206 cvox.TableWalker.prototype.announceHeaders = function(sel) {
207 cvox.ChromeVox.tts.speak(this.getHeaderText_(sel),
208 cvox.QueueMode.FLUSH,
209 cvox.AbstractTts.PERSONALITY_ANNOTATION);
210 return sel;
214 * @param {!cvox.CursorSelection} sel The current selection.
215 * @return {cvox.CursorSelection} The resulting selection.
216 * @export
218 cvox.TableWalker.prototype.speakTableLocation = function(sel) {
219 cvox.ChromeVox.navigationManager.speakDescriptionArray(
220 this.getLocationDescription_(sel),
221 cvox.QueueMode.FLUSH,
222 null);
223 return sel;
228 * @param {!cvox.CursorSelection} sel The current selection.
229 * @return {cvox.CursorSelection} The resulting selection.
230 * @export
232 cvox.TableWalker.prototype.exitShifterContent = function(sel) {
233 var tableNode = this.getTableNode_(sel);
234 if (!tableNode) {
235 return null;
237 var nextNode = cvox.DomUtil.directedNextLeafNode(tableNode, false);
238 return cvox.CursorSelection.fromNode(nextNode);
242 /** End of actions. */
246 * Returns the text content of the header(s) of the cell that contains sel.
247 * @param {!cvox.CursorSelection} sel The selection.
248 * @return {!string} The header text.
249 * @private
251 cvox.TableWalker.prototype.getHeaderText_ = function(sel) {
252 this.tt.initialize(this.getTableNode_(sel));
253 var position = this.tt.findNearestCursor(sel.start.node);
254 if (!position) {
255 return cvox.ChromeVox.msgs.getMsg('not_inside_table');
257 if (!this.tt.goToCell(position)) {
258 return cvox.ChromeVox.msgs.getMsg('not_inside_table');
260 return (
261 this.getRowHeaderText_(position) +
262 ' ' +
263 this.getColHeaderText_(position));
267 * Returns the location description.
268 * @param {!cvox.CursorSelection} sel A valid selection.
269 * @return {Array<cvox.NavDescription>} The location description.
270 * @suppress {checkTypes} actual parameter 2 of
271 * cvox.Msgs.prototype.getMsg does not match
272 * formal parameter
273 * found : Array<number>
274 * required: (Array<string>|null|undefined)
275 * @private
277 cvox.TableWalker.prototype.getLocationDescription_ = function(sel) {
278 var locationInfo = this.getLocationInfo(sel);
279 if (locationInfo == null) {
280 return null;
282 return [new cvox.NavDescription({
283 text: cvox.ChromeVox.msgs.getMsg('table_location', locationInfo)
284 })];
288 * Returns the text content of the row header(s) of the cell that contains sel.
289 * @param {!Array<number>} position The selection.
290 * @return {!string} The header text.
291 * @private
293 cvox.TableWalker.prototype.getRowHeaderText_ = function(position) {
294 // TODO(stoarca): OPTMZ Replace with join();
295 var rowHeaderText = '';
297 var rowHeaders = this.tt.getCellRowHeaders();
298 if (rowHeaders.length == 0) {
299 var firstCellInRow = this.tt.getCellAt([position[0], 0]);
300 rowHeaderText += cvox.DomUtil.collapseWhitespace(
301 cvox.DomUtil.getValue(firstCellInRow) + ' ' +
302 cvox.DomUtil.getName(firstCellInRow));
303 return cvox.ChromeVox.msgs.getMsg('row_header') + rowHeaderText;
306 for (var i = 0; i < rowHeaders.length; ++i) {
307 rowHeaderText += cvox.DomUtil.collapseWhitespace(
308 cvox.DomUtil.getValue(rowHeaders[i]) + ' ' +
309 cvox.DomUtil.getName(rowHeaders[i]));
311 if (rowHeaderText == '') {
312 return cvox.ChromeVox.msgs.getMsg('empty_row_header');
314 return cvox.ChromeVox.msgs.getMsg('row_header') + rowHeaderText;
318 * Returns the text content of the col header(s) of the cell that contains sel.
319 * @param {!Array<number>} position The selection.
320 * @return {!string} The header text.
321 * @private
323 cvox.TableWalker.prototype.getColHeaderText_ = function(position) {
324 // TODO(stoarca): OPTMZ Replace with join();
325 var colHeaderText = '';
327 var colHeaders = this.tt.getCellColHeaders();
328 if (colHeaders.length == 0) {
329 var firstCellInCol = this.tt.getCellAt([0, position[1]]);
330 colHeaderText += cvox.DomUtil.collapseWhitespace(
331 cvox.DomUtil.getValue(firstCellInCol) + ' ' +
332 cvox.DomUtil.getName(firstCellInCol));
333 return cvox.ChromeVox.msgs.getMsg('column_header') + colHeaderText;
336 for (var i = 0; i < colHeaders.length; ++i) {
337 colHeaderText += cvox.DomUtil.collapseWhitespace(
338 cvox.DomUtil.getValue(colHeaders[i]) + ' ' +
339 cvox.DomUtil.getName(colHeaders[i]));
341 if (colHeaderText == '') {
342 return cvox.ChromeVox.msgs.getMsg('empty_row_header');
344 return cvox.ChromeVox.msgs.getMsg('column_header') + colHeaderText;
348 * Returns the location info of sel within the containing table.
349 * @param {!cvox.CursorSelection} sel The selection.
350 * @return {Array<number>} The location info:
351 * [row index, row count, col index, col count].
353 cvox.TableWalker.prototype.getLocationInfo = function(sel) {
354 this.tt.initialize(this.getTableNode_(sel));
355 var position = this.tt.findNearestCursor(sel.start.node);
356 if (!position) {
357 return null;
359 // + 1 to account for 0-indexed
360 return [
361 position[0] + 1,
362 this.tt.rowCount,
363 position[1] + 1,
364 this.tt.colCount
365 ].map(function(x) {return cvox.ChromeVox.msgs.getNumber(x);});
369 * Returns true if sel is inside a table.
370 * @param {!cvox.CursorSelection} sel The selection.
371 * @return {boolean} True if inside a table node.
373 cvox.TableWalker.prototype.isInTable = function(sel) {
374 return this.getTableNode_(sel) != null;
378 * Wrapper for going to somewhere so that boilerplate is not repeated.
379 * @param {!cvox.CursorSelection} sel The selection from which to base the
380 * movement.
381 * @param {function(Array<number>):boolean} f The function to use for moving.
382 * Returns true on success and false on failure.
383 * @return {cvox.CursorSelection} The resulting selection.
384 * @private
386 cvox.TableWalker.prototype.goTo_ = function(sel, f) {
387 this.tt.initialize(this.getTableNode_(sel));
388 var position = this.tt.findNearestCursor(sel.end.node);
389 if (!position) {
390 return null;
392 this.tt.goToCell(position);
393 if (!f(position)) {
394 return null;
396 return cvox.CursorSelection.fromNode(this.tt.getCell()).
397 setReversed(sel.isReversed());
401 * Returns the nearest table node containing the end of the selection
402 * @param {!cvox.CursorSelection} sel The selection.
403 * @return {Node} The table node containing sel. null if not in a table.
404 * @private
406 cvox.TableWalker.prototype.getTableNode_ = function(sel) {
407 return cvox.DomUtil.getContainingTable(sel.end.node);
411 * Sync the backing traversal utility to the given selection.
412 * @param {!cvox.CursorSelection} sel The selection.
413 * @return {Array<number>} The position [x, y] of the selection.
414 * @private
416 cvox.TableWalker.prototype.syncPosition_ = function(sel) {
417 var tableNode = this.getTableNode_(sel);
418 this.tt.initialize(tableNode);
419 // we need to align the TraverseTable with our sel because our walker
420 // uses parts of it (for example isSpanned relies on being at a specific cell)
421 return this.tt.findNearestCursor(sel.end.node);