original
updated
{"ScriptPreparationCode":"var baseDOM = document.querySelector(\u0027.original\u0027);\r\nvar updateDOM = document.querySelector(\u0027.updated\u0027)\r\n\r\nvar DOMUpdates = [\r\n \u0027content updated\u0027,\r\n \u0027content \u003Cb\u003Eupdated\u003C/b\u003E\u0027,\r\n \u0027content \u003Cb\u003Eupdated\u003C/b\u003E more\u0027,\r\n \u0027\u003Cp\u003Econtent \u003Cb\u003Eupdated\u003C/b\u003E more\u003C/p\u003E\u0027,\r\n \u0060\u003Cdiv class=\u0022one\u0022\u003E\r\n \u003Cdiv\u003Econtent\u003Cb\u003Eupdated\u003C/b\u003E\u003C/div\u003E\r\n \u003Cspan\u003Emore\u003C/span\u003E\r\n \u003C/div\u003E\u0060,\r\n \u0060\u003Cdiv class=\u0022one\u0022\u003E\r\n \u003Cdiv\u003Econtent\u003C/div\u003E\r\n sass\u0026gt;as \u003Cb\u003Eupdated\u003C/b\u003Eaaa\r\n \u003Cspan\u003Emore\u003C/span\u003E\r\n \u003C/div\u003E\u0060,\r\n \u0060\u003Cdiv class=\u0022dos\u0022\u003E\r\n \u003Cdiv\u003Econtent\u003C/div\u003E\r\n sass\u0026gt;as \u003Cb\u003Eupdated\u003C/b\u003Eaaa\r\n \u003Cspan\u003Emore\u003C/span\u003E\r\n \u003C/div\u003E\u0060,\r\n \u0060\u003Cdiv class=\u0022dos\u0022\u003E\r\n \u003Cdiv\u003Econtent\u003C/div\u003E\r\n sass\u0026gt;as \u003Cb\u003Eupdated\u003C/b\u003Eaaa\r\n \u003Clist\u003Emore\u003C/list\u003E\r\n \u003C/div\u003E\u0060,\r\n \u0060\u003Cdiv class=\u0022dos\u0022\u003E\r\n \u003Cdiv\u003Econtent\u003C/div\u003E\r\n sass\u0026gt;as \u003Cb\u003Eupdated\u003C/b\u003Eaaa\r\n \u003Clist\u003E\r\n \u003Cp\u003E1\u003C/p\u003E\r\n \u003C/list\u003E\r\n \u003C/div\u003E\u0060,\r\n \u0060\u003Cdiv class=\u0022dos\u0022\u003E\r\n \u003Cdiv\u003Econtent\u003C/div\u003E\r\n sass\u0026gt;as \u003Cb\u003Eupdated\u003C/b\u003Eaaa\r\n \u003Clist\u003E\r\n \u003Cp\u003E1\u003C/p\u003E\r\n \u003Cp\u003E2\u003C/p\u003E\r\n \u003C/list\u003E\r\n \u003C/div\u003E\u0060,\r\n \u0060\u003Cdiv class=\u0022dos\u0022\u003E\r\n \u003Cdiv\u003Econtent\u003C/div\u003E\r\n sass\u0026gt;as \u003Cb\u003Eupdated\u003C/b\u003Eaaa\r\n \u003Clist\u003E\r\n \u003Cp\u003E1\u003C/p\u003E\r\n \u003Cp\u003E2\u003C/p\u003E\r\n \u003Cp\u003E3\u003C/p\u003E\r\n \u003C/list\u003E\r\n \u003C/div\u003E\u0060,\r\n];\r\n\r\nfunction cleanChildNodes(node) {\r\n for (var n = 0; n \u003C node.childNodes.length; n\u002B\u002B) {\r\n var child = node.childNodes[n];\r\n if\r\n (\r\n child.nodeType === 8\r\n ||\r\n (child.nodeType === 3 \u0026\u0026 !/\\S/.test(child.nodeValue))\r\n ) {\r\n node.removeChild(child);\r\n n--;\r\n }\r\n else if (child.nodeType === 1) {\r\n cleanChildNodes(child);\r\n }\r\n }\r\n}\r\n\r\nfunction _updateDomElement(oldDom, newDom) {\r\n cleanChildNodes(oldDom)\r\n cleanChildNodes(newDom)\r\n\r\n var newDomChildren = Array.from(newDom.childNodes);\r\n var oldDomChildren = Array.from(oldDom.childNodes);\r\n var isTextNode = (node) =\u003E node.nodeType === Node.TEXT_NODE;\r\n\r\n for (let iD = oldDomChildren.length - 1; iD \u003E= newDomChildren.length; iD--) {\r\n oldDom.removeChild(oldDomChildren[iD]);\r\n }\r\n\r\n newDomChildren.forEach((element, index) =\u003E {\r\n var oldElement = oldDomChildren[index];\r\n\r\n if (!oldElement) {\r\n oldDom.appendChild(element.cloneNode(true));\r\n }\r\n else if (\r\n isTextNode(element) \u0026\u0026 isTextNode(oldElement)\r\n \u0026\u0026 oldElement.nodeValue !== element.nodeValue\r\n ) {\r\n oldElement.nodeValue = element.nodeValue\r\n }\r\n else if (isTextNode(oldElement) \u0026\u0026 !isTextNode(element)) {\r\n oldDom.replaceChild(element.cloneNode(true), oldElement);\r\n }\r\n else if (element.nodeName !== oldElement.nodeName) {\r\n oldElement.outerHTML = element.outerHTML || \u0027\u0027\r\n }\r\n else if (element.outerHTML !== oldElement.outerHTML) {\r\n Array.from(element.attributes || []).forEach(attr =\u003E {\r\n const oldAttr = oldElement.getAttribute(attr.name);\r\n if (!oldAttr || oldAttr !== attr.value) {\r\n oldElement.setAttribute(attr.name, attr.value);\r\n }\r\n })\r\n if (oldElement.attributes.length \u003E element.attributes.length) {\r\n Array.from(oldElement.attributes || []).forEach(attr =\u003E {\r\n if (!element.attributes[attr.name]) {\r\n oldElement.removeAttribute(attr.name);\r\n }\r\n })\r\n }\r\n if (element.value !== oldElement.value) {\r\n console.log(\u0022Value \u0022, element.className);\r\n oldElement.value = element.value;\r\n }\r\n if (element.childNodes.length) {\r\n _updateDomElement(oldElement, element)\r\n }\r\n else if (element.innerText != oldElement.innerText) {\r\n console.log(\u0022innerText \u0022, element.className);\r\n oldElement.innerText = element.innerText;\r\n }\r\n }\r\n })\r\n\r\n //Security check\r\n if (newDom.innerHTML.replace(/\\s\u002B/g, \u0027\u0027) !== oldDom.innerHTML.replace(/\\s\u002B/g, \u0027\u0027)) {\r\n console.warn(\u0060\r\n Force innerHTML substitution :(\r\n OLD: ${oldDom.innerHTML.replace(/\\s\u002B/g, \u0027\u0027)}\r\n NEW: ${newDom.innerHTML.replace(/\\s\u002B/g, \u0027\u0027)}\r\n \u0060);\r\n oldDom.innerHTML = newDom.innerHTML;\r\n }\r\n }\r\n\r\nfunction _updateDomElementChildren(oldDom, newDom) {\r\n const newDomChildren = Array.from(newDom.children);\r\n const oldDomChildren = Array.from(oldDom.children);\r\n const isTextNode = (node) =\u003E node.nodeType === Node.TEXT_NODE;\r\n\r\n for (let iD = oldDomChildren.length - 1; iD \u003E= newDomChildren.length; iD--) {\r\n oldDom.removeChild(oldDomChildren[iD]);\r\n }\r\n\r\n newDomChildren.forEach((element, index) =\u003E {\r\n const oldElement = oldDomChildren[index];\r\n\r\n if (!oldElement) {\r\n oldDom.appendChild(element.cloneNode(true));\r\n }\r\n else if (\r\n isTextNode(element) \u0026\u0026 isTextNode(oldElement)\r\n \u0026\u0026 oldElement.nodeValue !== element.nodeValue\r\n ) {\r\n oldElement.nodeValue = element.nodeValue\r\n }\r\n else if (isTextNode(oldElement) \u0026\u0026 !isTextNode(element)) {\r\n oldDom.replaceChild(element.cloneNode(true), oldElement);\r\n }\r\n else if (element.nodeName !== oldElement.nodeName) {\r\n oldElement.outerHTML = element.outerHTML || \u0027\u0027\r\n console.warn(\u0060different nodeName ${oldElement.nodeName} != ${element.nodeName}\u0060);\r\n }\r\n else if (element.outerHTML !== oldElement.outerHTML) {\r\n Array.from(element.attributes || []).forEach(attr =\u003E {\r\n const oldAttr = oldElement.getAttribute(attr.name);\r\n if (!oldAttr || oldAttr !== attr.value) {\r\n oldElement.setAttribute(attr.name, attr.value);\r\n }\r\n })\r\n if (oldElement.attributes.length \u003E element.attributes.length) {\r\n Array.from(oldElement.attributes || []).forEach(attr =\u003E {\r\n if (!element.attributes[attr.name]) {\r\n oldElement.removeAttribute(attr.name);\r\n }\r\n })\r\n }\r\n if (element.value !== oldElement.value) {\r\n oldElement.value = element.value;\r\n }\r\n if (element.children.length) {\r\n _updateDomElementChildren(oldElement, element)\r\n }\r\n \telse if(element.textContent != oldElement.textContent){\r\n \toldElement.textContent = element.textContent\r\n }\r\n }\r\n })\r\n\r\n //Security check\r\n if (newDom.innerHTML.replace(/\\s\u002B/g, \u0027\u0027) !== oldDom.innerHTML.replace(/\\s\u002B/g, \u0027\u0027)) {\r\n console.warn(\u0060\r\n Force innerHTML substitution :(\r\n OLD: ${oldDom.innerHTML.replace(/\\s\u002B/g, \u0027\u0027)}\r\n NEW: ${newDom.innerHTML.replace(/\\s\u002B/g, \u0027\u0027)}\r\n \u0060);\r\n oldDom.innerHTML = newDom.innerHTML;\r\n }\r\n }\r\n","TestCases":[{"Name":"innerHTML ","Code":"DOMUpdates.forEach(update =\u003E {\r\n updateDOM.innerHTML = update\r\n baseDOM.innerHTML = updateDOM.innerHTML\r\n})","IsDeferred":false},{"Name":"updateDOM","Code":"DOMUpdates.forEach(update =\u003E {\r\n updateDOM.innerHTML = update\r\n _updateDomElement(baseDOM, updateDOM)\r\n})","IsDeferred":false},{"Name":"updateDOMChildren","Code":"DOMUpdates.forEach(update =\u003E {\r\n updateDOM.innerHTML = update\r\n _updateDomElementChildren(baseDOM, updateDOM)\r\n})","IsDeferred":false}]}