Home | History | Annotate | Download | only in src
      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 })();