Created
May 19, 2015 08:30
-
-
Save Shine-neko/e5a75c97d633822a531c to your computer and use it in GitHub Desktop.
This file contains 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
(function ($, undefined) { | |
$.fn.watch = function (options) { | |
/// <summary> | |
/// Allows you to monitor changes in a specific | |
/// CSS property of an element by polling the value. | |
/// when the value changes a function is called. | |
/// The function called is called in the context | |
/// of the selected element (ie. this) | |
/// | |
/// Uses the MutationObserver API of the DOM and | |
/// falls back to setInterval to poll for changes | |
/// for non-compliant browsers (pre IE 11) | |
/// </summary> | |
/// <param name="options" type="Object"> | |
/// Option to set - see comments in code below. | |
/// </param> | |
/// <returns type="jQuery" /> | |
var opt = $.extend({ | |
// CSS styles or Attributes to monitor as comma delimited list | |
// For attributes use a attr_ prefix | |
// Example: "top,left,opacity,attr_class" | |
properties: null, | |
// interval for 'manual polling' (IE 10 and older) | |
interval: 100, | |
// a unique id for this watcher instance | |
id: "_watcher", | |
// flag to determine whether child elements are watched | |
watchChildren: false, | |
// Callback function if not passed in callback parameter | |
callback: null | |
}, options); | |
return this.each(function () { | |
var el = this; | |
var el$ = $(this); | |
var fnc = function (mRec, mObs) { | |
__watcher.call(el, opt.id, mRec, mObs); | |
}; | |
var data = { | |
id: opt.id, | |
props: opt.properties.split(','), | |
vals: [opt.properties.split(',').length], | |
func: opt.callback, // user function | |
fnc: fnc, // __watcher internal | |
origProps: opt.properties, | |
interval: opt.interval, | |
intervalId: null | |
}; | |
// store initial props and values | |
$.each(data.props, function(i) { | |
if (data.props[i].startsWith('attr_')) | |
data.vals[i] = el$.attr(data.props[i].replace('attr_','')); | |
else | |
data.vals[i] = el$.css(data.props[i]); | |
}); | |
el$.data(opt.id, data); | |
hookChange(el$, opt.id, data); | |
}); | |
function hookChange(element$, id, data) { | |
element$.each(function () { | |
var el$ = $(this); | |
if (window.MutationObserver) { | |
var observer = el$.data('__watcherObserver'); | |
if (observer == null) { | |
observer = new MutationObserver(data.fnc); | |
el$.data('__watcherObserver', observer); | |
} | |
observer.observe(this, { | |
attributes: true, | |
subtree: opt.watchChildren, | |
childList: opt.watchChildren, | |
characterData: true | |
}); | |
} else | |
data.intervalId = setInterval(data.fnc, interval); | |
}); | |
} | |
function __watcher(id,mRec,mObs) { | |
var el$ = $(this); | |
var w = el$.data(id); | |
if (!w) return; | |
var el = this; | |
if (!w.func) | |
return; | |
var changed = false; | |
var i = 0; | |
for (i; i < w.props.length; i++) { | |
var key = w.props[i]; | |
var newVal = ""; | |
if (key.startsWith('attr_')) | |
newVal = el$.attr(key.replace('attr_', '')); | |
else | |
newVal = el$.css(key); | |
if (newVal == undefined) | |
continue; | |
if (w.vals[i] != newVal) { | |
w.vals[i] = newVal; | |
changed = true; | |
break; | |
} | |
} | |
if (changed) { | |
// unbind to avoid recursive events | |
el$.unwatch(id); | |
// call the user handler | |
w.func.call(el, w, i, mRec, mObs); | |
// rebind the events | |
hookChange(el$, id, w); | |
} | |
} | |
} | |
$.fn.unwatch = function (id) { | |
this.each(function () { | |
var el = $(this); | |
var data = el.data(id); | |
try { | |
if (window.MutationObserver) { | |
var observer = el.data("__watcherObserver"); | |
if (observer) { | |
observer.disconnect(); | |
el.removeData("__watcherObserver"); | |
} | |
} else | |
clearInterval(data.intervalId); | |
} | |
// ignore if element was already unbound | |
catch (e) { | |
} | |
}); | |
return this; | |
} | |
String.prototype.startsWith = function (sub) { | |
if (sub === null || sub === undefined) return false; | |
return sub == this.substr(0, sub.length); | |
} | |
})(jQuery, undefined); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment