attrchange.js 4.3 KB

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