Home | History | Annotate | Download | only in walkers
      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.
      4 
      5 /**
      6  * @fileoverview A base class for walkers that have a concept of lowest-level
      7  * node. Base classes must override the stopNodeDescent method to define
      8  * what a lowest-level node is. Then this walker will use those nodes as the
      9  * set of valid CursorSelections.
     10  */
     11 
     12 
     13 goog.provide('cvox.AbstractNodeWalker');
     14 
     15 goog.require('cvox.AbstractWalker');
     16 goog.require('cvox.CursorSelection');
     17 goog.require('cvox.DomUtil');
     18 
     19 /**
     20  * @constructor
     21  * @extends {cvox.AbstractWalker}
     22  */
     23 cvox.AbstractNodeWalker = function() {
     24   goog.base(this);
     25 
     26   /**
     27    * To keep track of and break infinite loops when trying to call next on
     28    * a body that does not DomUtil.hasContent().
     29    * @type {boolean}
     30    * @private
     31    */
     32   this.wasBegin_ = false;
     33 };
     34 goog.inherits(cvox.AbstractNodeWalker, cvox.AbstractWalker);
     35 
     36 /**
     37  * @override
     38  */
     39 cvox.AbstractNodeWalker.prototype.next = function(sel) {
     40   var r = sel.isReversed();
     41   var node = sel.end.node || document.body;
     42 
     43   do {
     44     node = cvox.DomUtil.directedNextLeafLikeNode(node, r,
     45         goog.bind(this.stopNodeDescent, this));
     46     if (!node) {
     47       return null;
     48     }
     49     // and repeat all of the above until we have a node that is not empty
     50   } while (node && !cvox.DomUtil.hasContent(node));
     51 
     52   return cvox.CursorSelection.fromNode(node).setReversed(r);
     53 };
     54 
     55 /**
     56  * @override
     57  */
     58 cvox.AbstractNodeWalker.prototype.sync = function(sel) {
     59   var ret = this.privateSync_(sel);
     60   this.wasBegin_ = false;
     61   return ret;
     62 };
     63 
     64 
     65 /**
     66  * Private version of sync to ensure that when a body has no content, we
     67  * don't do an infinite loop trying to find an empty node.
     68  * @param {!cvox.CursorSelection} sel The selection.
     69  * @return {cvox.CursorSelection} The synced selection.
     70  * @private
     71  */
     72 cvox.AbstractNodeWalker.prototype.privateSync_ = function(sel) {
     73   var r = sel.isReversed();
     74 
     75   if (sel.equals(cvox.CursorSelection.fromBody())) {
     76     if (this.wasBegin_) {
     77       // if body is empty, we return just the body selection
     78       return cvox.CursorSelection.fromBody().setReversed(r);
     79     }
     80     this.wasBegin_ = true;
     81   }
     82 
     83   var node = sel.start.node;
     84 
     85   while (node != document.body && node.parentNode &&
     86       this.stopNodeDescent(node.parentNode)) {
     87     node = node.parentNode;
     88   }
     89 
     90   while (!this.stopNodeDescent(node)) {
     91     node = cvox.DomUtil.directedFirstChild(node, r);
     92   }
     93 
     94   var n = cvox.CursorSelection.fromNode(node);
     95   if (!cvox.DomUtil.hasContent(node)) {
     96     var n = this.next(/** @type {!cvox.CursorSelection} */
     97         (cvox.CursorSelection.fromNode(node)).setReversed(r));
     98   }
     99   if (n) {
    100     return n.setReversed(r);
    101   }
    102   return this.begin({reversed: r});
    103 };
    104 
    105 /**
    106  * Returns true if this is "a leaf node" or lower. That is,
    107  * it is at the lowest valid level or lower for this granularity.
    108  * RESTRICTION: true for a node => true for all child nodes
    109  * RESTRICTION: true if node has no children
    110  * @param {!Node} node The node to check.
    111  * @return {boolean} true if this is at the "leaf node" level or lower
    112  * for this granularity.
    113  * @protected
    114  */
    115 cvox.AbstractNodeWalker.prototype.stopNodeDescent = goog.abstractMethod;
    116