| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 | var ElementType = require("domelementtype");var re_whitespace = /\s+/g;var NodePrototype = require("./lib/node");var ElementPrototype = require("./lib/element");function DomHandler(callback, options, elementCB){	if(typeof callback === "object"){		elementCB = options;		options = callback;		callback = null;	} else if(typeof options === "function"){		elementCB = options;		options = defaultOpts;	}	this._callback = callback;	this._options = options || defaultOpts;	this._elementCB = elementCB;	this.dom = [];	this._done = false;	this._tagStack = [];	this._parser = this._parser || null;}//default optionsvar defaultOpts = {	normalizeWhitespace: false, //Replace all whitespace with single spaces	withStartIndices: false, //Add startIndex properties to nodes	withEndIndices: false, //Add endIndex properties to nodes};DomHandler.prototype.onparserinit = function(parser){	this._parser = parser;};//Resets the handler back to starting stateDomHandler.prototype.onreset = function(){	DomHandler.call(this, this._callback, this._options, this._elementCB);};//Signals the handler that parsing is doneDomHandler.prototype.onend = function(){	if(this._done) return;	this._done = true;	this._parser = null;	this._handleCallback(null);};DomHandler.prototype._handleCallback =DomHandler.prototype.onerror = function(error){	if(typeof this._callback === "function"){		this._callback(error, this.dom);	} else {		if(error) throw error;	}};DomHandler.prototype.onclosetag = function(){	//if(this._tagStack.pop().name !== name) this._handleCallback(Error("Tagname didn't match!"));		var elem = this._tagStack.pop();	if(this._options.withEndIndices && elem){		elem.endIndex = this._parser.endIndex;	}	if(this._elementCB) this._elementCB(elem);};DomHandler.prototype._createDomElement = function(properties){	if (!this._options.withDomLvl1) return properties;	var element;	if (properties.type === "tag") {		element = Object.create(ElementPrototype);	} else {		element = Object.create(NodePrototype);	}	for (var key in properties) {		if (properties.hasOwnProperty(key)) {			element[key] = properties[key];		}	}	return element;};DomHandler.prototype._addDomElement = function(element){	var parent = this._tagStack[this._tagStack.length - 1];	var siblings = parent ? parent.children : this.dom;	var previousSibling = siblings[siblings.length - 1];	element.next = null;	if(this._options.withStartIndices){		element.startIndex = this._parser.startIndex;	}	if(this._options.withEndIndices){		element.endIndex = this._parser.endIndex;	}	if(previousSibling){		element.prev = previousSibling;		previousSibling.next = element;	} else {		element.prev = null;	}	siblings.push(element);	element.parent = parent || null;};DomHandler.prototype.onopentag = function(name, attribs){	var properties = {		type: name === "script" ? ElementType.Script : name === "style" ? ElementType.Style : ElementType.Tag,		name: name,		attribs: attribs,		children: []	};	var element = this._createDomElement(properties);	this._addDomElement(element);	this._tagStack.push(element);};DomHandler.prototype.ontext = function(data){	//the ignoreWhitespace is officially dropped, but for now,	//it's an alias for normalizeWhitespace	var normalize = this._options.normalizeWhitespace || this._options.ignoreWhitespace;	var lastTag;	if(!this._tagStack.length && this.dom.length && (lastTag = this.dom[this.dom.length-1]).type === ElementType.Text){		if(normalize){			lastTag.data = (lastTag.data + data).replace(re_whitespace, " ");		} else {			lastTag.data += data;		}	} else {		if(			this._tagStack.length &&			(lastTag = this._tagStack[this._tagStack.length - 1]) &&			(lastTag = lastTag.children[lastTag.children.length - 1]) &&			lastTag.type === ElementType.Text		){			if(normalize){				lastTag.data = (lastTag.data + data).replace(re_whitespace, " ");			} else {				lastTag.data += data;			}		} else {			if(normalize){				data = data.replace(re_whitespace, " ");			}			var element = this._createDomElement({				data: data,				type: ElementType.Text			});			this._addDomElement(element);		}	}};DomHandler.prototype.oncomment = function(data){	var lastTag = this._tagStack[this._tagStack.length - 1];	if(lastTag && lastTag.type === ElementType.Comment){		lastTag.data += data;		return;	}	var properties = {		data: data,		type: ElementType.Comment	};	var element = this._createDomElement(properties);	this._addDomElement(element);	this._tagStack.push(element);};DomHandler.prototype.oncdatastart = function(){	var properties = {		children: [{			data: "",			type: ElementType.Text		}],		type: ElementType.CDATA	};	var element = this._createDomElement(properties);	this._addDomElement(element);	this._tagStack.push(element);};DomHandler.prototype.oncommentend = DomHandler.prototype.oncdataend = function(){	this._tagStack.pop();};DomHandler.prototype.onprocessinginstruction = function(name, data){	var element = this._createDomElement({		name: name,		data: data,		type: ElementType.Directive	});	this._addDomElement(element);};module.exports = DomHandler;
 |