1 | /* |
---|
2 | A simple jQuery function that can add listeners on attribute change. |
---|
3 | http://meetselva.github.io/attrchange/ |
---|
4 | |
---|
5 | About License: |
---|
6 | Copyright (C) 2013-2014 Selvakumar Arumugam |
---|
7 | You may use attrchange plugin under the terms of the MIT Licese. |
---|
8 | https://github.com/meetselva/attrchange/blob/master/MIT-License.txt |
---|
9 | */ |
---|
10 | (function($) { |
---|
11 | function isDOMAttrModifiedSupported() { |
---|
12 | var p = document.createElement('p'); |
---|
13 | var flag = false; |
---|
14 | |
---|
15 | if (p.addEventListener) { |
---|
16 | p.addEventListener('DOMAttrModified', function() { |
---|
17 | flag = true |
---|
18 | }, false); |
---|
19 | } else if (p.attachEvent) { |
---|
20 | p.attachEvent('onDOMAttrModified', function() { |
---|
21 | flag = true |
---|
22 | }); |
---|
23 | } else { return false; } |
---|
24 | p.setAttribute('id', 'target'); |
---|
25 | return flag; |
---|
26 | } |
---|
27 | |
---|
28 | function checkAttributes(chkAttr, e) { |
---|
29 | if (chkAttr) { |
---|
30 | var attributes = this.data('attr-old-value'); |
---|
31 | |
---|
32 | if (e.attributeName.indexOf('style') >= 0) { |
---|
33 | if (!attributes['style']) |
---|
34 | attributes['style'] = {}; //initialize |
---|
35 | var keys = e.attributeName.split('.'); |
---|
36 | e.attributeName = keys[0]; |
---|
37 | e.oldValue = attributes['style'][keys[1]]; //old value |
---|
38 | e.newValue = keys[1] + ':' |
---|
39 | + this.prop("style")[$.camelCase(keys[1])]; //new value |
---|
40 | attributes['style'][keys[1]] = e.newValue; |
---|
41 | } else { |
---|
42 | e.oldValue = attributes[e.attributeName]; |
---|
43 | e.newValue = this.attr(e.attributeName); |
---|
44 | attributes[e.attributeName] = e.newValue; |
---|
45 | } |
---|
46 | |
---|
47 | this.data('attr-old-value', attributes); //update the old value object |
---|
48 | } |
---|
49 | } |
---|
50 | |
---|
51 | //initialize Mutation Observer |
---|
52 | var MutationObserver = window.MutationObserver |
---|
53 | || window.WebKitMutationObserver; |
---|
54 | |
---|
55 | $.fn.attrchange = function(a, b) { |
---|
56 | if (typeof a == 'object') {//core |
---|
57 | var cfg = { |
---|
58 | trackValues : false, |
---|
59 | callback : $.noop |
---|
60 | }; |
---|
61 | //backward compatibility |
---|
62 | if (typeof a === "function") { cfg.callback = a; } else { $.extend(cfg, a); } |
---|
63 | |
---|
64 | if (cfg.trackValues) { //get attributes old value |
---|
65 | this.each(function(i, el) { |
---|
66 | var attributes = {}; |
---|
67 | for ( var attr, i = 0, attrs = el.attributes, l = attrs.length; i < l; i++) { |
---|
68 | attr = attrs.item(i); |
---|
69 | attributes[attr.nodeName] = attr.value; |
---|
70 | } |
---|
71 | $(this).data('attr-old-value', attributes); |
---|
72 | }); |
---|
73 | } |
---|
74 | |
---|
75 | if (MutationObserver) { //Modern Browsers supporting MutationObserver |
---|
76 | var mOptions = { |
---|
77 | subtree : false, |
---|
78 | attributes : true, |
---|
79 | attributeOldValue : cfg.trackValues |
---|
80 | }; |
---|
81 | var observer = new MutationObserver(function(mutations) { |
---|
82 | mutations.forEach(function(e) { |
---|
83 | var _this = e.target; |
---|
84 | //get new value if trackValues is true |
---|
85 | if (cfg.trackValues) { |
---|
86 | e.newValue = $(_this).attr(e.attributeName); |
---|
87 | } |
---|
88 | if ($(_this).data('attrchange-status') === 'connected') { //execute if connected |
---|
89 | cfg.callback.call(_this, e); |
---|
90 | } |
---|
91 | }); |
---|
92 | }); |
---|
93 | |
---|
94 | return this.data('attrchange-method', 'Mutation Observer').data('attrchange-status', 'connected') |
---|
95 | .data('attrchange-obs', observer).each(function() { |
---|
96 | observer.observe(this, mOptions); |
---|
97 | }); |
---|
98 | } else if (isDOMAttrModifiedSupported()) { //Opera |
---|
99 | //Good old Mutation Events |
---|
100 | return this.data('attrchange-method', 'DOMAttrModified').data('attrchange-status', 'connected').on('DOMAttrModified', function(event) { |
---|
101 | if (event.originalEvent) { event = event.originalEvent; }//jQuery normalization is not required |
---|
102 | event.attributeName = event.attrName; //property names to be consistent with MutationObserver |
---|
103 | event.oldValue = event.prevValue; //property names to be consistent with MutationObserver |
---|
104 | if ($(this).data('attrchange-status') === 'connected') { //disconnected logically |
---|
105 | cfg.callback.call(this, event); |
---|
106 | } |
---|
107 | }); |
---|
108 | } else if ('onpropertychange' in document.body) { //works only in IE |
---|
109 | return this.data('attrchange-method', 'propertychange').data('attrchange-status', 'connected').on('propertychange', function(e) { |
---|
110 | e.attributeName = window.event.propertyName; |
---|
111 | //to set the attr old value |
---|
112 | checkAttributes.call($(this), cfg.trackValues, e); |
---|
113 | if ($(this).data('attrchange-status') === 'connected') { //disconnected logically |
---|
114 | cfg.callback.call(this, e); |
---|
115 | } |
---|
116 | }); |
---|
117 | } |
---|
118 | return this; |
---|
119 | } else if (typeof a == 'string' && $.fn.attrchange.hasOwnProperty('extensions') && |
---|
120 | $.fn.attrchange['extensions'].hasOwnProperty(a)) { //extensions/options |
---|
121 | return $.fn.attrchange['extensions'][a].call(this, b); |
---|
122 | } |
---|
123 | } |
---|
124 | })(jQuery); |
---|