UNPKG

3.05 kBJavaScriptView Raw
1var ElementType = require("./ElementType.js");
2
3function DomHandler(callback, options){
4 this._options = typeof callback === "object" ? callback : options || defaultOpts;
5 this._callback = typeof callback === "object" ? null : callback;
6 this.dom = [];
7 this._done = false;
8 this._tagStack = [];
9}
10
11//default options
12var defaultOpts = {
13 ignoreWhitespace: false, //Keep whitespace-only text nodes
14 refParent: false //add a reference to the elements parent node
15};
16
17//Resets the handler back to starting state
18DomHandler.prototype.onreset = function(){
19 DomHandler.call(this, this._callback, this._options);
20};
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(this._options.refParent){
48 element.parent = lastTag;
49 }
50 if(!lastTag.children){
51 lastTag.children = [element];
52 return;
53 }
54 lastChild = lastTag.children[lastTag.children.length - 1];
55 if(element.type === ElementType.Text && lastChild.type === ElementType.Text){
56 lastChild.data += element.data;
57 } else {
58 lastTag.children.push(element);
59 }
60 }
61 else {
62 this.dom.push(element);
63 }
64};
65
66DomHandler.prototype.onopentagname = function(name){
67 var element = {
68 type: name === "script" ? ElementType.Script : name === "style" ? ElementType.Style : ElementType.Tag,
69 name: name
70 };
71 this._addDomElement(element);
72 this._tagStack.push(element);
73};
74
75DomHandler.prototype.onattribute = function(name, value){
76 var element = this._tagStack[this._tagStack.length-1];
77 if(!("attribs" in element)) element.attribs = {};
78 element.attribs[name] = value;
79};
80
81DomHandler.prototype.ontext = function(data){
82 if(this._options.ignoreWhitespace && data.trim() === "") return;
83 this._addDomElement({
84 data: data,
85 type: ElementType.Text
86 });
87};
88
89DomHandler.prototype.oncomment = function(data){
90 var lastTag = this._tagStack[this._tagStack.length - 1];
91
92 if(lastTag && lastTag.type === ElementType.Comment){
93 lastTag.data += data;
94 return;
95 }
96
97 var element = {
98 data: data,
99 type: ElementType.Comment
100 };
101
102 if(!lastTag) this.dom.push(element);
103 else if(!lastTag.children) lastTag.children = [element];
104 else lastTag.children.push(element);
105
106 this._tagStack.push(element);
107};
108
109DomHandler.prototype.oncommentend = function(){
110 this._tagStack.pop();
111};
112
113DomHandler.prototype.onprocessinginstruction = function(name, data){
114 this._addDomElement({
115 name: name,
116 data: data,
117 type: ElementType.Directive
118 });
119};
120
121module.exports = DomHandler;
\No newline at end of file