summaryrefslogtreecommitdiffstats
path: root/chrome/browser/resources/chromeos/chromevox/common/find_util.js
blob: a5ac8a6b3713453e9e932c205c4443d86ee24646 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/**
 * @fileoverview Utilities for finding DOM nodes and CursorSelection's.
 */


goog.provide('cvox.FindUtil');

goog.require('cvox.BareObjectWalker');
goog.require('cvox.CursorSelection');


/**
 * @type {!cvox.BareObjectWalker}
 * @private
 */
cvox.FindUtil.objectWalker_ = new cvox.BareObjectWalker();


/**
 * Finds the next selection that matches the predicate function starting from
 * sel. Undefined if the nodes in sel are not attached to the document.
 * @param {!cvox.CursorSelection} sel The selection from which to start.
 * @param {function(Array<Node>):Node} predicate A function taking a
 * unique ancestor tree and outputting Node if the ancestor tree matches
 * the desired node to find.
 * @param {boolean=} opt_initialNode Whether to start the search from node
 * (true), or the next node (false); defaults to false.
 * @return {cvox.CursorSelection} The selection that was found.
 * null if end of document reached.
 */
cvox.FindUtil.findNext = function(sel, predicate, opt_initialNode) {
  var r = sel.isReversed();
  var cur = new cvox.CursorSelection(sel.absStart(), sel.absStart())
      .setReversed(r);

  // We may have been sync'ed into a subtree of the current predicate match.
  // Find our ancestor that matches the predicate.
  var ancestor;
  if (ancestor = predicate(cvox.DomUtil.getAncestors(cur.start.node))) {
    cur = cvox.CursorSelection.fromNode(ancestor).setReversed(r);
    if (opt_initialNode) {
      return cur;
    }
  }

  while (cur) {
    // Use ObjectWalker's traversal which guarantees us a stable iteration of
    // the DOM including returning null at page bounds.
    cur = cvox.FindUtil.objectWalker_.next(cur);
    var retNode = null;
    if (!cur ||
        (retNode = predicate(cvox.DomUtil.getAncestors(cur.start.node)))) {
      return retNode ? cvox.CursorSelection.fromNode(retNode) : null;
    }

    // Iframes require inter-frame messaging.
    if (cur.start.node.tagName == 'IFRAME') {
      return cur;
    }
  }
  return null;
};