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.
10 * Class for dimension change detection.
12 * @param {Element|Element[]|Elements|jQuery} element
13 * @param {Function} callback
17 this.ResizeSensor = function(element, callback) {
22 function EventQueue() {
24 this.add = function(ev) {
29 this.call = function() {
30 for (i = 0, j = this.q.length; i < j; i++) {
37 * @param {HTMLElement} element
38 * @param {String} prop
39 * @returns {String|Number}
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);
47 return element.style[prop];
53 * @param {HTMLElement} element
54 * @param {Function} resized
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);
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;';
70 element.resizeSensor.style.cssText = style;
71 element.resizeSensor.innerHTML =
72 '<div class="resize-sensor-expand" style="' + style + '">' +
73 '<div style="' + styleChild + '"></div>' +
75 '<div class="resize-sensor-shrink" style="' + style + '">' +
76 '<div style="' + styleChild + ' width: 200%; height: 200%"></div>' +
78 element.appendChild(element.resizeSensor);
80 if (!{fixed: 1, absolute: 1}[getComputedStyle(element, 'position')]) {
81 element.style.position = 'relative';
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];
89 var lastWidth, lastHeight;
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;
104 var changed = function() {
105 if (element.resizedAttached) {
106 element.resizedAttached.call();
110 var addEvent = function(el, name, cb) {
111 if (el.attachEvent) {
112 el.attachEvent('on' + name, cb);
114 el.addEventListener(name, cb);
118 var onScroll = function() {
119 if (element.offsetWidth != lastWidth || element.offsetHeight != lastHeight) {
125 addEvent(expand, 'scroll', onScroll);
126 addEvent(shrink, 'scroll', onScroll);
129 var elementType = Object.prototype.toString.call(element);
130 var isCollectionTyped = ('[object Array]' === elementType
131 || ('[object NodeList]' === elementType)
132 || ('[object HTMLCollection]' === elementType)
133 || ('undefined' !== typeof jQuery && element instanceof jQuery) //jquery
134 || ('undefined' !== typeof Elements && element instanceof Elements) //mootools
137 if (isCollectionTyped) {
138 var i = 0, j = element.length;
140 attachResizeEvent(element[i], callback);
143 attachResizeEvent(element, callback);
146 this.detach = function() {
147 if (isCollectionTyped) {
148 var i = 0, j = element.length;
150 ResizeSensor.detach(element[i]);
153 ResizeSensor.detach(element);
158 this.ResizeSensor.detach = function(element) {
159 if (element.resizeSensor) {
160 element.removeChild(element.resizeSensor);
161 delete element.resizeSensor;
162 delete element.resizedAttached;