forked from darcyclarke/Watch.js
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathjquery.watch.js
143 lines (120 loc) · 3.72 KB
/
jquery.watch.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/**
* jQuery Watch Plugin
*
* @author Darcy Clarke
*
* Copyright (c) 2013 Darcy Clarke
* Dual licensed under the MIT and GPL licenses.
*
* Usage:
* $('div').watch('width height', function(){
* console.log(this.style.width, this.style.height);
* });
*/
(function($){
/**
* Watch Method
*
* @param (String) the name of the properties to watch
* @param (Object) options to overide defaults (only 'throttle' right now)
* @param (Function) callback function to be executed when attributes change
*
* @return (jQuery Object) returns the jQuery object for chainability
*/
$.fn.watch = function(props, options, callback){
// Div element
var div = document.createElement('div');
// Check MutationObserver
var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
// CustomEvent with fallback
var CustomEvent = window.CustomEvent || function(){ return arguments || {}; };
/**
* Checks Support for Event
*
* @param (String) the name of the event
* @param (Element Object) the element to test support against
*
* @return {Boolean} returns result of test (true/false)
*/
var isEventSupported = function(eventName, el){
eventName = 'on' + eventName;
var supported = (eventName in el);
if(!supported){
el.setAttribute(eventName, 'return;');
supported = typeof el[eventName] == 'function';
}
return supported;
};
// Type check options
if(typeof(options) == 'function'){
callback = options;
options = {};
}
// Type check callback
if(typeof(callback) != 'function')
callback = function(){};
// Map options over defaults
options = $.extend({}, { throttle : 10 }, options);
/**
* Checks if properties have changed
*
* @param (Element Object) the element to watch
*/
var check = function($el){
var that = this;
$.each(this.watching, function(){
// Setup
var data = this;
var changed = false;
var temp;
// Loop through properties
for(var i=0;i < data.props.length; i++){
temp = $el[0].attributes[data.props[i]] || $el.css(data.props[i]);
if(data.vals[i] != temp){
data.vals[i] = temp;
changed = true;
break;
}
}
// Run callback if property has changed
if(changed && data.callback)
data.callback.call(that, new CustomEvent('AttrChange'));
});
};
// Iterate over each element
return this.each(function(){
var that = this;
var $el = $(this);
var data = {
props: props.split(' '),
vals: [],
changed: [],
callback: callback
};
// Grab each properties initial value
$.each(data.props, function(i){
data.vals[i] = $el[0].attributes[data.props[i]] || $el.css(data.props[i]);
data.changed[i] = false;
});
// Set data
if(!this.watching)
this.watching = [];
this.watching.push(data);
// Choose method of watching and fallback
if(MutationObserver){
var observer = new MutationObserver(function(mutations){
mutations.forEach(function(mutation){
callback.call(that, mutation);
});
});
observer.observe(this, { subtree: false, attributes: true });
} else if(isEventSupported('DOMAttrModified', div)){
$el.on('DOMAttrModified', callback);
} else if(isEventSupported('propertychange', div)){
$el.on('propertychange', callback);
} else {
setInterval(function(){ check.call(that, $el); }, options.throttle);
}
});
};
})(jQuery);