UNPKG

2.91 kBJavaScriptView Raw
1var ElementType = require("./ElementType.js");
2
3function DomHandler(callback, options){
4 this.dom = [];
5 this._done = false;
6 this._tagStack = [];
7 if(typeof callback === "object") this._options = callback;
8 else {
9 if(options) this._options = options; //otherwise, the prototype is used
10 if(callback) this._callback = callback;
11 }
12}
13
14//default options
15DomHandler.prototype._options = {
16 ignoreWhitespace: false //Keep whitespace-only text nodes
17};
18
19//Resets the handler back to starting state
20DomHandler.prototype.onreset = DomHandler;
21
22//Signals the handler that parsing is done
23DomHandler.prototype.onend = function(){
24 if(this._done) return;
25 this._done = true;
26 this._handleCallback(null);
27};
28
29DomHandler.prototype._handleCallback =
30DomHandler.prototype.onerror = function(error){
31 if(typeof this._callback === "function"){
32 this._callback(error, this.dom);
33 } else {
34 if(error) throw error;
35 }
36};
37
38DomHandler.prototype.onclosetag = function(name){
39 if(this._tagStack.pop().name !== name) this._handleCallback(Error("tagname didn't match!"));
40};
41
42DomHandler.prototype._addDomElement = function(element){
43 var lastChild,
44 lastTag = this._tagStack[this._tagStack.length - 1];
45
46 if(lastTag){ //There are parent elements
47 if(!lastTag.children){
48 lastTag.children = [element];
49 return;
50 }
51 lastChild = lastTag.children[lastTag.children.length - 1];
52 if(element.type === ElementType.Text && lastChild.type === ElementType.Text){
53 lastChild.data += element.data;
54 } else {
55 lastTag.children.push(element);
56 }
57 }
58 else {
59 this.dom.push(element);
60 }
61};
62
63DomHandler.prototype.onopentagname = function(name){
64 var element = {
65 type: name === "script" ? ElementType.Script : name === "style" ? ElementType.Style : ElementType.Tag,
66 name: name
67 };
68 this._addDomElement(element);
69 this._tagStack.push(element);
70};
71
72DomHandler.prototype.onattribute = function(name, value){
73 var element = this._tagStack[this._tagStack.length-1];
74 if(!("attribs" in element)) element.attribs = {};
75 element.attribs[name] = value;
76};
77
78DomHandler.prototype.ontext = function(data){
79 if(this._options.ignoreWhitespace && data.trim() === "") return;
80 this._addDomElement({
81 data: data,
82 type: ElementType.Text
83 });
84};
85
86DomHandler.prototype.oncomment = function(data){
87 var lastTag = this._tagStack[this._tagStack.length - 1];
88
89 if(lastTag && lastTag.type === ElementType.Comment){
90 lastTag.data += data;
91 return;
92 }
93
94 var element = {
95 data: data,
96 type: ElementType.Comment
97 };
98
99 if(!lastTag) this.dom.push(element);
100 else if(!lastTag.children) lastTag.children = [element];
101 else lastTag.children.push(element);
102
103 this._tagStack.push(element);
104};
105
106DomHandler.prototype.oncommentend = function(){
107 this._tagStack.pop();
108};
109
110DomHandler.prototype.onprocessinginstruction = function(name, data){
111 this._addDomElement({
112 name: name,
113 data: data,
114 type: ElementType.Directive
115 });
116};
117
118module.exports = DomHandler;
\No newline at end of file