Skip to content

Instantly share code, notes, and snippets.

@fleon
Last active August 29, 2015 14:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fleon/5de37b0fedcbe9409083 to your computer and use it in GitHub Desktop.
Save fleon/5de37b0fedcbe9409083 to your computer and use it in GitHub Desktop.
DOMFootprint
/**
* Creates a new DOMFootprint for the given HTML node.
* @param {Node} element The HTML node to create a footprint for.
*/
function DOMFootprint(element) {
this.element = element;
this.capture();
}
DOMFootprint.prototype = {
/**
* Captures the footprint of the DOM element and its descendants.
*/
capture: function () {
this.nodeName = this.element.nodeName;
this.nodeType = this.element.nodeType;
// element node
if (this.element.nodeType === 1) {
// capture all children and attributes
this.children = [];
this.attributes = {};
for (var i = 0, il = this.element.childNodes.length; i < il; i++) {
this.children[i] = new DOMFootprint(this.element.childNodes[i]);
}
for (var j = 0, jl = this.element.attributes.length; j < jl; j++) {
this.attributes[j] = this.element.attributes[j].name;
this.attributes[this.attributes[j]] = this.element.attributes[j].value;
this.attributes.length = this.element.attributes.length;
}
}
// text node or comment node
else if (this.element.nodeType === 3 || this.element.nodeType === 8) {
// capture textContent
this.textContent = this.element.textContent;
}
return this;
},
/**
* Restores the element to the state of its previously captured footprint.
*/
restore: function () {
// element node
if (this.nodeType === 1) {
// remove all existing children
while (this.element.childNodes.length) {
this.element.removeChild(this.element.childNodes[0]);
}
// update all attributes
var attributesToRemove = [];
for (var i = this.element.attributes.length; i--;) {
if (this.attributes.hasOwnProperty(this.element.attributes[i].name)) {
if (this.element.attributes[i].value === this.attributes[this.attributes[i]]) {
continue;
}
this.element.setAttribute(this.attributes[i], this.attributes[this.attributes[i]]);
} else {
attributesToRemove.push(this.element.attributes[i].name);
}
}
for (var attribute = attributesToRemove.pop(); attribute;) {
this.element.removeAttribute(attribute);
}
// append and restore the footprints of all old children
for (var j = 0, jl = this.children.length; j < jl; j++) {
this.element.appendChild(this.children[j].element);
this.children[j].restore();
}
}
// text node or comment node
else if (this.element.nodeType === 3 || this.element.nodeType === 8) {
this.element.textContent = this.textContent;
}
return this;
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment