UNPKG

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