var HTML5 = require('../html5'); var events = require('events'); function error(msg) { return {type: 'SerializeError', data: msg}; } function empty_tag(node) { if(node.hasChildNodes()) return error(_("Void element has children")); return {type: 'EmptyTag', name: node.tagName, data: node.attributes, namespace: node.namespace}; } function start_tag(node) { return {type: 'StartTag', name: node.tagName, data: node.attributes, namespace: node.namespace}; } function end_tag(node) { return {type: 'EndTag', name: node.tagName, namespace: node.namespace }; } function text(data, target) { if(m = new RegExp("^[" + HTML5.SPACE_CHARACTERS + "]+").exec(data)) { target.emit('token', {type: 'SpaceCharacters', data: m[0]}); data = data.slice(m[0].length, data.length); if(data.length == 0) return; } if(m = new RegExp("["+HTML5.SPACE_CHARACTERS + "]+$").exec(data)) { target.emit('token', {type: 'Characters', data: data.slice(0, m.length)}); target.emit('token', {type: 'SpaceCharacters', data: data.slice(m.index, data.length)}); } else { target.emit('token', {type: 'Characters', data: data}); } } function comment(data) { return {type: 'Comment', data: data}; } function doctype(node) { return {type: 'Doctype', name: node.nodeName, publicId: node.publicId, systemId: node.systemId, correct: node.correct}; } function unknown(node) { return error(_("unknown node: ")+ JSON.stringify(node)); } function _(str) { return str; } HTML5.TreeWalker = function(document, dest) { if(dest instanceof Function) this.addListener('token', dest); walk(document, this); }; function walk(node, dest) { switch(node.nodeType) { case node.DOCUMENT_FRAGMENT_NODE: case node.DOCUMENT_NODE: for(var child = 0; child < node.childNodes.length; ++child) { walk(node.childNodes[child], dest); } break; case node.ELEMENT_NODE: if(HTML5.VOID_ELEMENTS.indexOf(node.tagName.toLowerCase()) != -1) { dest.emit('token', empty_tag(node)); } else { dest.emit('token', start_tag(node)); for(var child = 0; child < node.childNodes.length; ++child) { walk(node.childNodes[child], dest); } dest.emit('token', end_tag(node)); } break; case node.TEXT_NODE: text(node.nodeValue, dest); break; case node.COMMENT_NODE: dest.emit('token', comment(node.nodeValue)); break; case node.DOCUMENT_TYPE_NODE: dest.emit('token', doctype(node)); break; default: dest.emit('token', unknown(node)); } } HTML5.TreeWalker.prototype = new events.EventEmitter;