'use strict';
var DefaultTreeAdapter = require('../tree_adapters/default'),
Doctype = require('../common/doctype'), Utils = require('../common/utils'), HTML = require('../common/html');
//Aliases var $ = HTML.TAG_NAMES,
NS = HTML.NAMESPACES;
//Default serializer options var DEFAULT_OPTIONS = {
encodeHtmlEntities: true
};
//Escaping regexes var AMP_REGEX = /&/g,
NBSP_REGEX = /\u00a0/g, DOUBLE_QUOTE_REGEX = /"/g, LT_REGEX = /</g, GT_REGEX = />/g;
//Escape string function escapeString(str, attrMode) {
str = str .replace(AMP_REGEX, '&') .replace(NBSP_REGEX, ' '); if (attrMode) str = str.replace(DOUBLE_QUOTE_REGEX, '"'); else { str = str .replace(LT_REGEX, '<') .replace(GT_REGEX, '>'); } return str;
}
//Enquote doctype ID
//Serializer var Serializer = module.exports = function (treeAdapter, options) {
this.treeAdapter = treeAdapter || DefaultTreeAdapter; this.options = Utils.mergeOptions(DEFAULT_OPTIONS, options);
};
//API Serializer.prototype.serialize = function (node) {
this.html = ''; this._serializeChildNodes(node); return this.html;
};
//Internals Serializer.prototype._serializeChildNodes = function (parentNode) {
var childNodes = this.treeAdapter.getChildNodes(parentNode); if (childNodes) { for (var i = 0, cnLength = childNodes.length; i < cnLength; i++) { var currentNode = childNodes[i]; if (this.treeAdapter.isElementNode(currentNode)) this._serializeElement(currentNode); else if (this.treeAdapter.isTextNode(currentNode)) this._serializeTextNode(currentNode); else if (this.treeAdapter.isCommentNode(currentNode)) this._serializeCommentNode(currentNode); else if (this.treeAdapter.isDocumentTypeNode(currentNode)) this._serializeDocumentTypeNode(currentNode); } }
};
Serializer.prototype._serializeElement = function (node) {
var tn = this.treeAdapter.getTagName(node), ns = this.treeAdapter.getNamespaceURI(node); this.html += '<' + tn; this._serializeAttributes(node); this.html += '>'; if (tn !== $.AREA && tn !== $.BASE && tn !== $.BASEFONT && tn !== $.BGSOUND && tn !== $.BR && tn !== $.BR && tn !== $.COL && tn !== $.EMBED && tn !== $.FRAME && tn !== $.HR && tn !== $.IMG && tn !== $.INPUT && tn !== $.KEYGEN && tn !== $.LINK && tn !== $.MENUITEM && tn !== $.META && tn !== $.PARAM && tn !== $.SOURCE && tn !== $.TRACK && tn !== $.WBR) { if (tn === $.PRE || tn === $.TEXTAREA || tn === $.LISTING) { var firstChild = this.treeAdapter.getFirstChild(node); if (firstChild && this.treeAdapter.isTextNode(firstChild)) { var content = this.treeAdapter.getTextNodeContent(firstChild); if (content[0] === '\n') this.html += '\n'; } } var childNodesHolder = tn === $.TEMPLATE && ns === NS.HTML ? this.treeAdapter.getChildNodes(node)[0] : node; this._serializeChildNodes(childNodesHolder); this.html += '</' + tn + '>'; }
};
Serializer.prototype._serializeAttributes = function (node) {
var attrs = this.treeAdapter.getAttrList(node); for (var i = 0, attrsLength = attrs.length; i < attrsLength; i++) { var attr = attrs[i], value = this.options.encodeHtmlEntities ? escapeString(attr.value, true) : attr.value; this.html += ' '; if (!attr.namespace) this.html += attr.name; else if (attr.namespace === NS.XML) this.html += 'xml:' + attr.name; else if (attr.namespace === NS.XMLNS) { if (attr.name !== 'xmlns') this.html += 'xmlns:'; this.html += attr.name; } else if (attr.namespace === NS.XLINK) this.html += 'xlink:' + attr.name; else this.html += attr.namespace + ':' + attr.name; this.html += '="' + value + '"'; }
};
Serializer.prototype._serializeTextNode = function (node) {
var content = this.treeAdapter.getTextNodeContent(node), parent = this.treeAdapter.getParentNode(node), parentTn = void 0; if (parent && this.treeAdapter.isElementNode(parent)) parentTn = this.treeAdapter.getTagName(parent); if (parentTn === $.STYLE || parentTn === $.SCRIPT || parentTn === $.XMP || parentTn === $.IFRAME || parentTn === $.NOEMBED || parentTn === $.NOFRAMES || parentTn === $.PLAINTEXT || parentTn === $.NOSCRIPT) { this.html += content; } else this.html += this.options.encodeHtmlEntities ? escapeString(content, false) : content;
};
Serializer.prototype._serializeCommentNode = function (node) {
this.html += '<!--' + this.treeAdapter.getCommentNodeContent(node) + '-->';
};
Serializer.prototype._serializeDocumentTypeNode = function (node) {
var name = this.treeAdapter.getDocumentTypeNodeName(node), publicId = this.treeAdapter.getDocumentTypeNodePublicId(node), systemId = this.treeAdapter.getDocumentTypeNodeSystemId(node); this.html += '<' + Doctype.serializeContent(name, publicId, systemId) + '>';
};