Path: blob/trunk/third_party/closure/goog/dom/pattern/matcher.js
2868 views
// Copyright 2007 The Closure Library Authors. All Rights Reserved.1//2// Licensed under the Apache License, Version 2.0 (the "License");3// you may not use this file except in compliance with the License.4// You may obtain a copy of the License at5//6// http://www.apache.org/licenses/LICENSE-2.07//8// Unless required by applicable law or agreed to in writing, software9// distributed under the License is distributed on an "AS-IS" BASIS,10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.11// See the License for the specific language governing permissions and12// limitations under the License.1314/**15* @fileoverview DOM pattern matcher. Allows for simple searching of DOM16* using patterns descended from {@link goog.dom.pattern.AbstractPattern}.17*18* @author [email protected] (Robby Walker)19*/2021goog.provide('goog.dom.pattern.Matcher');2223goog.require('goog.dom.TagIterator');24goog.require('goog.dom.pattern.MatchType');25goog.require('goog.iter');262728// TODO(robbyw): Allow for backtracks of size > 1.29303132/**33* Given a set of patterns and a root node, this class tests the patterns in34* parallel.35*36* It is not (yet) a smart matcher - it doesn't do any advanced backtracking.37* Given the pattern <code>DIV, SPAN</code> the matcher will not match38* <code>DIV, DIV, SPAN</code> because it starts matching at the first39* <code>DIV</code>, fails to match <code>SPAN</code> at the second, and never40* backtracks to try again.41*42* It is also possible to have a set of complex patterns that when matched in43* parallel will miss some possible matches. Running multiple times will catch44* all matches eventually.45*46* @constructor47* @final48*/49goog.dom.pattern.Matcher = function() {50/**51* Array of patterns to attempt to match in parallel.52*53* @private {Array<goog.dom.pattern.AbstractPattern>}54*/55this.patterns_ = [];5657/**58* Array of callbacks to call when a pattern is matched. The indexing is the59* same as the {@link #patterns_} array.60*61* @private {Array<Function>}62*/63this.callbacks_ = [];64};656667/**68* Adds a pattern to be matched. The callback can return an object whose keys69* are processing instructions.70*71* @param {goog.dom.pattern.AbstractPattern} pattern The pattern to add.72* @param {Function} callback Function to call when a match is found. Uses73* the above semantics.74*/75goog.dom.pattern.Matcher.prototype.addPattern = function(pattern, callback) {76this.patterns_.push(pattern);77this.callbacks_.push(callback);78};798081/**82* Resets all the patterns.83*84* @private85*/86goog.dom.pattern.Matcher.prototype.reset_ = function() {87for (var i = 0, len = this.patterns_.length; i < len; i++) {88this.patterns_[i].reset();89}90};919293/**94* Test the given node against all patterns.95*96* @param {goog.dom.TagIterator} position A position in a node walk that is97* located at the token to process.98* @return {boolean} Whether a pattern modified the position or tree99* and its callback resulted in DOM structure or position modification.100* @private101*/102goog.dom.pattern.Matcher.prototype.matchToken_ = function(position) {103for (var i = 0, len = this.patterns_.length; i < len; i++) {104var pattern = this.patterns_[i];105switch (pattern.matchToken(position.node, position.tagType)) {106case goog.dom.pattern.MatchType.MATCH:107case goog.dom.pattern.MatchType.BACKTRACK_MATCH:108var callback = this.callbacks_[i];109110// Callbacks are allowed to modify the current position, but must111// return true if the do.112if (callback(pattern.matchedNode, position, pattern)) {113return true;114}115116default:117// Do nothing.118break;119}120}121122return false;123};124125126/**127* Match the set of patterns against a match tree.128*129* @param {Node} node The root node of the tree to match.130*/131goog.dom.pattern.Matcher.prototype.match = function(node) {132var position = new goog.dom.TagIterator(node);133134this.reset_();135136goog.iter.forEach(position, function() {137while (this.matchToken_(position)) {138// Since we've moved, our old pattern statuses don't make sense any more.139// Reset them.140this.reset_();141}142}, this);143};144145146