detect-element-resize.js 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. /**
  2. * Detect Element Resize
  3. *
  4. * https://github.com/sdecima/javascript-detect-element-resize
  5. * Sebastian Decima
  6. *
  7. * version: 0.5.3
  8. **/
  9. (function () {
  10. var attachEvent = document.attachEvent,
  11. stylesCreated = false;
  12. if (!attachEvent) {
  13. var requestFrame = (function(){
  14. var raf = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame ||
  15. function(fn){ return window.setTimeout(fn, 20); };
  16. return function(fn){ return raf(fn); };
  17. })();
  18. var cancelFrame = (function(){
  19. var cancel = window.cancelAnimationFrame || window.mozCancelAnimationFrame || window.webkitCancelAnimationFrame ||
  20. window.clearTimeout;
  21. return function(id){ return cancel(id); };
  22. })();
  23. function resetTriggers(element){
  24. var triggers = element.__resizeTriggers__,
  25. expand = triggers.firstElementChild,
  26. contract = triggers.lastElementChild,
  27. expandChild = expand.firstElementChild;
  28. contract.scrollLeft = contract.scrollWidth;
  29. contract.scrollTop = contract.scrollHeight;
  30. expandChild.style.width = expand.offsetWidth + 1 + 'px';
  31. expandChild.style.height = expand.offsetHeight + 1 + 'px';
  32. expand.scrollLeft = expand.scrollWidth;
  33. expand.scrollTop = expand.scrollHeight;
  34. };
  35. function checkTriggers(element){
  36. return element.offsetWidth != element.__resizeLast__.width ||
  37. element.offsetHeight != element.__resizeLast__.height;
  38. }
  39. function scrollListener(e){
  40. var element = this;
  41. resetTriggers(this);
  42. if (this.__resizeRAF__) cancelFrame(this.__resizeRAF__);
  43. this.__resizeRAF__ = requestFrame(function(){
  44. if (checkTriggers(element)) {
  45. element.__resizeLast__.width = element.offsetWidth;
  46. element.__resizeLast__.height = element.offsetHeight;
  47. element.__resizeListeners__.forEach(function(fn){
  48. fn.call(element, e);
  49. });
  50. }
  51. });
  52. };
  53. /* Detect CSS Animations support to detect element display/re-attach */
  54. var animation = false,
  55. animationstring = 'animation',
  56. keyframeprefix = '',
  57. animationstartevent = 'animationstart',
  58. domPrefixes = 'Webkit Moz O ms'.split(' '),
  59. startEvents = 'webkitAnimationStart animationstart oAnimationStart MSAnimationStart'.split(' '),
  60. pfx = '';
  61. {
  62. var elm = document.createElement('fakeelement');
  63. if( elm.style.animationName !== undefined ) { animation = true; }
  64. if( animation === false ) {
  65. for( var i = 0; i < domPrefixes.length; i++ ) {
  66. if( elm.style[ domPrefixes[i] + 'AnimationName' ] !== undefined ) {
  67. pfx = domPrefixes[ i ];
  68. animationstring = pfx + 'Animation';
  69. keyframeprefix = '-' + pfx.toLowerCase() + '-';
  70. animationstartevent = startEvents[ i ];
  71. animation = true;
  72. break;
  73. }
  74. }
  75. }
  76. }
  77. var animationName = 'resizeanim';
  78. var animationKeyframes = '@' + keyframeprefix + 'keyframes ' + animationName + ' { from { opacity: 0; } to { opacity: 0; } } ';
  79. var animationStyle = keyframeprefix + 'animation: 1ms ' + animationName + '; ';
  80. }
  81. function createStyles() {
  82. if (!stylesCreated) {
  83. //opacity:0 works around a chrome bug https://code.google.com/p/chromium/issues/detail?id=286360
  84. var css = (animationKeyframes ? animationKeyframes : '') +
  85. '.resize-triggers { ' + (animationStyle ? animationStyle : '') + 'visibility: hidden; opacity: 0; } ' +
  86. '.resize-triggers, .resize-triggers > div, .contract-trigger:before { content: \" \"; display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; } .resize-triggers > div { background: #eee; overflow: auto; } .contract-trigger:before { width: 200%; height: 200%; }',
  87. head = document.head || document.getElementsByTagName('head')[0],
  88. style = document.createElement('style');
  89. style.type = 'text/css';
  90. if (style.styleSheet) {
  91. style.styleSheet.cssText = css;
  92. } else {
  93. style.appendChild(document.createTextNode(css));
  94. }
  95. head.appendChild(style);
  96. stylesCreated = true;
  97. }
  98. }
  99. window.addResizeListener = function(element, fn){
  100. if (attachEvent) element.attachEvent('onresize', fn);
  101. else {
  102. if (!element.__resizeTriggers__) {
  103. if (getComputedStyle(element).position == 'static') element.style.position = 'relative';
  104. createStyles();
  105. element.__resizeLast__ = {};
  106. element.__resizeListeners__ = [];
  107. (element.__resizeTriggers__ = document.createElement('div')).className = 'resize-triggers';
  108. element.__resizeTriggers__.innerHTML = '<div class="expand-trigger"><div></div></div>' +
  109. '<div class="contract-trigger"></div>';
  110. element.appendChild(element.__resizeTriggers__);
  111. resetTriggers(element);
  112. element.addEventListener('scroll', scrollListener, true);
  113. /* Listen for a css animation to detect element display/re-attach */
  114. animationstartevent && element.__resizeTriggers__.addEventListener(animationstartevent, function(e) {
  115. if(e.animationName == animationName)
  116. resetTriggers(element);
  117. });
  118. }
  119. element.__resizeListeners__.push(fn);
  120. }
  121. };
  122. window.removeResizeListener = function(element, fn){
  123. if (attachEvent) element.detachEvent('onresize', fn);
  124. else {
  125. element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1);
  126. if (!element.__resizeListeners__.length) {
  127. element.removeEventListener('scroll', scrollListener);
  128. element.__resizeTriggers__ = !element.removeChild(element.__resizeTriggers__);
  129. }
  130. }
  131. }
  132. })();