Last active
June 2, 2020 00:55
-
-
Save mwrouse/8e6bff2ed20851e2faf8e8f5398097a2 to your computer and use it in GitHub Desktop.
JavaScript addEventListener and removeEventListener polyfill for IE6+
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Event polyfill | |
* Michael Rouse | |
* December 2016 | |
*/ | |
function polyfillEvent(e) { | |
e = e || window.event; | |
e.eventPhase = e.eventPhase || 0; | |
e.defaultPrevented = e.defaultPrevented || false; | |
e.bubbles = e.bubbles || true; | |
e.cancelable = e.cancelable || true; | |
e.view = e.view || undefined; | |
e.preventDefault = e.preventDefault || function () { e.returnValue = false; e.defaultPrevented = true; } | |
e.stopPropagation = e.stopPropagation || function () { e.cancelBubble = true } | |
return e; | |
} | |
/** | |
* addEventListener and removeEventListener Polyfill IE5+ | |
* Michael Rouse | |
* December 2016 | |
*/ | |
(function() { | |
if (window.addEventListener && window.removeEventListener) return; // Polyfill is not needed :) | |
if (!window.attachEvent || !window.detachEvent) { console.warn("Can't apply polyfill: no attachEvent or detachEvent"); return; } | |
var IsFunction = function(toCheck) { return typeof toCheck === 'function'; }; | |
var Phases = { None: 0, Capturing: 1, AtTarget: 2, Bubbling: 3 }; | |
/** | |
* Add Event Listener | |
*/ | |
function addEventListener(action, callback, capture) { | |
capture = capture ? true : false; | |
var self = this; | |
// Properties that hold the event listeners | |
self.__listeners = self.__listeners || { }; | |
self.__listeners[action] = self.__listeners[action] || [ ]; | |
// Listener object that will go in the array | |
var listener = { | |
fn: callback, | |
useCapture: capture | |
}; | |
// Only register the event once | |
if (self.__listeners[action].length == 0) { | |
// Create event listener for the first time | |
self.__listeners['on' + action] = function(e) { | |
e = polyfillEvent(e); | |
e.target = e.srcElement || self; | |
var domList = []; | |
var node = e.target; | |
// Get all nodes for propagation of the event | |
while (node) { | |
domList.unshift(node); | |
node = node.parentNode; | |
} | |
if (domList[0] !== window) domList.unshift(window); | |
e.view = domList[0]; // e.view is a reference to the window object where the event was called | |
// Capturing Phase (Window -> Target) | |
for (var i = 0; i < domList.length; i++) { | |
var el = domList[i]; | |
e.eventPhase = (self === el) ? Phases.AtTarget : Phases.Capturing; | |
e.currentTarget = el; | |
if (!el.__listeners || !el.__listeners[action]) continue; // No events on this element | |
// Call all the listeners on this element for this action | |
for (var j = 0; j < el.__listeners[action].length; j++) { | |
var listener = el.__listeners[action][j]; | |
if (!listener.useCapture || !IsFunction(listener.fn)) continue; // Ivalid callback or not a capture | |
// Call the event listener | |
listener.fn.call(el, e); | |
// Do not continue if propagation was stopped | |
if (e.cancelBubble) return; | |
} | |
} | |
// Bubbling Phase (Target -> Window) | |
for (var i = domList.length - 1; i >= 0; i--) { | |
var el = domList[i]; | |
e.eventPhase = (self === el) ? Phases.AtTarget : Phases.Bubbling; | |
e.currentTarget = el; | |
if (!el.__listeners || !el.__listeners[action]) continue; // No event listeners | |
// Call all the listeners on this element for this action | |
for (var j = 0; j < el.__listeners[action].length; j++) { | |
var listener = el.__listeners[action].length; | |
if (listener.useCapture || !IsFunction(listener.fn)) continue; // A capture event or invalid callback | |
// Call the event listener | |
listener.fn.call(el, e); | |
// Do not continue if propagation was stopped | |
if (e.cancelBubble) return; | |
} | |
} | |
e.cancelBubble = true; | |
}; | |
// Use attachEvent to create the event listener | |
self.attachEvent('on' + action, self.__listeners['on' + action]); | |
} | |
// Add the listener to the polyfill | |
self.__listeners[action].push(listener); | |
} | |
/** | |
* Remove Event Listener | |
*/ | |
function removeEventListener(action, callback, capture) { | |
capture = capture ? true : false; | |
var self = this; | |
// Properties that hold the event listeners | |
self.__listeners = self.__listeners || { }; | |
self.__listeners[action] = self.__listeners[action] || []; | |
// Find the event listener and remove it | |
for (var i = 0; i < self.__listeners[action].length; i++) { | |
if (self.__listeners[action][i].fn == callback && self.__listeners[action][i].useCapture == capture) { | |
self.__listeners[action].splice(i, 1); | |
break; | |
} | |
} | |
// If no more events exist, remove the event listener | |
if (self.__listeners[action].length == 0 && IsFunction(self.__listeners['on' + action])) { | |
self.detachEvent('on' + action, self.__listeners['on' + action]); | |
} | |
} | |
// Applies the polyfill to an element | |
function polyfill(el) { | |
el.addEventListener = addEventListener; | |
el.removeEventListener = removeEventListener; | |
return el; | |
} | |
// Alters a function on the document | |
function ReplaceDocFunction(fn) { | |
var old = document[fn]; | |
document[fn] = function(param) { | |
return polyfill(old(param)); | |
}; | |
} | |
// Apply the polyfills | |
polyfill(window); | |
polyfill(document); | |
// Add polyfill to window.Element if possible | |
if (window.Element && window.Element.prototype) { | |
polyfill(window.Element.prototype); | |
} else { | |
// Apply the polyfill to all of the elements in the document | |
for(var i = 0; i < document.all.length; i++) { | |
polyfill(document.all[i]); | |
} | |
// Change these important functions to return something that has the event listener functions | |
ReplaceDocFunction('getElementById'); | |
ReplaceDocFunction('getElementsByTagName'); | |
ReplaceDocFunction('createElement'); | |
} | |
}()); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment