|
1 | 1 | /**
|
2 |
| - * Copyright 2013 Marc J. Schmidt. See the LICENSE file at the top-level |
| 2 | + * Copyright Marc J. Schmidt. See the LICENSE file at the top-level |
3 | 3 | * directory of this distribution and at
|
4 | 4 | * https://github.com/marcj/css-element-queries/blob/master/LICENSE.
|
5 | 5 | */
|
6 | 6 | ;
|
7 | 7 | (function() {
|
8 |
| - var hasNativeResizeEvent = 'onresize' in document.createElement("span") && !(/Chrome/).test(navigator.userAgent); |
| 8 | + |
9 | 9 | /**
|
10 | 10 | * Class for dimension change detection.
|
11 | 11 | *
|
|
15 | 15 | * @constructor
|
16 | 16 | */
|
17 | 17 | this.ResizeSensor = function(element, callback) {
|
18 |
| - /** |
19 |
| - * Adds a listener to the over/under-flow event. |
20 |
| - * |
21 |
| - * @param {HTMLElement} element |
22 |
| - * @param {Function} callback |
23 |
| - */ |
24 |
| - function addResizeListener(element, callback) { |
25 |
| - if (window.OverflowEvent) { |
26 |
| - //webkit |
27 |
| - element.addEventListener('overflowchanged', function(e) { |
28 |
| - callback.call(this, e); |
29 |
| - }); |
30 |
| - } else { |
31 |
| - element.addEventListener('overflow', function(e) { |
32 |
| - callback.call(this, e); |
33 |
| - }); |
34 |
| - element.addEventListener('underflow', function(e) { |
35 |
| - callback.call(this, e); |
36 |
| - }); |
37 |
| - } |
38 |
| - } |
39 |
| - |
40 | 18 | /**
|
41 | 19 | *
|
42 | 20 | * @constructor
|
|
48 | 26 | };
|
49 | 27 |
|
50 | 28 | this.remove = function(ev) {
|
51 |
| - var index = this.q.indexOf(ev); |
52 |
| - if (index !== -1) { |
53 |
| - this.q.splice(index, 1); |
54 |
| - } |
| 29 | + var index = this.q.indexOf(ev); |
| 30 | + if (index !== -1) { |
| 31 | + this.q.splice(index, 1); |
| 32 | + } |
55 | 33 | };
|
56 | 34 |
|
57 | 35 | this.empty = function() {
|
58 |
| - return !this.q.length; |
| 36 | + return !this.q.length; |
59 | 37 | };
|
60 | 38 |
|
61 | 39 | var i, j;
|
|
81 | 59 | }
|
82 | 60 | }
|
83 | 61 |
|
84 |
| - function callEventQueue() { |
85 |
| - element.resizedAttached.call(); |
86 |
| - } |
87 |
| - |
88 | 62 | /**
|
89 | 63 | *
|
90 | 64 | * @param {HTMLElement} element
|
91 | 65 | * @param {Function} resized
|
92 | 66 | */
|
93 | 67 | function attachResizeEvent(element, resized) {
|
94 |
| - if (element.resizedAttached) { |
| 68 | + if (!element.resizedAttached) { |
| 69 | + element.resizedAttached = new EventQueue(); |
| 70 | + element.resizedAttached.add(resized); |
| 71 | + } else if (element.resizedAttached) { |
95 | 72 | element.resizedAttached.add(resized);
|
96 | 73 | return;
|
97 | 74 | }
|
98 | 75 |
|
99 |
| - element.resizedAttached = new EventQueue(); |
100 |
| - element.resizedAttached.add(resized); |
| 76 | + element.resizeSensor = document.createElement('div'); |
| 77 | + element.resizeSensor.className = 'resize-sensor'; |
| 78 | + var style = 'position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow: scroll; z-index: -1; visibility: hidden;'; |
| 79 | + var styleChild = 'position: absolute; left: 0; top: 0;'; |
| 80 | + |
| 81 | + element.resizeSensor.style.cssText = style; |
| 82 | + element.resizeSensor.innerHTML = |
| 83 | + '<div class="resize-sensor-expand" style="' + style + '">' + |
| 84 | + '<div style="' + styleChild + '"></div>' + |
| 85 | + '</div>' + |
| 86 | + '<div class="resize-sensor-shrink" style="' + style + '">' + |
| 87 | + '<div style="' + styleChild + ' width: 200%; height: 200%"></div>' + |
| 88 | + '</div>'; |
| 89 | + element.appendChild(element.resizeSensor); |
| 90 | + |
| 91 | + if ('absolute' !== getComputedStyle(element, 'position')) { |
| 92 | + element.style.position = 'relative'; |
| 93 | + } |
101 | 94 |
|
102 |
| - if (hasNativeResizeEvent) { |
103 |
| - //internet explorer |
104 |
| - if (element.attachEvent) { |
105 |
| - element.attachEvent('onresize', callEventQueue); |
106 |
| - } else if (element.addEventListener) { |
107 |
| - element.addEventListener('resize', callEventQueue); |
108 |
| - } |
109 |
| - } else { |
110 |
| - var myResized = function() { |
111 |
| - if (setupSensor()) { |
112 |
| - element.resizedAttached.call(); |
113 |
| - } |
114 |
| - }; |
115 |
| - element.resizeSensor = document.createElement('div'); |
116 |
| - element.resizeSensor.className = 'resize-sensor'; |
117 |
| - var style = |
118 |
| - 'position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow: hidden; z-index: -1;'; |
119 |
| - element.resizeSensor.style.cssText = style; |
120 |
| - element.resizeSensor.innerHTML = |
121 |
| - '<div class="resize-sensor-overflow" style="' + style + '">' + |
122 |
| - '<div></div>' + |
123 |
| - '</div>' + |
124 |
| - '<div class="resize-sensor-underflow" style="' + style + '">' + |
125 |
| - '<div></div>' + |
126 |
| - '</div>'; |
127 |
| - element.appendChild(element.resizeSensor); |
128 |
| - |
129 |
| - if ('absolute' !== getComputedStyle(element, 'position')) { |
130 |
| - element.style.position = 'relative'; |
| 95 | + var expand = element.resizeSensor.childNodes[0]; |
| 96 | + var expandChild = expand.childNodes[0]; |
| 97 | + var shrink = element.resizeSensor.childNodes[1]; |
| 98 | + |
| 99 | + var lastWidth, lastHeight; |
| 100 | + |
| 101 | + var reset = function() { |
| 102 | + expandChild.style.width = expand.offsetWidth + 10 + 'px'; |
| 103 | + expandChild.style.height = expand.offsetHeight + 10 + 'px'; |
| 104 | + expand.scrollLeft = expand.scrollWidth; |
| 105 | + expand.scrollTop = expand.scrollHeight; |
| 106 | + shrink.scrollLeft = shrink.scrollWidth; |
| 107 | + shrink.scrollTop = shrink.scrollHeight; |
| 108 | + lastWidth = element.offsetWidth; |
| 109 | + lastHeight = element.offsetHeight; |
| 110 | + }; |
| 111 | + |
| 112 | + reset(); |
| 113 | + |
| 114 | + var changed = function() { |
| 115 | + element.resizedAttached.call(); |
| 116 | + }; |
| 117 | + |
| 118 | + var addEvent = function(el, name, cb) { |
| 119 | + if (el.attachEvent) { |
| 120 | + el.attachEvent('on' + name, cb); |
| 121 | + } else { |
| 122 | + el.addEventListener(name, cb); |
131 | 123 | }
|
| 124 | + }; |
132 | 125 |
|
133 |
| - var x = -1, |
134 |
| - y = -1, |
135 |
| - firstStyle = element.resizeSensor.firstElementChild.firstChild.style, |
136 |
| - lastStyle = element.resizeSensor.lastElementChild.firstChild.style; |
137 |
| - |
138 |
| - function setupSensor() { |
139 |
| - var change = false, |
140 |
| - width = element.resizeSensor.offsetWidth, |
141 |
| - height = element.resizeSensor.offsetHeight; |
142 |
| - |
143 |
| - if (x != width) { |
144 |
| - firstStyle.width = (width - 1) + 'px'; |
145 |
| - lastStyle.width = (width + 1) + 'px'; |
146 |
| - change = true; |
147 |
| - x = width; |
148 |
| - } |
149 |
| - if (y != height) { |
150 |
| - firstStyle.height = (height - 1) + 'px'; |
151 |
| - lastStyle.height = (height + 1) + 'px'; |
152 |
| - change = true; |
153 |
| - y = height; |
154 |
| - } |
155 |
| - return change; |
| 126 | + addEvent(expand, 'scroll', function() { |
| 127 | + if (element.offsetWidth > lastWidth || element.offsetHeight > lastHeight) { |
| 128 | + changed(); |
156 | 129 | }
|
| 130 | + reset(); |
| 131 | + }); |
157 | 132 |
|
158 |
| - setupSensor(); |
159 |
| - addResizeListener(element.resizeSensor, myResized); |
160 |
| - addResizeListener(element.resizeSensor.firstElementChild, myResized); |
161 |
| - addResizeListener(element.resizeSensor.lastElementChild, myResized); |
162 |
| - } |
| 133 | + addEvent(shrink, 'scroll',function() { |
| 134 | + if (element.offsetWidth < lastWidth || element.offsetHeight < lastHeight) { |
| 135 | + changed(); |
| 136 | + } |
| 137 | + reset(); |
| 138 | + }); |
163 | 139 | }
|
164 | 140 |
|
165 | 141 | function detachResizeEvent(element, resized) {
|
166 |
| - element.resizedAttached.remove(resized); |
167 |
| - if (!element.resizedAttached.empty()) { |
168 |
| - return; |
169 |
| - } |
170 |
| - |
171 |
| - if (hasNativeResizeEvent) { |
172 |
| - //internet explorer |
173 |
| - if (element.detachEvent) { |
174 |
| - element.detachEvent('onresize', callEventQueue); |
175 |
| - } else if (element.removeEventListener) { |
176 |
| - element.removeEventListener('resize', callEventQueue); |
| 142 | + element.resizedAttached.remove(resized); |
| 143 | + if (!element.resizedAttached.empty()) { |
| 144 | + return; |
177 | 145 | }
|
178 |
| - } else { |
| 146 | + |
179 | 147 | var parentNode = element.resizeSensor.parentNode;
|
180 | 148 | if (parentNode) {
|
181 |
| - parentNode.removeChild(element.resizeSensor); |
| 149 | + parentNode.removeChild(element.resizeSensor); |
182 | 150 | }
|
183 |
| - } |
184 |
| - |
185 |
| - delete element.resizedAttached; |
186 |
| - delete element.resizeSensor; |
| 151 | + |
| 152 | + delete element.resizedAttached; |
| 153 | + delete element.resizeSensor; |
187 | 154 | }
|
188 | 155 |
|
189 | 156 | var isCollection = 'array' === typeof element
|
|
198 | 165 | } else {
|
199 | 166 | attachResizeEvent(element, callback);
|
200 | 167 | }
|
201 |
| - |
| 168 | + |
202 | 169 | return {
|
203 | 170 | destroy: function() {
|
204 |
| - if (isCollection) { |
205 |
| - var i = 0, j = element.length; |
206 |
| - for (; i < j; i++) { |
207 |
| - detachResizeEvent(element[i], callback); |
208 |
| - } |
209 |
| - } else { |
210 |
| - detachResizeEvent(element, callback); |
211 |
| - } |
| 171 | + if (isCollection) { |
| 172 | + var i = 0, j = element.length; |
| 173 | + for (; i < j; i++) { |
| 174 | + detachResizeEvent(element[i], callback); |
| 175 | + } |
| 176 | + } else { |
| 177 | + detachResizeEvent(element, callback); |
| 178 | + } |
212 | 179 | }
|
213 | 180 | };
|
214 |
| - } |
| 181 | + }; |
215 | 182 |
|
216 | 183 | })();
|
0 commit comments