can-simple-dom
Version:
A simple JS DOM.
86 lines (68 loc) • 2.07 kB
JavaScript
var he = require('he');
function HTMLParser(tokenize, document, voidMap) {
this.tokenize = tokenize;
this.document = document;
this.voidMap = voidMap;
this.parentStack = [];
}
HTMLParser.prototype.isVoid = function(element) {
return this.voidMap[element.nodeName] === true;
};
HTMLParser.prototype.pushElement = function(token) {
var el = this.document.createElement(token.tagName);
for (var i=0;i<token.attributes.length;i++) {
var attr = token.attributes[i];
if(attr[0] !== 'href' && attr[0] !== 'src') {
attr[1] = he.encode(attr[1]);
}
el.setAttribute(attr[0], attr[1]);
}
if (this.isVoid(el) || token.selfClosing) {
return this.appendChild(el);
}
this.parentStack.push(el);
};
HTMLParser.prototype.popElement = function(token) {
var el = this.parentStack.pop();
if (el.nodeName !== token.tagName.toUpperCase()) {
throw new Error('unbalanced tag');
}
this.appendChild(el);
};
HTMLParser.prototype.appendText = function(token) {
var text = this.document.createTextNode(token.chars);
this.appendChild(text);
};
HTMLParser.prototype.appendComment = function(token) {
var comment = this.document.createComment(token.chars);
this.appendChild(comment);
};
HTMLParser.prototype.appendChild = function(node) {
var parentNode = this.parentStack[this.parentStack.length-1];
parentNode.appendChild(node);
};
HTMLParser.prototype.parse = function(html/*, context*/) {
// TODO use context for namespaceURI issues
var fragment = this.document.createDocumentFragment();
this.parentStack.push(fragment);
var tokens = this.tokenize(html);
for (var i=0, l=tokens.length; i<l; i++) {
var token = tokens[i];
switch (token.type) {
case 'StartTag':
this.pushElement(token);
break;
case 'EndTag':
this.popElement(token);
break;
case 'Chars':
this.appendText(token);
break;
case 'Comment':
this.appendComment(token);
break;
}
}
return this.parentStack.pop();
};
module.exports = HTMLParser;