1/** 2 * Copyright Marc J. Schmidt. See the LICENSE file at the top-level 3 * directory of this distribution and at 4 * https://github.com/marcj/css-element-queries/blob/master/LICENSE. 5 */ 6; 7(function() { 8 9 /** 10 * Class for dimension change detection. 11 * 12 * @param {Element|Element[]|Elements|jQuery} element 13 * @param {Function} callback 14 * 15 * @constructor 16 */ 17 this.ResizeSensor = function(element, callback) { 18 /** 19 * 20 * @constructor 21 */ 22 function EventQueue() { 23 this.q = []; 24 this.add = function(ev) { 25 this.q.push(ev); 26 }; 27 28 var i, j; 29 this.call = function() { 30 for (i = 0, j = this.q.length; i < j; i++) { 31 this.q[i].call(); 32 } 33 }; 34 } 35 36 /** 37 * @param {HTMLElement} element 38 * @param {String} prop 39 * @returns {String|Number} 40 */ 41 function getComputedStyle(element, prop) { 42 if (element.currentStyle) { 43 return element.currentStyle[prop]; 44 } else if (window.getComputedStyle) { 45 return window.getComputedStyle(element, null).getPropertyValue(prop); 46 } else { 47 return element.style[prop]; 48 } 49 } 50 51 /** 52 * 53 * @param {HTMLElement} element 54 * @param {Function} resized 55 */ 56 function attachResizeEvent(element, resized) { 57 if (!element.resizedAttached) { 58 element.resizedAttached = new EventQueue(); 59 element.resizedAttached.add(resized); 60 } else if (element.resizedAttached) { 61 element.resizedAttached.add(resized); 62 return; 63 } 64 65 element.resizeSensor = document.createElement('div'); 66 element.resizeSensor.className = 'resize-sensor'; 67 var style = 'position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow: scroll; z-index: -1; visibility: hidden;'; 68 var styleChild = 'position: absolute; left: 0; top: 0;'; 69 70 element.resizeSensor.style.cssText = style; 71 element.resizeSensor.innerHTML = 72 '<div class="resize-sensor-expand" style="' + style + '">' + 73 '<div style="' + styleChild + '"></div>' + 74 '</div>' + 75 '<div class="resize-sensor-shrink" style="' + style + '">' + 76 '<div style="' + styleChild + ' width: 200%; height: 200%"></div>' + 77 '</div>'; 78 element.appendChild(element.resizeSensor); 79 80 if (!{fixed: 1, absolute: 1}[getComputedStyle(element, 'position')]) { 81 element.style.position = 'relative'; 82 } 83 84 var expand = element.resizeSensor.childNodes[0]; 85 var expandChild = expand.childNodes[0]; 86 var shrink = element.resizeSensor.childNodes[1]; 87 var shrinkChild = shrink.childNodes[0]; 88 89 var lastWidth, lastHeight; 90 91 var reset = function() { 92 expandChild.style.width = expand.offsetWidth + 10 + 'px'; 93 expandChild.style.height = expand.offsetHeight + 10 + 'px'; 94 expand.scrollLeft = expand.scrollWidth; 95 expand.scrollTop = expand.scrollHeight; 96 shrink.scrollLeft = shrink.scrollWidth; 97 shrink.scrollTop = shrink.scrollHeight; 98 lastWidth = element.offsetWidth; 99 lastHeight = element.offsetHeight; 100 }; 101 102 reset(); 103 104 var changed = function() { 105 if (element.resizedAttached) { 106 element.resizedAttached.call(); 107 } 108 }; 109 110 var addEvent = function(el, name, cb) { 111 if (el.attachEvent) { 112 el.attachEvent('on' + name, cb); 113 } else { 114 el.addEventListener(name, cb); 115 } 116 }; 117 118 addEvent(expand, 'scroll', function() { 119 if (element.offsetWidth > lastWidth || element.offsetHeight > lastHeight) { 120 changed(); 121 } 122 reset(); 123 }); 124 125 addEvent(shrink, 'scroll',function() { 126 if (element.offsetWidth < lastWidth || element.offsetHeight < lastHeight) { 127 changed(); 128 } 129 reset(); 130 }); 131 } 132 133 if ("[object Array]" === Object.prototype.toString.call(element) 134 || ('undefined' !== typeof jQuery && element instanceof jQuery) //jquery 135 || ('undefined' !== typeof Elements && element instanceof Elements) //mootools 136 ) { 137 var i = 0, j = element.length; 138 for (; i < j; i++) { 139 attachResizeEvent(element[i], callback); 140 } 141 } else { 142 attachResizeEvent(element, callback); 143 } 144 145 this.detach = function() { 146 ResizeSensor.detach(element); 147 }; 148 }; 149 150 this.ResizeSensor.detach = function(element) { 151 if (element.resizeSensor) { 152 element.removeChild(element.resizeSensor); 153 delete element.resizeSensor; 154 delete element.resizedAttached; 155 } 156 }; 157 158})();