Last active
February 5, 2024 08:34
Revisions
-
Warsaalk revised this gist
Dec 13, 2018 . 1 changed file with 152 additions and 130 deletions.There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -1,139 +1,161 @@ /** * @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); }; }; -
Warsaalk revised this gist
Jan 7, 2016 . No changes.There are no files selected for viewing
-
Warsaalk revised this gist
Jan 7, 2016 . No changes.There are no files selected for viewing
-
Warsaalk created this gist
Jan 7, 2016 .There are no files selected for viewing
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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,35 @@ <!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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,139 @@ /** * 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) { 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])) { classQueue[x] = 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]) { nodeQueue[x] = 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]); } }; // 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) { 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) { 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) { 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]); } } } checkId = document.getElementById(parentName); if (checkId && checkId.nodeName.toUpperCase() == nodeName.toUpperCase()) { process(callback, checkId); } nodeList.push(nodeName); nodeParent.push(parentName); nodeCallback.push(callback); }; };