'use strict'; var Tokenizer = require('../tokenization/tokenizer'), TokenizerProxy = require('./tokenizer_proxy'), Utils = require('../common/utils'); //Default options var DEFAULT_OPTIONS = { decodeHtmlEntities: true, locationInfo: false }; //Skipping handler function skip() { //NOTE: do nothing =) } //SimpleApiParser var SimpleApiParser = module.exports = function (handlers, options) { this.options = Utils.mergeOptions(DEFAULT_OPTIONS, options); this.handlers = { doctype: this._wrapHandler(handlers.doctype), startTag: this._wrapHandler(handlers.startTag), endTag: this._wrapHandler(handlers.endTag), text: this._wrapHandler(handlers.text), comment: this._wrapHandler(handlers.comment) }; }; SimpleApiParser.prototype._wrapHandler = function (handler) { var parser = this; handler = handler || skip; if (this.options.locationInfo) { return function () { var args = Array.prototype.slice.call(arguments); args.push(parser.currentTokenLocation); handler.apply(handler, args); }; } return handler; }; //API SimpleApiParser.prototype.parse = function (html) { var token = null; this._reset(html); do { token = this.tokenizerProxy.getNextToken(); if (token.type === Tokenizer.CHARACTER_TOKEN || token.type === Tokenizer.WHITESPACE_CHARACTER_TOKEN || token.type === Tokenizer.NULL_CHARACTER_TOKEN) { if (this.options.locationInfo) { if (this.pendingText === null) this.currentTokenLocation = token.location; else this.currentTokenLocation.end = token.location.end; } this.pendingText = (this.pendingText || '') + token.chars; } else { this._emitPendingText(); this._handleToken(token); } } while (token.type !== Tokenizer.EOF_TOKEN); }; //Internals SimpleApiParser.prototype._handleToken = function (token) { if (this.options.locationInfo) this.currentTokenLocation = token.location; if (token.type === Tokenizer.START_TAG_TOKEN) this.handlers.startTag(token.tagName, token.attrs, token.selfClosing); else if (token.type === Tokenizer.END_TAG_TOKEN) this.handlers.endTag(token.tagName); else if (token.type === Tokenizer.COMMENT_TOKEN) this.handlers.comment(token.data); else if (token.type === Tokenizer.DOCTYPE_TOKEN) this.handlers.doctype(token.name, token.publicId, token.systemId); }; SimpleApiParser.prototype._reset = function (html) { this.tokenizerProxy = new TokenizerProxy(html, this.options); this.pendingText = null; this.currentTokenLocation = null; }; SimpleApiParser.prototype._emitPendingText = function () { if (this.pendingText !== null) { this.handlers.text(this.pendingText); this.pendingText = null; } };