aboutsummaryrefslogtreecommitdiff
path: root/contexts/data/lib/closure-library/closure/goog/dom/pattern/sequence.js
blob: df40fd6f616febd2d4866172e3124ce657741553 (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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
// Copyright 2007 The Closure Library Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS-IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview DOM pattern to match a sequence of other patterns.
 *
 * @author robbyw@google.com (Robby Walker)
 */

goog.provide('goog.dom.pattern.Sequence');

goog.require('goog.dom.NodeType');
goog.require('goog.dom.pattern.AbstractPattern');
goog.require('goog.dom.pattern.MatchType');



/**
 * Pattern object that matches a sequence of other patterns.
 *
 * @param {Array.<goog.dom.pattern.AbstractPattern>} patterns Ordered array of
 *     patterns to match.
 * @param {boolean=} opt_ignoreWhitespace Optional flag to ignore text nodes
 *     consisting entirely of whitespace.  The default is to not ignore them.
 * @constructor
 * @extends {goog.dom.pattern.AbstractPattern}
 */
goog.dom.pattern.Sequence = function(patterns, opt_ignoreWhitespace) {
  this.patterns = patterns;
  this.ignoreWhitespace_ = !!opt_ignoreWhitespace;
};
goog.inherits(goog.dom.pattern.Sequence, goog.dom.pattern.AbstractPattern);


/**
 * Ordered array of patterns to match.
 *
 * @type {Array.<goog.dom.pattern.AbstractPattern>}
 */
goog.dom.pattern.Sequence.prototype.patterns;


/**
 * Position in the patterns array we have reached by successful matches.
 *
 * @type {number}
 * @private
 */
goog.dom.pattern.Sequence.prototype.currentPosition_ = 0;


/**
 * Whether or not to ignore whitespace only Text nodes.
 *
 * @type {boolean}
 * @private
 */
goog.dom.pattern.Sequence.prototype.ignoreWhitespace_ = false;


/**
 * Test whether the given token starts, continues, or finishes the sequence
 * of patterns given in the constructor.
 *
 * @param {Node} token Token to match against.
 * @param {goog.dom.TagWalkType} type The type of token.
 * @return {goog.dom.pattern.MatchType} <code>MATCH</code> if the pattern
 *     matches, <code>MATCHING</code> if the pattern starts a match, and
 *     <code>NO_MATCH</code> if the pattern does not match.
 * @override
 */
goog.dom.pattern.Sequence.prototype.matchToken = function(token, type) {
  // If the option is set, ignore any whitespace only text nodes
  if (this.ignoreWhitespace_ && token.nodeType == goog.dom.NodeType.TEXT &&
      goog.dom.pattern.BREAKING_TEXTNODE_RE.test(token.nodeValue)) {
    return goog.dom.pattern.MatchType.MATCHING;
  }

  switch (this.patterns[this.currentPosition_].matchToken(token, type)) {
    case goog.dom.pattern.MatchType.MATCH:
      // Record the first token we match.
      if (this.currentPosition_ == 0) {
        this.matchedNode = token;
      }

      // Move forward one position.
      this.currentPosition_++;

      // Check if this is the last position.
      if (this.currentPosition_ == this.patterns.length) {
        this.reset();
        return goog.dom.pattern.MatchType.MATCH;
      } else {
        return goog.dom.pattern.MatchType.MATCHING;
      }

    case goog.dom.pattern.MatchType.MATCHING:
      // This can happen when our child pattern is a sequence or a repetition.
      return goog.dom.pattern.MatchType.MATCHING;

    case goog.dom.pattern.MatchType.BACKTRACK_MATCH:
      // This means a repetitive match succeeded 1 token ago.
      // TODO(robbyw): Backtrack further if necessary.
      this.currentPosition_++;

      if (this.currentPosition_ == this.patterns.length) {
        this.reset();
        return goog.dom.pattern.MatchType.BACKTRACK_MATCH;
      } else {
        // Retry the same token on the next pattern.
        return this.matchToken(token, type);
      }

    default:
      this.reset();
      return goog.dom.pattern.MatchType.NO_MATCH;
  }
};


/**
 * Reset any internal state this pattern keeps.
 * @override
 */
goog.dom.pattern.Sequence.prototype.reset = function() {
  if (this.patterns[this.currentPosition_]) {
    this.patterns[this.currentPosition_].reset();
  }
  this.currentPosition_ = 0;
};