UNPKG

ifsm

Version:

a jQuery State Machine (FSM / HSM) to design and manage javascript web user interfaces, simulators, games...

186 lines (155 loc) 6.5 kB
/* A simple jQuery function that can add listeners on attribute change. http://meetselva.github.io/attrchange/ About License: Copyright (C) 2013 Selvakumar Arumugam You may use attrchange plugin under the terms of the MIT Licese. https://github.com/meetselva/attrchange/blob/master/MIT-License.txt attrchange is a simple jQuery function to bind a listener function to any HTML element on attribute change. DEMOS & DOCUMENTATION: ====================== http://meetselva.github.com/attrchange/ Reference: ========== - http://hacks.mozilla.org/2012/05/dom-mutationobserver-reacting-to-dom-changes-without-killing-browser-performance/ - https://developer.mozilla.org/en/DOM/Mutation_events - https://developer.mozilla.org/en/DOM/DOM_Mutation_Observers - http://msdn.microsoft.com/en-us/library/ie/ms536956%28v=vs.85%29.aspx Browser Support Information: ============================ This plugin has been successfully tested in the following browsers: IE6+ FF Chrome `DOMAttrModified` - Supported in IE 9, FF and Opera `MutationObservers` - is very new and it is supported in FF and Chrome 18. `onpropertychange` - Only in IE Known Issues: ============ attrchange plugin uses different API to support cross browser/backward compatibility. The response has been normalized to match with the response from MutationObserver however the return values from the API's are sometimes different especially on style attribute. On changing the style attribute, Older standard such as DOMAttrModified/onpropertychange returns the specific css property that was updated (ex: return for updating css top would return -> top: 60px) but the MutationObserver returns the entire style attribute value and not the property that was changed (something like $(this).attr('style')). Example: ======== <script type="text/javascript" src="http://code.jquery.com/jquery.min.js"></script> <script type="text/javascript" src="https://raw.github.com/meetselva/attrchange/master/attrchange.js"></script> <script type="text/javascript"> $(selector).attrchange({ trackValues: true, // Default to false, if set to true the event object is updated with old and new value. callback: function (event) { //event - event object //event.attributeName - Name of the attribute modified //event.oldValue - Previous value of the modified attribute //event.newValue - New value of the modified attribute //Triggered when the selected elements attribute is added/updated/removed } }); </script> */ (function($) { function isDOMAttrModifiedSupported() { var p = document.createElement('p'); var flag = false; if (p.addEventListener) p.addEventListener('DOMAttrModified', function() { flag = true }, false); else if (p.attachEvent) p.attachEvent('onDOMAttrModified', function() { flag = true }); else return false; p.setAttribute('id', 'target'); return flag; } function checkAttributes(chkAttr, e) { if (chkAttr) { var attributes = this.data('attr-old-value'); if (e.attributeName.indexOf('style') >= 0) { if (!attributes['style']) attributes['style'] = {}; //initialize var keys = e.attributeName.split('.'); e.attributeName = keys[0]; e.oldValue = attributes['style'][keys[1]]; //old value e.newValue = keys[1] + ':' + this.prop("style")[$.camelCase(keys[1])]; //new value attributes['style'][keys[1]] = e.newValue; } else { e.oldValue = attributes[e.attributeName]; e.newValue = this.attr(e.attributeName); attributes[e.attributeName] = e.newValue; } this.data('attr-old-value', attributes); //update the old value object } } //initialize Mutation Observer var MutationObserver = window.MutationObserver || window.WebKitMutationObserver; $.fn.attrchange = function(o) { var cfg = { trackValues: false, callback: $.noop }; //for backward compatibility if (typeof o === "function" ) { cfg.callback = o; } else { $.extend(cfg, o); } if (cfg.trackValues) { //get attributes old value $(this).each(function (i, el) { var attributes = {}; for (var attr, i=0, attrs=el.attributes, l=attrs.length; i<l; i++){ attr = attrs.item(i); attributes[attr.nodeName] = attr.value; } $(this).data('attr-old-value', attributes); }); } if (MutationObserver) { //Modern Browsers supporting MutationObserver /* Mutation Observer is still new and not supported by all browsers. http://lists.w3.org/Archives/Public/public-webapps/2011JulSep/1622.html */ var mOptions = { subtree: false, attributes: true, attributeOldValue: cfg.trackValues }; var observer = new MutationObserver(function(mutations) { mutations.forEach(function(e) { var _this = e.target; //get new value if trackValues is true if (cfg.trackValues) { /** * @KNOWN_ISSUE: The new value is buggy for STYLE attribute as we don't have * any additional information on which style is getting updated. * */ e.newValue = $(_this).attr(e.attributeName); } cfg.callback.call(_this, e); }); }); return this.each(function() { observer.observe(this, mOptions); }); } else if (isDOMAttrModifiedSupported()) { //Opera //Good old Mutation Events but the performance is no good //http://hacks.mozilla.org/2012/05/dom-mutationobserver-reacting-to-dom-changes-without-killing-browser-performance/ return this.on('DOMAttrModified', function(event) { if (event.originalEvent) event = event.originalEvent; //jQuery normalization is not required for us event.attributeName = event.attrName; //property names to be consistent with MutationObserver event.oldValue = event.prevValue; //property names to be consistent with MutationObserver cfg.callback.call(this, event); }); } else if ('onpropertychange' in document.body) { //works only in IE return this.on('propertychange', function(e) { e.attributeName = window.event.propertyName; //to set the attr old value checkAttributes.call($(this), cfg.trackValues , e); cfg.callback.call(this, e); }); } return this; } })(jQuery);