(function(window, Object, HTMLElement){
if (HTMLElement in window) return;
var
timer = 0,
clearTimeout = window.clearTimeout,
setTimeout = window.setTimeout,
ElementPrototype = Element.prototype,
gOPD = Object.getOwnPropertyDescriptor,
defineProperty = Object.defineProperty,
notifyChanges = function () {
document.dispatchEvent(new CustomEvent('readystatechange'));
},
scheduleNotification = function (target, name) {
clearTimeout(timer);
timer = setTimeout(notifyChanges, 10);
},
wrapSetter = function (name) {
var
descriptor = gOPD(ElementPrototype, name),
// why not just overwrite the setter?
// BECAUSE IE8, THAT'S WHY!
substitute = {
configurable: descriptor.configurable,
enumerable: descriptor.enumerable,
get: function () {
return descriptor.get.call(this);
},
set: function asd(value) {
// caveat, this slows down innerHTML
// "just a tiny bit" ...
delete ElementPrototype[name];
// AHHAHAHAHAAHAHAHAAHAHAHHAHAHHAHAHHAHHAHAHHAHHAHAH
this[name] = value;
// needed for the next call
defineProperty(ElementPrototype, name, substitute);
scheduleNotification(this);
}
}
;
defineProperty(ElementPrototype, name, substitute);
},
wrapMethod = function (name) {
var
descriptor = gOPD(ElementPrototype, name),
value = descriptor.value
;
descriptor.value = function () {
var result = value.apply(this, arguments);
scheduleNotification(this);
return result;
};
defineProperty(
ElementPrototype,
name,
descriptor
);
}
;
wrapSetter('innerHTML');
wrapSetter('innerText');
wrapSetter('outerHTML');
wrapSetter('outerText');
wrapSetter('textContent');
wrapMethod('appendChild');
wrapMethod('applyElement');
wrapMethod('insertAdjacentElement');
wrapMethod('insertAdjacentHTML');
wrapMethod('insertAdjacentText');
wrapMethod('insertBefore');
wrapMethod('insertData');
wrapMethod('replaceAdjacentText');
wrapMethod('replaceChild');
wrapMethod('removeChild');
window[HTMLElement] = Element;
}(window, Object, 'HTMLElement'));