diff --git a/src/ResizeSensor.js b/src/ResizeSensor.js
index 648a713..5196def 100755
--- a/src/ResizeSensor.js
+++ b/src/ResizeSensor.js
@@ -4,49 +4,18 @@
* https://github.com/marcj/css-element-queries/blob/master/LICENSE.
*/
;
-(function (root, factory) {
- if (typeof define === "function" && define.amd) {
+(function ( root, factory ) {
+ if ( typeof define === "function" && define.amd ) {
define(factory);
- } else if (typeof exports === "object") {
+ } else if ( typeof exports === "object" ) {
module.exports = factory();
} else {
root.ResizeSensor = factory();
}
-}(this, function () {
-
- // Only used for the dirty checking, so the event callback count is limted to max 1 call per fps per sensor.
- // In combination with the event based resize sensor this saves cpu time, because the sensor is too fast and
- // would generate too many unnecessary events.
- var requestAnimationFrame = window.requestAnimationFrame ||
- window.mozRequestAnimationFrame ||
- window.webkitRequestAnimationFrame ||
- function (fn) {
- return window.setTimeout(fn, 20);
- };
+}( this, function () {
- /**
- * Iterate over each of the provided element(s).
- *
- * @param {HTMLElement|HTMLElement[]} elements
- * @param {Function} callback
- */
- function forEachElement(elements, callback){
- var elementsType = Object.prototype.toString.call(elements);
- var isCollectionTyped = ('[object Array]' === elementsType
- || ('[object NodeList]' === elementsType)
- || ('[object HTMLCollection]' === elementsType)
- || ('undefined' !== typeof jQuery && elements instanceof jQuery) //jquery
- || ('undefined' !== typeof Elements && elements instanceof Elements) //mootools
- );
- var i = 0, j = elements.length;
- if (isCollectionTyped) {
- for (; i < j; i++) {
- callback(elements[i]);
- }
- } else {
- callback(elements);
- }
- }
+
+ var events = new EventQueue();
/**
* Class for dimension change detection.
@@ -56,163 +25,270 @@
*
* @constructor
*/
- var ResizeSensor = function(element, callback) {
- /**
- *
- * @constructor
- */
- function EventQueue() {
- var q = [];
- this.add = function(ev) {
- q.push(ev);
- };
-
- var i, j;
- this.call = function() {
- for (i = 0, j = q.length; i < j; i++) {
- q[i].call();
- }
- };
+ var ResizeSensor = function ( element, callback ) {
+ var that = this;
- this.remove = function(ev) {
- var newQueue = [];
- for(i = 0, j = q.length; i < j; i++) {
- if(q[i] !== ev) newQueue.push(q[i]);
- }
- q = newQueue;
- }
+ // Add class variables here
+ that.element = element;
+ that.callback = callback;
- this.length = function() {
- return q.length;
+ forEachElement( element, function( elem ){
+ if( !elem.resizeSensor ) {
+ appendDetectors( that, elem );
}
+
+ events.add( elem, callback );
+ });
+ };
+
+ ResizeSensor.prototype = {
+ constructor: ResizeSensor,
+
+ detach: function ResizeSensorDetach ( ev, element ) {
+ ResizeSensor.detach( element || this.element, ev );
+ },
+
+ reset: function ResizeSensorResize () {
+ forEachElement( element, function( elem ){
+ if( elem.resizeSensor ) {
+ reset( that, elem );
+ }
+ });
}
+ };
- /**
- * @param {HTMLElement} element
- * @param {String} prop
- * @returns {String|Number}
- */
- function getComputedStyle(element, prop) {
- if (element.currentStyle) {
- return element.currentStyle[prop];
- } else if (window.getComputedStyle) {
- return window.getComputedStyle(element, null).getPropertyValue(prop);
- } else {
- return element.style[prop];
- }
+ /**
+ * Function for appending the detectors to the elements
+ */
+ function appendDetectors ( that, element ) {
+ var style = 'display: block; position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow: scroll; z-index: -1; visibility: hidden;',
+ styleChild = 'position: absolute; left: 0; top: 0; transition: 0s;';
+
+ // Set the elements position to enable the ability to use top/right/bottom/left
+ if ( getComputedStyle(element, 'position') == 'static' ) {
+ element.style.position = 'relative';
}
- /**
- *
- * @param {HTMLElement} element
- * @param {Function} resized
- */
- function attachResizeEvent(element, resized) {
- if (!element.resizedAttached) {
- element.resizedAttached = new EventQueue();
- element.resizedAttached.add(resized);
- } else if (element.resizedAttached) {
- element.resizedAttached.add(resized);
- return;
- }
+ // Create the sensor element and set the styles and innerHTML
+ var rSE = document.createElement( 'resize-sensor' );
+ rSE.className = 'resize-sensor';
- element.resizeSensor = document.createElement('div');
- element.resizeSensor.className = 'resize-sensor';
- var style = 'position: absolute; left: 0; top: 0; right: 0; bottom: 0; overflow: hidden; z-index: -1; visibility: hidden;';
- var styleChild = 'position: absolute; left: 0; top: 0; transition: 0s;';
-
- element.resizeSensor.style.cssText = style;
- element.resizeSensor.innerHTML =
- '
' +
- '';
- element.appendChild(element.resizeSensor);
-
- if (getComputedStyle(element, 'position') == 'static') {
- element.style.position = 'relative';
- }
+ rSE.style.cssText = style;
+ rSE.innerHTML =
+ '' +
+ ''
- var expand = element.resizeSensor.childNodes[0];
- var expandChild = expand.childNodes[0];
- var shrink = element.resizeSensor.childNodes[1];
+ rSE.element = element;
+
+ rSE.resetting = false;
- var reset = function() {
- expandChild.style.width = 100000 + 'px';
- expandChild.style.height = 100000 + 'px';
+ rSE.lastWidth = element.offsetWidth;
+ rSE.lastHeight = element.offsetHeight;
+ rSE.cacheWidth = null;
+ rSE.cacheHeight = null;
- expand.scrollLeft = 100000;
- expand.scrollTop = 100000;
+ rSE.expand = rSE.childNodes[0];
+ rSE.expandChild = rSE.expand.childNodes[0];
+ rSE.shrink = rSE.childNodes[1];
+ rSE.shrinkChild = rSE.shrink.childNodes[0];
- shrink.scrollLeft = 100000;
- shrink.scrollTop = 100000;
- };
+ rSE.detach = function ResizeSensorDetach () {
+ that.detach( that.callback, element );
+ };
- reset();
- var dirty = false;
+ rSE.reset = function ResizeSensorReset () {
+ reset( rSE );
+ };
- var dirtyChecking = function() {
- if (!element.resizedAttached) return;
+ element.resizeSensor = rSE;
+
+ element.appendChild( element.resizeSensor );
+ reset( element.resizeSensor );
+ }
- if (dirty) {
- element.resizedAttached.call();
- dirty = false;
+ /**
+ * Class for event queueing and management
+ *
+ * @constructor
+ */
+ function EventQueue () {
+ var that = this,
+ q = {},
+ guid = 1;
+ this.add = function ( element, ev ) {
+ var guid = element.guid || 'rs-' + (guid++);
+ element.rsguid = guid;
+ q[guid] = q[guid] || [];
+ q[guid].push( ev );
+ };
+
+ var i, j;
+ this.call = function ( element, context, arguments ) {
+ var guid = element.rsguid || '';
+ if( !!q[guid] ) {
+ var evl = q[guid];
+ for ( i = 0, j = evl.length; i < j; i++ ) {
+ evl[i].apply( context, arguments );
}
+ }
+ };
- requestAnimationFrame(dirtyChecking);
- };
+ this.remove = function ( element, ev ) {
+ var newQueue = [];
+ if( !!q[element.rsguid] ) {
+ var evl = q[element.rsguid];
+ for( i = 0, j = evl.length; i < j; i++ ) {
+ if(evl[i] !== ev) {
+ newQueue.push( evl[i] );
+ }
+ }
+ q[element.rsguid] = newQueue;
+ }
+ };
- requestAnimationFrame(dirtyChecking);
- var lastWidth, lastHeight;
- var cachedWidth, cachedHeight; //useful to not query offsetWidth twice
+ this.length = function ( element ) {
+ if( !!q[element.rsguid] ) {
+ return q[element.rsguid].length;
+ }
+ };
+ }
- var onScroll = function() {
- if ((cachedWidth = element.offsetWidth) != lastWidth || (cachedHeight = element.offsetHeight) != lastHeight) {
- dirty = true;
- lastWidth = cachedWidth;
- lastHeight = cachedHeight;
- }
- reset();
- };
+ var collectionTypes = ['[object Array]', '[object NodeList]', '[object HTMLCollection]'];
+ /**
+ * Iterate over each of the provided element(s).
+ *
+ * @param {HTMLElement|HTMLElement[]} elements
+ * @param {Function} callback
+ */
+ function forEachElement ( elements, callback ){
+ if( !elements ) {
+ return;
+ }
+ var elementsType = Object.prototype.toString.call( elements ),
+ isVanillaCollection = collectionTypes.indexOf(elementsType) != -1,
+ isJQueryCollection = 'undefined' !== typeof Elements && elements instanceof Elements,
+ isMooToolsCollection = 'undefined' !== typeof Elements && elements instanceof Elements,
+ isCollectionTyped = isVanillaCollection || isJQueryCollection || isMooToolsCollection,
- var addEvent = function(el, name, cb) {
- if (el.attachEvent) {
- el.attachEvent('on' + name, cb);
- } else {
- el.addEventListener(name, cb);
- }
- };
+ i = 0, j = elements.length;
+ if ( isCollectionTyped ) {
+ for (; i < j; i++) {
+ callback( elements[i] );
+ }
+ } else {
+ callback( elements );
+ }
+ }
- addEvent(expand, 'scroll', onScroll);
- addEvent(shrink, 'scroll', onScroll);
+ /**
+ * @param {HTMLElement} element
+ * @param {String} prop
+ * @returns {String|Number}
+ */
+ function getComputedStyle ( element, prop ) {
+ if ( element.currentStyle ) {
+ return element.currentStyle[prop];
+ } else if ( window.getComputedStyle ) {
+ return window.getComputedStyle( element, null ).getPropertyValue( prop );
+ } else {
+ return element.style[prop];
}
+ }
- forEachElement(element, function(elem){
- attachResizeEvent(elem, callback);
- });
+ function hasClass ( element, className ) {
+ return (" "+ element.className +" ").replace(/[\n\t]/g, " ").indexOf(" "+ className +" ") > -1;
+ }
- this.detach = function(ev) {
- ResizeSensor.detach(element, ev);
- };
- };
+ function live (eventType, elementQuerySelector, cb) {
+ document.addEventListener( eventType, function (event) {
+ var qs = document.querySelectorAll(elementQuerySelector);
- ResizeSensor.detach = function(element, ev) {
- forEachElement(element, function(elem){
- if(elem.resizedAttached && typeof ev == "function"){
- elem.resizedAttached.remove(ev);
- if(elem.resizedAttached.length()) return;
+ if (qs) {
+ var el = event.target, index = -1;
+ while (el && ((index = Array.prototype.indexOf.call(qs, el)) === -1)) {
+ el = el.parentElement;
+ }
+
+ if (index > -1) {
+ cb.call(el, event);
+ }
}
- if (elem.resizeSensor) {
- elem.removeChild(elem.resizeSensor);
+ }, true );
+ }
+
+ /**
+ * Reset the size and scroll position of the resizeSensor element
+ * @param {[type]} rSE resizeSensor Element
+ */
+ function reset ( rSE ) {
+ rSE.resetting = true;
+ rSE.expandChild.style.width = '100000px';
+ rSE.expandChild.style.height = '100000px';
+
+
+ rSE.expand.scrollLeft = 100000;
+ rSE.expand.scrollTop = 100000;
+
+ rSE.shrink.scrollLeft = 100000;
+ rSE.shrink.scrollTop = 100000;
+ rSE.resetting = false;
+ }
+
+ function scrollHandler ( ev ) {
+ var
+ that = this,
+ detector = ev.target,
+
+ type,
+ rSE = detector.parentNode,
+ elem = rSE.element;
+ if( elem && !rSE.resetting ) {
+ if (
+ elem.offsetWidth != rSE.lastWidth
+ || elem.offsetHeight != rSE.lastHeight
+ ) {
+ events.call( elem, elem, [
+ ev,
+ {
+ width: rSE.offsetWidth,
+ widthDifference: rSE.offsetWidth - rSE.lastWidth,
+ height: rSE.offsetHeight,
+ heightDifference: rSE.offsetHeight - rSE.lastHeight
+ }
+ ]);
+
+ rSE.lastWidth = rSE.offsetWidth;
+ rSE.lastHeight = rSE.offsetHeight;
+ }
+ reset( rSE );
+ }
+ }
+
+ ResizeSensor.detach = function( element, ev ) {
+ forEachElement( element, function( elem ){
+ if( typeof ev == "function" ){
+ events.remove( elem, ev );
+ if( elem.resizedAttached.length( elem ) ) {
+ return;
+ }
+ }
+ if ( elem.resizeSensor ) {
+ if(elem.resizeSensor.parentNode) {
+ elem.removeChild( elem.resizeSensor );
+ }
delete elem.resizeSensor;
delete elem.resizedAttached;
}
});
};
+
+ // use only one event for all sensors
+ live( 'scroll', '.resize-sensor', scrollHandler );
return ResizeSensor;
-
}));