Skip to content

Commit

Permalink
Add MutationEvents class and related functions
Browse files Browse the repository at this point in the history
  • Loading branch information
mfreed7 committed Jul 29, 2024
1 parent e235ba5 commit f86c86f
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 0 deletions.
28 changes: 28 additions & 0 deletions src/mutation_events.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
return;
}
window.mutationEventsPolyfillInstalled = true;
// If the feature is already natively supported, use it instead.
if ("MutationEvent" in window && !window.mutationEventsUsePolyfillAlways) {
return;
}

const mutationEvents = new Set([
'DOMCharacterDataModified',
Expand Down Expand Up @@ -184,5 +188,29 @@
originalRemoveEventListener.apply(this, arguments);
};

// This makes things like MutationEvent.MODIFICATION not throw.
window.MutationEvent = class extends CustomEvent {
constructor(type,dict) {
if (type !== "MagicString") {
throw("Illegal constructor");
}
super('',dict);
}
initMutationEvent(...args) {
this.initCustomEvent(...args);
}
static MODIFICATION = 1;
static ADDITION = 2;
static REMOVAL = 3;
}
window.initMutationEvent = () => new MutationEvent();
const originalCreateEvent = Document.prototype.createEvent;
Document.prototype.createEvent = function(type,...args) {
if (type === "MutationEvent") {
return new MutationEvent("MagicString");
}
return originalCreateEvent.call(this,type,...args);
};

console.log(`Mutation Events polyfill installed (native feature: ${("MutationEvent" in window) ? "supported" : "not present"}).`);
})();
34 changes: 34 additions & 0 deletions test/test.html
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ <h3>Detailed event logs:</h3>
usePolyfill.disabled = true;
const loadPolyfill = usePolyfill.checked;
if (loadPolyfill) {
// This will tell the polyfill to load even if natively supported:
window.mutationEventsUsePolyfillAlways = true;
const polyfill = document.createElement('script');
polyfill.src = "../src/mutation_events.js";
const loaded = new Promise(resolve => polyfill.onload = resolve);
Expand Down Expand Up @@ -458,6 +460,38 @@ <h3>Detailed event logs:</h3>
[0, 'parent'],
],
() => div.setAttribute('foo','bar'));

// Manual test of MutationEvent interface
function testInterface(fn,desc) {
try {
result = fn();
} catch {
result = false;
}
addResult(result,desc);
}
testInterface(() => {return "MutationEvent" in window},"MutationEvent exists");
testInterface(() => {
try {
new MutationEvent('DOMNodeRemoved');
return false; // Explicit constructor should throw
} catch {
return true;
}
},"MutationEvent cannot be constructed");
testInterface(() => {return MutationEvent.MODIFICATION === 1},"MutationEvent.MODIFICATION exists");
testInterface(() => {return MutationEvent.ADDITION === 2},"MutationEvent.ADDITION exists");
testInterface(() => {return MutationEvent.REMOVAL === 3},"MutationEvent.REMOVAL exists");
testInterface(() => {return document.createEvent("MutationEvent") instanceof MutationEvent},"document.createEvent");
testInterface(() => {return document.createEvent("Event") instanceof Event},"document.createEvent doesn't break stuff");
testInterface(() => {return document.createEvent("MouseEvent") instanceof MouseEvent},"document.createEvent doesn't break stuff");
testInterface(() => {return document.createEvent("MouseEvents") instanceof MouseEvent},"document.createEvent doesn't break stuff");
testInterface(() => {return document.createEvent("MutationEvent").type === ""},"document.createEvent returns empty type");
testInterface(() => {
const evt = document.createEvent("MutationEvent");
evt.initMutationEvent('DOMNodeRemoved',true,true,null,"foo","bar","baz",1);
return evt.type === 'DOMNodeRemoved';
},"MutationEvent.initMutationEvent() exists");
}

</script>

0 comments on commit f86c86f

Please sign in to comment.