-
Notifications
You must be signed in to change notification settings - Fork 1
/
BadDOM.js
68 lines (67 loc) · 3.31 KB
/
BadDOM.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
window.vDiff = (target, source) => {
const worker = {
settings: {
original: target,
},
replace(nTarget, nSource = target) {
const v = new DOMParser().parseFromString(source, 'text/html').body.childNodes
const vHTML = v[0];
if (vHTML.nodeName !== target.nodeName) {
target.parentElement.replaceChild(vHTML, target);
return;
}
this.iterate(target, vHTML);
},
iterate(targetNode, sourceNode, tOriginal) {
if (targetNode || sourceNode) {
this.checkAdditions(targetNode, sourceNode, tOriginal);
if (targetNode && sourceNode && targetNode.nodeName !== sourceNode.nodeName) {
this.checkNodeName(targetNode, sourceNode);
} else if (targetNode && sourceNode && targetNode.nodeName === sourceNode.nodeName) {
this.checkTextContent(targetNode, sourceNode);
targetNode.nodeType !== 3 && target.nodeType !== 8 && this.checkAttributes(targetNode, sourceNode);
}
}
if (targetNode && sourceNode) {
if (targetNode.childNodes && sourceNode.childNodes) {
this.settings.lengthDifferentiator = [...target.childNodes, ...sourceNode.childNodes];
} else {
this.settings.lengthDifferentiator = null;
}
(this.settings.lengthDifferentiator || []).forEach((node, idx) => {
this.settings.lengthDifferentiator &&
this.iterate(targetNode.childNodes[idx], sourceNode.childNodes[idx], targetNode, sourceNode);
});
}
},
checkNodeName(targetNode, sourceNode) {
const n = sourceNode.cloneNode(true);
targetNode.parentElement.replaceChild(n, targetNode);
},
checkAttributes(targetNode, sourceNode) {
const attributes = targetNode.attributes || [];
const filteredAttrs = Object.keys(attributes).map((n) => attributes[n]);
const attributesNew = sourceNode.attributes || [];
const filteredAttrsNew = Object.keys(attributesNew).map((n) => attributesNew[n]);
filteredAttrs.forEach(o => sourceNode.getAttribute(o.name) !== null ?
targetNode.setAttribute(o.name, sourceNode.getAttribute(o.name)) :
targetNode.removeAttribute(o.name));
filteredAttrsNew.forEach(a => targetNode.getAttribute(a.name) !== sourceNode.getAttribute(a.name) &&
targetNode.setAttribute(a.name, sourceNode.getAttribute(a.name)));
},
checkTextContent(targetNode, sourceNode) {
if (targetNode.nodeValue !== sourceNode.nodeValue) {
targetNode.textContent = sourceNode.textContent;
}
},
checkAdditions(targetNode, sourceNode, tParent = this.settings.original) {
if (sourceNode && targetNode === undefined) {
const newNode = sourceNode.cloneNode(true);
tParent.nodeType !== 3 && tParent.nodeType !== 8 && tParent.appendChild(newNode);
} else if (targetNode && sourceNode === undefined) {
targetNode.parentElement.removeChild(targetNode);
}
},
};
Object.create(worker).replace(target, source);
};