diff options
Diffstat (limited to 'node_modules/domhandler/index.js')
-rw-r--r-- | node_modules/domhandler/index.js | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/node_modules/domhandler/index.js b/node_modules/domhandler/index.js new file mode 100644 index 000000000..68816a0d0 --- /dev/null +++ b/node_modules/domhandler/index.js @@ -0,0 +1,174 @@ +var ElementType = require("domelementtype");
+
+var re_whitespace = /\s+/g;
+
+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 = [];
+}
+
+//default options
+var defaultOpts = {
+ normalizeWhitespace: false //Replace all whitespace with single spaces
+};
+
+//Resets the handler back to starting state
+DomHandler.prototype.onreset = function(){
+ DomHandler.call(this, this._callback, this._options, this._elementCB);
+};
+
+//Signals the handler that parsing is done
+DomHandler.prototype.onend = function(){
+ if(this._done) return;
+ this._done = true;
+ 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(name){
+ //if(this._tagStack.pop().name !== name) this._handleCallback(Error("Tagname didn't match!"));
+ var elem = this._tagStack.pop();
+ if(this._elementCB) this._elementCB(elem);
+};
+
+DomHandler.prototype._addDomElement = function(element){
+ var lastTag = this._tagStack[this._tagStack.length - 1];
+
+ if(lastTag){
+ lastTag.children.push(element);
+ } else { //There aren't parent elements
+ this.dom.push(element);
+ }
+};
+
+DomHandler.prototype.onopentag = function(name, attribs){
+ var lastTag = this._tagStack[this._tagStack.length - 1];
+
+ var element = {
+ type: name === "script" ? ElementType.Script : name === "style" ? ElementType.Style : ElementType.Tag,
+ name: name,
+ attribs: attribs,
+ children: [],
+ prev: null,
+ next: null,
+ parent: lastTag || null
+ };
+
+ if(lastTag){
+ var idx = lastTag.children.length;
+ while(idx > 0){
+ if(ElementType.isTag(lastTag.children[--idx])){
+ element.prev = lastTag.children[idx];
+ lastTag.children[idx].next = element;
+ break;
+ }
+ }
+ lastTag.children.push(element);
+ } else {
+ this.dom.push(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, " ");
+ }
+
+ this._addDomElement({
+ data: data,
+ type: ElementType.Text
+ });
+ }
+ }
+};
+
+DomHandler.prototype.oncomment = function(data){
+ var lastTag = this._tagStack[this._tagStack.length - 1];
+
+ if(lastTag && lastTag.type === ElementType.Comment){
+ lastTag.data += data;
+ return;
+ }
+
+ var element = {
+ data: data,
+ type: ElementType.Comment
+ };
+
+ this._addDomElement(element);
+ this._tagStack.push(element);
+};
+
+DomHandler.prototype.oncdatastart = function(){
+ var element = {
+ children: [{
+ data: "",
+ type: ElementType.Text
+ }],
+ type: ElementType.CDATA
+ };
+
+ this._addDomElement(element);
+ this._tagStack.push(element);
+};
+
+DomHandler.prototype.oncommentend = DomHandler.prototype.oncdataend = function(){
+ this._tagStack.pop();
+};
+
+DomHandler.prototype.onprocessinginstruction = function(name, data){
+ this._addDomElement({
+ name: name,
+ data: data,
+ type: ElementType.Directive
+ });
+};
+
+module.exports = DomHandler;
\ No newline at end of file |