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})();