domchange.js (2786B)
1 // See: http://stackoverflow.com/a/3219767 2 (function (window) { 3 var last = +new Date(); 4 var delay = 100; // default delay 5 6 // Manage event queue 7 var stack = []; 8 9 function callback() { 10 var now = +new Date(); 11 if (now - last > delay) { 12 for (var i = 0; i < stack.length; i++) { 13 stack[i](); 14 } 15 last = now; 16 } 17 } 18 19 // Public interface 20 var onDomChange = function (fn, newdelay) { 21 if (newdelay) delay = newdelay; 22 stack.push(fn); 23 }; 24 25 // Naive approach for compatibility 26 function naive() { 27 28 var last = document.getElementsByTagName('*'); 29 var lastlen = last.length; 30 var timer = setTimeout(function check() { 31 32 // get current state of the document 33 var current = document.getElementsByTagName('*'); 34 var len = current.length; 35 36 // if the length is different 37 // it's fairly obvious 38 if (len != lastlen) { 39 // just make sure the loop finishes early 40 last = []; 41 } 42 43 // go check every element in order 44 for (var i = 0; i < len; i++) { 45 if (current[i] !== last[i]) { 46 callback(); 47 last = current; 48 lastlen = len; 49 break; 50 } 51 } 52 53 // over, and over, and over again 54 setTimeout(check, delay); 55 56 }, delay); 57 } 58 59 // 60 // Check for mutation events support 61 // 62 63 var support = {}; 64 65 var el = document.documentElement; 66 var remain = 3; 67 68 // callback for the tests 69 function decide() { 70 if (support.DOMNodeInserted) { 71 window.addEventListener("DOMContentLoaded", function () { 72 if (support.DOMSubtreeModified) { // for FF 3+, Chrome 73 el.addEventListener('DOMSubtreeModified', callback, false); 74 } else { // for FF 2, Safari, Opera 9.6+ 75 el.addEventListener('DOMNodeInserted', callback, false); 76 el.addEventListener('DOMNodeRemoved', callback, false); 77 } 78 }, false); 79 } else if (document.onpropertychange) { // for IE 5.5+ 80 document.onpropertychange = callback; 81 } else { // fallback 82 naive(); 83 } 84 } 85 86 // checks a particular event 87 function test(event) { 88 el.addEventListener(event, function fn() { 89 support[event] = true; 90 el.removeEventListener(event, fn, false); 91 if (--remain === 0) decide(); 92 }, false); 93 } 94 95 // attach test events 96 if (window.addEventListener) { 97 test('DOMSubtreeModified'); 98 test('DOMNodeInserted'); 99 test('DOMNodeRemoved'); 100 } else { 101 decide(); 102 } 103 104 // do the dummy test 105 var dummy = document.createElement("div"); 106 el.appendChild(dummy); 107 el.removeChild(dummy); 108 109 // expose 110 if (typeof define === 'function' && define.amd) { 111 define('domchange', function() { 112 return onDomChange; 113 }) 114 } 115 window.onDomChange = onDomChange; 116 })(window);