1/** 2* jquery-watcher 3* 4* @author Rick Strahl 5* @copyright © 2014-2020 Rick Strahl, West Wind Technologies 6* @license MIT License http://en.wikipedia.org/wiki/MIT_License 7* @package jquery-watcher 8*/ 9 10(function($, undefined) { 11 $.fn.watch = function(options) { 12 /// <summary> 13 /// Allows you to monitor changes in a specific 14 /// CSS property of an element by polling the value. 15 /// You can also monitor attributes (using attr_ prefix) 16 /// or property changes (using prop_ prefix). 17 /// when the value changes a function is called. 18 /// The callback is fired in the context 19 /// of the selected element (ie. this) 20 /// 21 /// Uses the MutationObserver API of the DOM and 22 /// falls back to setInterval to poll for changes 23 /// for non-compliant browsers (pre IE 11) 24 /// </summary> 25 /// <param name="options" type="Object"> 26 /// Option to set - see comments in code below. 27 /// </param> 28 /// <returns type="jQuery" /> 29 var opt = $.extend({ 30 // CSS styles or Attributes to monitor as comma delimited list 31 // For attributes use a attr_ prefix 32 // Example: "top,left,opacity,attr_class" 33 properties: null, 34 35 // interval for 'manual polling' (IE 10 and older) 36 interval: 100, 37 38 // a unique id for this watcher instance 39 id: "_watcher_" + new Date().getTime(), 40 41 // flag to determine whether child elements are watched 42 watchChildren: false, 43 44 // Callback function if not passed in callback parameter 45 callback: null 46 }, options); 47 48 return this.each(function() { 49 var el = this; 50 var el$ = $(this); 51 var fnc = function(mRec, mObs) {
52 __watcher.call(el, opt.id, mRec, mObs); 53 }; 54 55 var data = { 56 id: opt.id, 57 props: opt.properties.split(','), 58 vals: [opt.properties.split(',').length], 59 func: opt.callback, // user function 60 fnc: fnc, // __watcher internal 61 origProps: opt.properties, 62 interval: opt.interval, 63 intervalId: null 64 }; 65 // store initial props and values 66 $.each(data.props, function(i) { 67 var propName = data.props[i]; 68 if (data.props[i].startsWith('attr_')) 69 data.vals[i] = el$.attr(propName.replace('attr_', '')); 70 else if (propName.startsWith('prop_')) 71 data.vals[i] = el$.prop(propName.replace('props_', '')); 72 else 73 data.vals[i] = el$.css(propName); 74 }); 75 76 el$.data(opt.id, data); 77 78 hookChange(el$, opt.id, data); 79 }); 80 81 function hookChange(element$, id, data) { 82 element$.each(function() { 83 var el$ = $(this); 84 85 if (window.MutationObserver) { 86 var observer = el$.data('__watcherObserver' + opt.id); 87 if (observer == null) { 88 observer = new MutationObserver(data.fnc); 89 el$.data('__watcherObserver' + opt.id, observer); 90 } 91 observer.observe(this, { 92 attributes: true, 93 subtree: opt.watchChildren, 94 childList: opt.watchChildren, 95 characterData: true 96 }); 97 } else 98 data.intervalId = setInterval(data.fnc, opt.interval); 99 }); 100 } 101
102 function __watcher(id, mRec, mObs) { 103 var el$ = $(this); 104 var w = el$.data(id); 105 if (!w) return; 106 var el = this; 107 108 if (!w.func) 109 return; 110 111 var changed = false; 112 var i = 0; 113 for (i; i < w.props.length; i++) { 114 var key = w.props[i]; 115 116 var newVal = ""; 117 if (key.startsWith('attr_')) 118 newVal = el$.attr(key.replace('attr_', '')); 119 else if (key.startsWith('prop_')) 120 newVal = el$.prop(key.replace('prop_', '')); 121 else 122 newVal = el$.css(key); 123 124 if (newVal == undefined) 125 continue; 126 127 if (w.vals[i] != newVal) { 128 w.vals[i] = newVal; 129 changed = true; 130 break; 131 } 132 } 133 if (changed) { 134 // unbind to avoid recursive events 135 el$.unwatch(id); 136 137 // call the user handler
138 w.func.call(el, w, i, mRec, mObs); 139 140 // rebind the events 141 hookChange(el$, id, w); 142 } 143 } 144 } 145 $.fn.unwatch = function(id) { 146 this.each(function() { 147 var el = $(this); 148 var data = el.data(id); 149 try { 150 if (window.MutationObserver) { 151 var observer = el.data("__watcherObserver" + id); 152 if (observer) { 153 observer.disconnect(); 154 el.removeData("__watcherObserver" + id); 155 } 156 } else 157 clearInterval(data.intervalId); 158 } 159 // ignore if element was already unbound 160 catch (e) { 161 } 162 }); 163 return this; 164 } 165 String.prototype.startsWith = function(sub) { 166 if (sub === null || sub === undefined) return false; 167 return sub == this.substr(0, sub.length); 168 } 169 } 170)(jQuery, undefined);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.