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 ) ;
0 commit comments