diff --git a/cjs/shared/parse-from-string.js b/cjs/shared/parse-from-string.js index 84a9fdf3..daa3544e 100644 --- a/cjs/shared/parse-from-string.js +++ b/cjs/shared/parse-from-string.js @@ -43,8 +43,10 @@ exports.isNotParsing = isNotParsing; const parseFromString = (document, isHTML, markupLanguage) => { const {active, registry} = document[CUSTOM_ELEMENTS]; + const foreignObjects = []; + const ownerSVGElements = []; + let node = document; - let ownerSVGElement = null; let parsingCData = false; notParsing = false; @@ -60,14 +62,17 @@ const parseFromString = (document, isHTML, markupLanguage) => { onopentag(name, attributes) { let create = true; if (isHTML) { - if (ownerSVGElement) { + const { length: slength } = ownerSVGElements; + const { length: flength } = foreignObjects; + if (slength && (!flength || (foreignObjects[flength - 1].ownerSVGElement !== ownerSVGElements[slength - 1]))) { node = append(node, document.createElementNS(SVG_NAMESPACE, name), active); - node.ownerSVGElement = ownerSVGElement; + node.ownerSVGElement = ownerSVGElements[slength - 1]; + if (name === 'foreignobject' || name === 'FOREIGNOBJECT') foreignObjects.push(node); create = false; } else if (name === 'svg' || name === 'SVG') { - ownerSVGElement = document.createElementNS(SVG_NAMESPACE, name); - node = append(node, ownerSVGElement, active); + node = append(node, document.createElementNS(SVG_NAMESPACE, name), active); + ownerSVGElements[slength] = node; create = false; } else if (active) { @@ -105,8 +110,10 @@ const parseFromString = (document, isHTML, markupLanguage) => { // onclosetag() { - if (isHTML && node === ownerSVGElement) - ownerSVGElement = null; + if (isHTML) { + pop(node, ownerSVGElements); + pop(node, foreignObjects); + } node = node.parentNode; } }, { @@ -123,3 +130,9 @@ const parseFromString = (document, isHTML, markupLanguage) => { return document; }; exports.parseFromString = parseFromString; + +const pop = (node, list) => { + let { length } = list; + if (length && node === list[length - 1]) + list.pop(); +}; diff --git a/esm/shared/parse-from-string.js b/esm/shared/parse-from-string.js index 08c6fe39..40ec134c 100644 --- a/esm/shared/parse-from-string.js +++ b/esm/shared/parse-from-string.js @@ -41,8 +41,10 @@ export const isNotParsing = () => notParsing; export const parseFromString = (document, isHTML, markupLanguage) => { const {active, registry} = document[CUSTOM_ELEMENTS]; + const foreignObjects = []; + const ownerSVGElements = []; + let node = document; - let ownerSVGElement = null; let parsingCData = false; notParsing = false; @@ -58,14 +60,17 @@ export const parseFromString = (document, isHTML, markupLanguage) => { onopentag(name, attributes) { let create = true; if (isHTML) { - if (ownerSVGElement) { + const { length: slength } = ownerSVGElements; + const { length: flength } = foreignObjects; + if (slength && (!flength || (foreignObjects[flength - 1].ownerSVGElement !== ownerSVGElements[slength - 1]))) { node = append(node, document.createElementNS(SVG_NAMESPACE, name), active); - node.ownerSVGElement = ownerSVGElement; + node.ownerSVGElement = ownerSVGElements[slength - 1]; + if (name === 'foreignobject' || name === 'FOREIGNOBJECT') foreignObjects.push(node); create = false; } else if (name === 'svg' || name === 'SVG') { - ownerSVGElement = document.createElementNS(SVG_NAMESPACE, name); - node = append(node, ownerSVGElement, active); + node = append(node, document.createElementNS(SVG_NAMESPACE, name), active); + ownerSVGElements[slength] = node; create = false; } else if (active) { @@ -103,8 +108,10 @@ export const parseFromString = (document, isHTML, markupLanguage) => { // onclosetag() { - if (isHTML && node === ownerSVGElement) - ownerSVGElement = null; + if (isHTML) { + pop(node, ownerSVGElements); + pop(node, foreignObjects); + } node = node.parentNode; } }, { @@ -120,3 +127,9 @@ export const parseFromString = (document, isHTML, markupLanguage) => { return document; }; + +const pop = (node, list) => { + let { length } = list; + if (length && node === list[length - 1]) + list.pop(); +}; diff --git a/test/svg/document.js b/test/svg/document.js index 0fc12c7d..7e2d8428 100644 --- a/test/svg/document.js +++ b/test/svg/document.js @@ -12,3 +12,10 @@ try { assert(false, true, 'facades should not be instantiable'); } catch (OK) {} + + +const {parseHTML} = global[Symbol.for('linkedom')]; + +const html = '
x
'; + +assert(parseHTML(html).document.toString().includes('
'), true, 'foreignObject'); diff --git a/worker.js b/worker.js index 2671c7f5..eb38ac5c 100644 --- a/worker.js +++ b/worker.js @@ -2272,8 +2272,10 @@ const attribute = (element, end, attribute, value, active) => { const parseFromString = (document, isHTML, markupLanguage) => { const {active, registry} = document[CUSTOM_ELEMENTS]; + const foreignObjects = []; + const ownerSVGElements = []; + let node = document; - let ownerSVGElement = null; let parsingCData = false; const content = new Parser({ @@ -2287,14 +2289,17 @@ const parseFromString = (document, isHTML, markupLanguage) => { onopentag(name, attributes) { let create = true; if (isHTML) { - if (ownerSVGElement) { + const { length: slength } = ownerSVGElements; + const { length: flength } = foreignObjects; + if (slength && (!flength || (foreignObjects[flength - 1].ownerSVGElement !== ownerSVGElements[slength - 1]))) { node = append$2(node, document.createElementNS(SVG_NAMESPACE, name), active); - node.ownerSVGElement = ownerSVGElement; + node.ownerSVGElement = ownerSVGElements[slength - 1]; + if (name === 'foreignobject' || name === 'FOREIGNOBJECT') foreignObjects.push(node); create = false; } else if (name === 'svg' || name === 'SVG') { - ownerSVGElement = document.createElementNS(SVG_NAMESPACE, name); - node = append$2(node, ownerSVGElement, active); + node = append$2(node, document.createElementNS(SVG_NAMESPACE, name), active); + ownerSVGElements[slength] = node; create = false; } else if (active) { @@ -2332,8 +2337,10 @@ const parseFromString = (document, isHTML, markupLanguage) => { // onclosetag() { - if (isHTML && node === ownerSVGElement) - ownerSVGElement = null; + if (isHTML) { + pop(node, ownerSVGElements); + pop(node, foreignObjects); + } node = node.parentNode; } }, { @@ -2348,6 +2355,12 @@ const parseFromString = (document, isHTML, markupLanguage) => { return document; }; +const pop = (node, list) => { + let { length } = list; + if (length && node === list[length - 1]) + list.pop(); +}; + const htmlClasses = new Map; const registerHTMLClass = (names, Class) => {