|
@@ -18,21 +18,23 @@
|
|
|
* along with SingleFile. If not, see <http://www.gnu.org/licenses/>.
|
|
* along with SingleFile. If not, see <http://www.gnu.org/licenses/>.
|
|
|
*/
|
|
*/
|
|
|
|
|
|
|
|
-/* global Node */
|
|
|
|
|
-
|
|
|
|
|
this.serializer = this.serializer || (() => {
|
|
this.serializer = this.serializer || (() => {
|
|
|
|
|
|
|
|
const SELF_CLOSED_TAG_NAMES = ["area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param", "source", "track", "wbr"];
|
|
const SELF_CLOSED_TAG_NAMES = ["area", "base", "br", "col", "command", "embed", "hr", "img", "input", "keygen", "link", "meta", "param", "source", "track", "wbr"];
|
|
|
|
|
|
|
|
|
|
+ const Node_ELEMENT_NODE = 1;
|
|
|
|
|
+ const Node_TEXT_NODE = 3;
|
|
|
|
|
+ const Node_COMMENT_NODE = 8;
|
|
|
|
|
+
|
|
|
// see https://www.w3.org/TR/html5/syntax.html#optional-tags
|
|
// see https://www.w3.org/TR/html5/syntax.html#optional-tags
|
|
|
const OMITTED_START_TAGS = [
|
|
const OMITTED_START_TAGS = [
|
|
|
- { tagName: "head", accept: element => !element.childNodes.length || element.childNodes[0].nodeType == Node.ELEMENT_NODE },
|
|
|
|
|
|
|
+ { tagName: "head", accept: element => !element.childNodes.length || element.childNodes[0].nodeType == Node_ELEMENT_NODE },
|
|
|
{ tagName: "body", accept: element => !element.childNodes.length }
|
|
{ tagName: "body", accept: element => !element.childNodes.length }
|
|
|
];
|
|
];
|
|
|
const OMITTED_END_TAGS = [
|
|
const OMITTED_END_TAGS = [
|
|
|
- { tagName: "html", accept: next => !next || next.nodeType != Node.COMMENT_NODE },
|
|
|
|
|
- { tagName: "head", accept: next => !next || (next.nodeType != Node.COMMENT_NODE && (next.nodeType != Node.TEXT_NODE || !startsWithSpaceChar(next.textContent))) },
|
|
|
|
|
- { tagName: "body", accept: next => !next || next.nodeType != Node.COMMENT_NODE },
|
|
|
|
|
|
|
+ { tagName: "html", accept: next => !next || next.nodeType != Node_COMMENT_NODE },
|
|
|
|
|
+ { tagName: "head", accept: next => !next || (next.nodeType != Node_COMMENT_NODE && (next.nodeType != Node_TEXT_NODE || !startsWithSpaceChar(next.textContent))) },
|
|
|
|
|
+ { tagName: "body", accept: next => !next || next.nodeType != Node_COMMENT_NODE },
|
|
|
{ tagName: "li", accept: (next, element) => (!next && element.parentElement && (element.parentElement.tagName == "UL" || element.parentElement.tagName == "OL")) || (next && ["LI"].includes(next.tagName)) },
|
|
{ tagName: "li", accept: (next, element) => (!next && element.parentElement && (element.parentElement.tagName == "UL" || element.parentElement.tagName == "OL")) || (next && ["LI"].includes(next.tagName)) },
|
|
|
{ tagName: "dt", accept: next => !next || ["DT", "DD"].includes(next.tagName) },
|
|
{ tagName: "dt", accept: next => !next || ["DT", "DD"].includes(next.tagName) },
|
|
|
{ tagName: "p", accept: next => next && ["ADDRESS", "ARTICLE", "ASIDE", "BLOCKQUOTE", "DETAILS", "DIV", "DL", "FIELDSET", "FIGCAPTION", "FIGURE", "FOOTER", "FORM", "H1", "H2", "H3", "H4", "H5", "H6", "HEADER", "HR", "MAIN", "NAV", "OL", "P", "PRE", "SECTION", "TABLE", "UL"].includes(next.tagName) },
|
|
{ tagName: "p", accept: next => next && ["ADDRESS", "ARTICLE", "ASIDE", "BLOCKQUOTE", "DETAILS", "DIV", "DL", "FIELDSET", "FIGCAPTION", "FIGURE", "FOOTER", "FORM", "H1", "H2", "H3", "H4", "H5", "H6", "HEADER", "HR", "MAIN", "NAV", "OL", "P", "PRE", "SECTION", "TABLE", "UL"].includes(next.tagName) },
|
|
@@ -41,8 +43,8 @@ this.serializer = this.serializer || (() => {
|
|
|
{ tagName: "rp", accept: next => !next || ["RT", "RP"].includes(next.tagName) },
|
|
{ tagName: "rp", accept: next => !next || ["RT", "RP"].includes(next.tagName) },
|
|
|
{ tagName: "optgroup", accept: next => !next || ["OPTGROUP"].includes(next.tagName) },
|
|
{ tagName: "optgroup", accept: next => !next || ["OPTGROUP"].includes(next.tagName) },
|
|
|
{ tagName: "option", accept: next => !next || ["OPTION", "OPTGROUP"].includes(next.tagName) },
|
|
{ tagName: "option", accept: next => !next || ["OPTION", "OPTGROUP"].includes(next.tagName) },
|
|
|
- { tagName: "colgroup", accept: next => !next || (next.nodeType != Node.COMMENT_NODE && (next.nodeType != Node.TEXT_NODE || !startsWithSpaceChar(next.textContent))) },
|
|
|
|
|
- { tagName: "caption", accept: next => !next || (next.nodeType != Node.COMMENT_NODE && (next.nodeType != Node.TEXT_NODE || !startsWithSpaceChar(next.textContent))) },
|
|
|
|
|
|
|
+ { tagName: "colgroup", accept: next => !next || (next.nodeType != Node_COMMENT_NODE && (next.nodeType != Node_TEXT_NODE || !startsWithSpaceChar(next.textContent))) },
|
|
|
|
|
+ { tagName: "caption", accept: next => !next || (next.nodeType != Node_COMMENT_NODE && (next.nodeType != Node_TEXT_NODE || !startsWithSpaceChar(next.textContent))) },
|
|
|
{ tagName: "thead", accept: next => !next || ["TBODY", "TFOOT"].includes(next.tagName) },
|
|
{ tagName: "thead", accept: next => !next || ["TBODY", "TFOOT"].includes(next.tagName) },
|
|
|
{ tagName: "tbody", accept: next => !next || ["TBODY", "TFOOT"].includes(next.tagName) },
|
|
{ tagName: "tbody", accept: next => !next || ["TBODY", "TFOOT"].includes(next.tagName) },
|
|
|
{ tagName: "tfoot", accept: next => !next },
|
|
{ tagName: "tfoot", accept: next => !next },
|
|
@@ -73,11 +75,11 @@ this.serializer = this.serializer || (() => {
|
|
|
};
|
|
};
|
|
|
|
|
|
|
|
function serialize(node) {
|
|
function serialize(node) {
|
|
|
- if (node.nodeType == Node.TEXT_NODE) {
|
|
|
|
|
|
|
+ if (node.nodeType == Node_TEXT_NODE) {
|
|
|
return serializeTextNode(node);
|
|
return serializeTextNode(node);
|
|
|
- } else if (node.nodeType == Node.COMMENT_NODE) {
|
|
|
|
|
|
|
+ } else if (node.nodeType == Node_COMMENT_NODE) {
|
|
|
return serializeCommentNode(node);
|
|
return serializeCommentNode(node);
|
|
|
- } else if (node.nodeType == Node.ELEMENT_NODE) {
|
|
|
|
|
|
|
+ } else if (node.nodeType == Node_ELEMENT_NODE) {
|
|
|
return serializeElement(node);
|
|
return serializeElement(node);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -85,7 +87,7 @@ this.serializer = this.serializer || (() => {
|
|
|
function serializeTextNode(textNode) {
|
|
function serializeTextNode(textNode) {
|
|
|
const parentNode = textNode.parentNode;
|
|
const parentNode = textNode.parentNode;
|
|
|
let parentTagName;
|
|
let parentTagName;
|
|
|
- if (parentNode && parentNode.nodeType == Node.ELEMENT_NODE) {
|
|
|
|
|
|
|
+ if (parentNode && parentNode.nodeType == Node_ELEMENT_NODE) {
|
|
|
parentTagName = parentNode.tagName.toLowerCase();
|
|
parentTagName = parentNode.tagName.toLowerCase();
|
|
|
}
|
|
}
|
|
|
if (!parentTagName || TEXT_NODE_TAGS.includes(parentTagName)) {
|
|
if (!parentTagName || TEXT_NODE_TAGS.includes(parentTagName)) {
|