[81b0915] | 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); |
---|