2 * Detect Element Resize Plugin for jQuery
4 * https://github.com/sdecima/javascript-detect-element-resize
11 var attachEvent = document.attachEvent,
12 stylesCreated = false;
14 var jQuery_resize = $.fn.resize;
16 $.fn.resize = function(callback) {
17 return this.each(function() {
19 jQuery_resize.call(jQuery(this), callback);
21 addResizeListener(this, callback);
25 $.fn.removeResize = function(callback) {
26 return this.each(function() {
27 removeResizeListener(this, callback);
32 var requestFrame = (function(){
33 var raf = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame ||
34 function(fn){ return window.setTimeout(fn, 20); };
35 return function(fn){ return raf(fn); };
38 var cancelFrame = (function(){
39 var cancel = window.cancelAnimationFrame || window.mozCancelAnimationFrame || window.webkitCancelAnimationFrame ||
41 return function(id){ return cancel(id); };
44 function resetTriggers(element){
45 var triggers = element.__resizeTriggers__,
46 expand = triggers.firstElementChild,
47 contract = triggers.lastElementChild,
48 expandChild = expand.firstElementChild;
49 contract.scrollLeft = contract.scrollWidth;
50 contract.scrollTop = contract.scrollHeight;
51 expandChild.style.width = expand.offsetWidth + 1 + 'px';
52 expandChild.style.height = expand.offsetHeight + 1 + 'px';
53 expand.scrollLeft = expand.scrollWidth;
54 expand.scrollTop = expand.scrollHeight;
57 function checkTriggers(element){
58 return element.offsetWidth != element.__resizeLast__.width ||
59 element.offsetHeight != element.__resizeLast__.height;
62 function scrollListener(e){
65 if (this.__resizeRAF__) cancelFrame(this.__resizeRAF__);
66 this.__resizeRAF__ = requestFrame(function(){
67 if (checkTriggers(element)) {
68 element.__resizeLast__.width = element.offsetWidth;
69 element.__resizeLast__.height = element.offsetHeight;
70 element.__resizeListeners__.forEach(function(fn){
77 /* Detect CSS Animations support to detect element display/re-attach */
78 var animation = false,
79 animationstring = 'animation',
81 animationstartevent = 'animationstart',
82 domPrefixes = 'Webkit Moz O ms'.split(' '),
83 startEvents = 'webkitAnimationStart animationstart oAnimationStart MSAnimationStart'.split(' '),
86 var elm = document.createElement('fakeelement');
87 if( elm.style.animationName !== undefined ) { animation = true; }
89 if( animation === false ) {
90 for( var i = 0; i < domPrefixes.length; i++ ) {
91 if( elm.style[ domPrefixes[i] + 'AnimationName' ] !== undefined ) {
92 pfx = domPrefixes[ i ];
93 animationstring = pfx + 'Animation';
94 keyframeprefix = '-' + pfx.toLowerCase() + '-';
95 animationstartevent = startEvents[ i ];
103 var animationName = 'resizeanim';
104 var animationKeyframes = '@' + keyframeprefix + 'keyframes ' + animationName + ' { from { opacity: 0; } to { opacity: 0; } } ';
105 var animationStyle = keyframeprefix + 'animation: 1ms ' + animationName + '; ';
108 function createStyles() {
109 if (!stylesCreated) {
110 //opacity:0 works around a chrome bug https://code.google.com/p/chromium/issues/detail?id=286360
111 var css = (animationKeyframes ? animationKeyframes : '') +
112 '.resize-triggers { ' + (animationStyle ? animationStyle : '') + 'visibility: hidden; opacity: 0; } ' +
113 '.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%; }',
114 head = document.head || document.getElementsByTagName('head')[0],
115 style = document.createElement('style');
117 style.type = 'text/css';
118 if (style.styleSheet) {
119 style.styleSheet.cssText = css;
121 style.appendChild(document.createTextNode(css));
124 head.appendChild(style);
125 stylesCreated = true;
129 window.addResizeListener = function(element, fn){
130 if (attachEvent) element.attachEvent('onresize', fn);
132 if (!element.__resizeTriggers__) {
133 if (getComputedStyle(element).position == 'static') element.style.position = 'relative';
135 element.__resizeLast__ = {};
136 element.__resizeListeners__ = [];
137 (element.__resizeTriggers__ = document.createElement('div')).className = 'resize-triggers';
138 element.__resizeTriggers__.innerHTML = '<div class="expand-trigger"><div></div></div>' +
139 '<div class="contract-trigger"></div>';
140 element.appendChild(element.__resizeTriggers__);
141 resetTriggers(element);
142 element.addEventListener('scroll', scrollListener, true);
144 /* Listen for a css animation to detect element display/re-attach */
145 animationstartevent && element.__resizeTriggers__.addEventListener(animationstartevent, function(e) {
146 if(e.animationName == animationName)
147 resetTriggers(element);
150 element.__resizeListeners__.push(fn);
154 window.removeResizeListener = function(element, fn){
155 if (attachEvent) element.detachEvent('onresize', fn);
157 element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1);
158 if (!element.__resizeListeners__.length) {
159 element.removeEventListener('scroll', scrollListener);
160 element.__resizeTriggers__ = !element.removeChild(element.__resizeTriggers__);