| module.exports = serializeNode | |
| var voidElements = ["area","base","br","col","embed","hr","img","input","keygen","link","menuitem","meta","param","source","track","wbr"]; | |
| function serializeNode(node) { | |
| switch (node.nodeType) { | |
| case 3: | |
| return escapeText(node.data) | |
| case 8: | |
| return "<!--" + node.data + "-->" | |
| default: | |
| return serializeElement(node) | |
| } | |
| } | |
| function serializeElement(elem) { | |
| var strings = [] | |
| var tagname = elem.tagName | |
| if (elem.namespaceURI === "http://www.w3.org/1999/xhtml") { | |
| tagname = tagname.toLowerCase() | |
| } | |
| strings.push("<" + tagname + properties(elem) + datasetify(elem)) | |
| if (voidElements.indexOf(tagname) > -1) { | |
| strings.push(" />") | |
| } else { | |
| strings.push(">") | |
| if (elem.childNodes.length) { | |
| strings.push.apply(strings, elem.childNodes.map(serializeNode)) | |
| } else if (elem.textContent || elem.innerText) { | |
| strings.push(escapeText(elem.textContent || elem.innerText)) | |
| } else if (elem.innerHTML) { | |
| strings.push(elem.innerHTML) | |
| } | |
| strings.push("</" + tagname + ">") | |
| } | |
| return strings.join("") | |
| } | |
| function isProperty(elem, key) { | |
| var type = typeof elem[key] | |
| if (key === "style" && Object.keys(elem.style).length > 0) { | |
| return true | |
| } | |
| return elem.hasOwnProperty(key) && | |
| (type === "string" || type === "boolean" || type === "number") && | |
| key !== "nodeName" && key !== "className" && key !== "tagName" && | |
| key !== "textContent" && key !== "innerText" && key !== "namespaceURI" && key !== "innerHTML" | |
| } | |
| function stylify(styles) { | |
| if (typeof styles === 'string') return styles | |
| var attr = "" | |
| Object.keys(styles).forEach(function (key) { | |
| var value = styles[key] | |
| key = key.replace(/[A-Z]/g, function(c) { | |
| return "-" + c.toLowerCase(); | |
| }) | |
| attr += key + ":" + value + ";" | |
| }) | |
| return attr | |
| } | |
| function datasetify(elem) { | |
| var ds = elem.dataset | |
| var props = [] | |
| for (var key in ds) { | |
| props.push({ name: "data-" + key, value: ds[key] }) | |
| } | |
| return props.length ? stringify(props) : "" | |
| } | |
| function stringify(list) { | |
| var attributes = [] | |
| list.forEach(function (tuple) { | |
| var name = tuple.name | |
| var value = tuple.value | |
| if (name === "style") { | |
| value = stylify(value) | |
| } | |
| attributes.push(name + "=" + "\"" + escapeAttributeValue(value) + "\"") | |
| }) | |
| return attributes.length ? " " + attributes.join(" ") : "" | |
| } | |
| function properties(elem) { | |
| var props = [] | |
| for (var key in elem) { | |
| if (isProperty(elem, key)) { | |
| props.push({ name: key, value: elem[key] }) | |
| } | |
| } | |
| for (var ns in elem._attributes) { | |
| for (var attribute in elem._attributes[ns]) { | |
| var prop = elem._attributes[ns][attribute] | |
| var name = (prop.prefix ? prop.prefix + ":" : "") + attribute | |
| props.push({ name: name, value: prop.value }) | |
| } | |
| } | |
| if (elem.className) { | |
| props.push({ name: "class", value: elem.className }) | |
| } | |
| return props.length ? stringify(props) : "" | |
| } | |
| function escapeText(s) { | |
| var str = ''; | |
| if (typeof(s) === 'string') { | |
| str = s; | |
| } else if (s) { | |
| str = s.toString(); | |
| } | |
| return str | |
| .replace(/&/g, "&") | |
| .replace(/</g, "<") | |
| .replace(/>/g, ">") | |
| } | |
| function escapeAttributeValue(str) { | |
| return escapeText(str).replace(/"/g, """) | |
| } | |