Last active
February 5, 2024 08:34
-
-
Save Warsaalk/17346faac439f7d8a30a to your computer and use it in GitHub Desktop.
A Javascript class that observes DOM changes for a single target. It allows listening to ID's, Classes and Node names and returns the nodes if they are added to the DOM.
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
<!doctype html> | |
<html> | |
<head> | |
<title>Mutation Listener</title> | |
<script src="mutationlistener.js"></script> | |
</head> | |
<body> | |
<div id="test"> | |
Existing content | |
</div> | |
<script> | |
var listener = new Observer(document); | |
listener.listenToId('test', function () { | |
console.log(this); | |
}); | |
listener.listenToClass('test', function () { | |
console.log(this); | |
}); | |
listener.listenToElement('p', 'test', function () { | |
console.log(this); | |
}); | |
var testClass = document.createElement('div'); | |
testClass.classList.add('test'); | |
testClass.appendChild(document.createTextNode('Newly added div with ClassName "test"')); | |
document.body.appendChild(testClass); | |
var paragraph = document.createElement('p'); | |
paragraph.appendChild(document.createTextNode('Newly added paragraph')); | |
document.getElementById('test').appendChild(paragraph); | |
</script> | |
</body> | |
</html> |
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
/** | |
* @author Klaas Van Parys | |
* | |
* Listen to changes within a target and subscribe to those changes. | |
* | |
* @class Observer | |
* @constructor | |
* | |
* @param {Node|String} targetArgument This is the single target you want to observe. It can be a selector or a Node | |
* @param {Boolean} [asyncArgument=false] Set to "true" if the found elements should be processed asynchronously | |
*/ | |
function Observer (targetArgument, asyncArgument) | |
{ | |
this.supported = "MutationObserver" in window; | |
var target = "string" === typeof targetArgument ? document.querySelector(targetArgument) : targetArgument; | |
var async = "boolean" === typeof asyncArgument ? asyncArgument : false; | |
var idList = [], idCallback = []; | |
var classList = [], classCallback = []; | |
var nodeList = [], nodeParent = [], nodeCallback = []; | |
var process = function (callback, mutation) | |
{ | |
if (async) { | |
setTimeout(function(callbackArg, mutationArg) { | |
if (callbackArg) return function () { callbackArg.call(mutationArg) }; | |
}(callback, mutation), 0); | |
} else { | |
callback.call(mutation); | |
} | |
}; | |
var mutationCallback = function (mutations) | |
{ | |
var idQueue = {}, classQueue = {}, nodeQueue = {}; | |
for (var i=mutations.length; i--;) { | |
for (var n=mutations[i].addedNodes.length; n--;) { | |
if (mutations[i].addedNodes[n].nodeType === 1){ //Only observe elements | |
for (var x=idList.length; x--;) { | |
if (mutations[i].addedNodes[n].id === idList[x]) { | |
idQueue[x] = mutations[i].addedNodes[n]; | |
} | |
} | |
for (var x=classList.length; x--;) { | |
if (mutations[i].addedNodes[n].classList.contains(classList[x])) { | |
if (classQueue[x] === void 0) { | |
classQueue[x] = []; | |
} | |
classQueue[x].push(mutations[i].addedNodes[n]); | |
} | |
} | |
for (var x=nodeList.length; x--;) { | |
if (mutations[i].addedNodes[n].nodeName.toUpperCase() === nodeList[x].toUpperCase()) { | |
if (mutations[i].target.classList.contains(nodeParent[x]) || mutations[i].target.id === nodeParent[x]) { | |
if (nodeQueue[x] === void 0) { | |
nodeQueue[x] = []; | |
} | |
nodeQueue[x].push(mutations[i].addedNodes[n]); | |
} | |
} | |
} | |
} | |
} | |
} | |
//Process found ID elements | |
for (var index in idQueue) { | |
process(idCallback[index], idQueue[index]); | |
} | |
//Process found Class elements | |
for (var index in classQueue) { | |
process(classCallback[index], classQueue[index]); | |
} | |
//Process found nodes | |
for (var index in nodeQueue) { | |
process(nodeCallback[index], nodeQueue[index]); | |
} | |
}; | |
if (this.supported) { | |
// Init MutationObserver | |
var mutationObserver = new MutationObserver(mutationCallback); | |
mutationObserver.observe(target, {childList: true, subtree: true}); | |
} | |
/** | |
* Start listening to a specific ID | |
* | |
* @method listenToId | |
* @param {String} id The html ID you want to listen to | |
* @param {Function} callback A function that needs to be called when the element is found | |
*/ | |
this.listenToId = function (id, callback) | |
{ | |
if (this.supported === false) return false; | |
var check = document.getElementById(id); | |
if (check) { | |
process(callback, check); | |
} | |
idList.push(id); | |
idCallback.push(callback); | |
}; | |
/** | |
* Start listening to a specific ClassName | |
* | |
* @method listenToClass | |
* @param {String} className The html ClassName you want to listen to | |
* @param {Function} callback A function that needs to be called when the element is found | |
*/ | |
this.listenToClass = function (className, callback) | |
{ | |
if (this.supported === false) return false; | |
var check = document.getElementsByClassName(className); | |
if (check.length > 0) { | |
for (var i=check.length; i--;) { | |
process(callback, check[i]); | |
} | |
} | |
classList.push(className); | |
classCallback.push(callback); | |
}; | |
/** | |
* Start listening to a specific Node name | |
* | |
* @method listenToElement | |
* @param {String} nodeName The html Node name you want to listen to | |
* @param {String} parentName The html ID or ClassName of the nodeName its parent | |
* @param {Function} callback A function that needs to be called when the element is found | |
*/ | |
this.listenToElement = function (nodeName, parentName, callback) | |
{ | |
if (this.supported === false) return false; | |
var checkClass = document.getElementsByClassName(parentName); | |
if (checkClass.length > 0) { | |
for (var i=checkClass.length; i--;) { | |
if (checkClass[i].nodeName.toUpperCase() === nodeName.toUpperCase()) { | |
process(callback, checkClass[i]); | |
} | |
} | |
} | |
var checkId = document.getElementById(parentName); | |
if (checkId && checkId.nodeName.toUpperCase() === nodeName.toUpperCase()) { | |
process(callback, checkId); | |
} | |
nodeList.push(nodeName); | |
nodeParent.push(parentName); | |
nodeCallback.push(callback); | |
}; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment