mirror of
https://github.com/marko-js/marko.git
synced 2025-12-08 19:26:05 +00:00
172 lines
3.9 KiB
JavaScript
172 lines
3.9 KiB
JavaScript
"use strict";
|
|
|
|
var runtimeHtmlHelpers = require("marko/runtime/html/helpers");
|
|
var escapeXml = runtimeHtmlHelpers.x;
|
|
var escapeXmlAttr = runtimeHtmlHelpers.xa;
|
|
var escapeScript = runtimeHtmlHelpers.xs;
|
|
var escapeStyle = runtimeHtmlHelpers.xc;
|
|
|
|
var openTagOnly = {};
|
|
|
|
[
|
|
"base",
|
|
"br",
|
|
"col",
|
|
"hr",
|
|
"embed",
|
|
"img",
|
|
"input",
|
|
"keygen",
|
|
"link",
|
|
"meta",
|
|
"param",
|
|
"source",
|
|
"track",
|
|
"wbr",
|
|
].forEach(function (tagName) {
|
|
openTagOnly[tagName] = true;
|
|
});
|
|
|
|
function getNodeValue(node) {
|
|
return node.___nodeValue || node.nodeValue;
|
|
}
|
|
|
|
function getFirstChild(node) {
|
|
return node.___firstChild || node.firstChild;
|
|
}
|
|
|
|
function getNextSibling(node) {
|
|
return node.___nextSibling || node.nextSibling;
|
|
}
|
|
|
|
function vdomToHTML(node, options) {
|
|
// NOTE: We don't use XMLSerializer because we need to sort the attributes to correctly compare output HTML strings
|
|
// BAD: return (new XMLSerializer()).serializeToString(node);
|
|
var html = "";
|
|
function serializeHelper(node) {
|
|
var nodeType = node.nodeType || node.___nodeType;
|
|
|
|
if (nodeType === 1) {
|
|
serializeElHelper(node);
|
|
} else if (nodeType === 3) {
|
|
serializeTextHelper(node);
|
|
} else if (nodeType === 8) {
|
|
serializeCommentHelper(node);
|
|
} else {
|
|
html += `INVALID NODE TYPE ${nodeType}\n`;
|
|
}
|
|
}
|
|
|
|
function serializeElHelper(el) {
|
|
var tagName = el.nodeName;
|
|
|
|
html += "<" + tagName;
|
|
|
|
var attributes = el.attributes;
|
|
var attributesArray = [];
|
|
var attrName;
|
|
|
|
if (typeof attributes.length === "number") {
|
|
for (var i = 0; i < attributes.length; i++) {
|
|
var attr = attributes[i];
|
|
attrName = attr.name;
|
|
|
|
if (attrName === "data-marko-const") {
|
|
continue;
|
|
}
|
|
attributesArray.push(
|
|
" " + attrName + '="' + escapeXmlAttr(attr.value) + '"',
|
|
);
|
|
}
|
|
} else {
|
|
for (attrName in attributes) {
|
|
if (attrName === "data-marko-const") {
|
|
continue;
|
|
}
|
|
|
|
var attrValue = attributes[attrName];
|
|
if (typeof attrValue !== "string") {
|
|
if (attrValue === true) {
|
|
attrValue = "";
|
|
} else if (!attrValue) {
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (attrName === "xlink:href") {
|
|
attrName = "http://www.w3.org/1999/xlink:href";
|
|
}
|
|
attributesArray.push(
|
|
" " + attrName + '="' + escapeXmlAttr(attrValue) + '"',
|
|
);
|
|
}
|
|
}
|
|
|
|
attributesArray.sort();
|
|
|
|
html += attributesArray.join("");
|
|
|
|
html += ">";
|
|
|
|
var hasEndTag = true;
|
|
if (tagName.toUpperCase() === "TEXTAREA") {
|
|
html += el.value;
|
|
} else {
|
|
var curChild = getFirstChild(el);
|
|
if (curChild) {
|
|
while (curChild) {
|
|
let nodeType = curChild.nodeType || curChild.___nodeType;
|
|
if (nodeType === 3) {
|
|
let tag = tagName.toUpperCase();
|
|
let escapeText =
|
|
tag === "SCRIPT"
|
|
? escapeScript
|
|
: tag === "STYLE"
|
|
? escapeStyle
|
|
: escapeXml;
|
|
serializeTextHelper(curChild, escapeText);
|
|
} else {
|
|
serializeHelper(curChild);
|
|
}
|
|
|
|
curChild = getNextSibling(curChild);
|
|
}
|
|
} else if (openTagOnly[tagName.toLowerCase()]) {
|
|
hasEndTag = false;
|
|
}
|
|
}
|
|
|
|
if (hasEndTag) {
|
|
html += "</" + tagName + ">";
|
|
}
|
|
}
|
|
|
|
function serializeTextHelper(node, escape) {
|
|
escape = escape || escapeXml;
|
|
html += escape(getNodeValue(node));
|
|
}
|
|
|
|
function serializeCommentHelper(node) {
|
|
html += "<!--" + getNodeValue(node) + "-->";
|
|
}
|
|
|
|
let nodeType = node.nodeType || node.___nodeType;
|
|
|
|
if (
|
|
nodeType === 11 /* DocumentFragment */ ||
|
|
(options && options.childrenOnly)
|
|
) {
|
|
var curChild = getFirstChild(node);
|
|
while (curChild) {
|
|
serializeHelper(curChild);
|
|
curChild = getNextSibling(curChild);
|
|
}
|
|
} else {
|
|
serializeHelper(node);
|
|
}
|
|
|
|
return html;
|
|
}
|
|
|
|
module.exports = vdomToHTML;
|