From 0a80f3ec58ab6de6e5491898bcfe263b04032ae6 Mon Sep 17 00:00:00 2001
From: Oscar Perez
Date: Wed, 7 Jan 2015 12:45:59 -0500
Subject: [PATCH 1/4] Fixed issue where the resize-trigger div would hide
sibling elements (observed in iOS WebView).
---
detect-element-resize.js | 2 +-
jquery.resize.js | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/detect-element-resize.js b/detect-element-resize.js
index cbb3c02..022a6d0 100644
--- a/detect-element-resize.js
+++ b/detect-element-resize.js
@@ -93,7 +93,7 @@
//opacity:0 works around a chrome bug https://code.google.com/p/chromium/issues/detail?id=286360
var css = (animationKeyframes ? animationKeyframes : '') +
'.resize-triggers { ' + (animationStyle ? animationStyle : '') + 'visibility: hidden; opacity: 0; } ' +
- '.resize-triggers, .resize-triggers > div, .contract-trigger:before { content: \" \"; display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; } .resize-triggers > div { background: #eee; overflow: auto; } .contract-trigger:before { width: 200%; height: 200%; }',
+ '.resize-triggers, .resize-triggers > div, .contract-trigger:before { content: \" \"; display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; z-index: -1; } .resize-triggers > div { background: #eee; overflow: auto; } .contract-trigger:before { width: 200%; height: 200%; }',
head = document.head || document.getElementsByTagName('head')[0],
style = document.createElement('style');
diff --git a/jquery.resize.js b/jquery.resize.js
index ba42a80..0186ba1 100644
--- a/jquery.resize.js
+++ b/jquery.resize.js
@@ -110,7 +110,7 @@
//opacity:0 works around a chrome bug https://code.google.com/p/chromium/issues/detail?id=286360
var css = (animationKeyframes ? animationKeyframes : '') +
'.resize-triggers { ' + (animationStyle ? animationStyle : '') + 'visibility: hidden; opacity: 0; } ' +
- '.resize-triggers, .resize-triggers > div, .contract-trigger:before { content: \" \"; display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; } .resize-triggers > div { background: #eee; overflow: auto; } .contract-trigger:before { width: 200%; height: 200%; }',
+ '.resize-triggers, .resize-triggers > div, .contract-trigger:before { content: \" \"; display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; z-index: -1; } .resize-triggers > div { background: #eee; overflow: auto; } .contract-trigger:before { width: 200%; height: 200%; }',
head = document.head || document.getElementsByTagName('head')[0],
style = document.createElement('style');
From e55cce69edefcd32ce7b6ce043c06869317281ba Mon Sep 17 00:00:00 2001
From: Drazen Pupovac
Date: Mon, 4 Sep 2017 16:48:03 +0100
Subject: [PATCH 2/4] Remove all element listeners on remove resize
---
detect-element-resize.js | 34 +++++++++++++++++++++-------------
jquery.resize.js | 40 ++++++++++++++++++++++++----------------
2 files changed, 45 insertions(+), 29 deletions(-)
diff --git a/detect-element-resize.js b/detect-element-resize.js
index cbb3c02..a710093 100644
--- a/detect-element-resize.js
+++ b/detect-element-resize.js
@@ -35,7 +35,7 @@
expandChild.style.height = expand.offsetHeight + 1 + 'px';
expand.scrollLeft = expand.scrollWidth;
expand.scrollTop = expand.scrollHeight;
- };
+ }
function checkTriggers(element){
return element.offsetWidth != element.__resizeLast__.width ||
@@ -55,7 +55,7 @@
});
}
});
- };
+ }
/* Detect CSS Animations support to detect element display/re-attach */
var animation = false,
@@ -71,11 +71,11 @@
if( animation === false ) {
for( var i = 0; i < domPrefixes.length; i++ ) {
- if( elm.style[ domPrefixes[i] + 'AnimationName' ] !== undefined ) {
- pfx = domPrefixes[ i ];
+ if( elm.style[ domPrefixes[i] + 'AnimationName'] !== undefined) {
+ pfx = domPrefixes[i];
animationstring = pfx + 'Animation';
keyframeprefix = '-' + pfx.toLowerCase() + '-';
- animationstartevent = startEvents[ i ];
+ animationstartevent = startEvents[i];
animation = true;
break;
}
@@ -108,7 +108,7 @@
stylesCreated = true;
}
}
-
+
window.addResizeListener = function(element, fn){
if (attachEvent) element.attachEvent('onresize', fn);
else {
@@ -125,10 +125,15 @@
element.addEventListener('scroll', scrollListener, true);
/* Listen for a css animation to detect element display/re-attach */
- animationstartevent && element.__resizeTriggers__.addEventListener(animationstartevent, function(e) {
- if(e.animationName == animationName)
- resetTriggers(element);
- });
+ if (animationstartevent) {
+ element.__resizeTriggers__.animationStartListener = function (e) {
+ if (e.animationName == animationName) {
+ resetTriggers(element);
+ }
+ }
+
+ element.__resizeTriggers__.addEventListener(animationstartevent, element.__resizeTriggers__.animationStartListener);
+ }
}
element.__resizeListeners__.push(fn);
}
@@ -139,9 +144,12 @@
else {
element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1);
if (!element.__resizeListeners__.length) {
- element.removeEventListener('scroll', scrollListener);
- element.__resizeTriggers__ = !element.removeChild(element.__resizeTriggers__);
+ element.removeEventListener('scroll', scrollListener, true);
+ if (animationstartevent) {
+ element.__resizeTriggers__.removeEventListener(animationstartevent, element.__resizeTriggers__.animationStartListener);
+ }
+ element.__resizeTriggers__ = !element.removeChild(element.__resizeTriggers__);
}
}
- }
+ };
})();
\ No newline at end of file
diff --git a/jquery.resize.js b/jquery.resize.js
index ba42a80..fd0cbd2 100644
--- a/jquery.resize.js
+++ b/jquery.resize.js
@@ -20,13 +20,13 @@
else
addResizeListener(this, callback);
});
- }
+ };
$.fn.removeResize = function(callback) {
return this.each(function() {
removeResizeListener(this, callback);
});
- }
+ };
if (!attachEvent) {
var requestFrame = (function(){
@@ -52,7 +52,7 @@
expandChild.style.height = expand.offsetHeight + 1 + 'px';
expand.scrollLeft = expand.scrollWidth;
expand.scrollTop = expand.scrollHeight;
- };
+ }
function checkTriggers(element){
return element.offsetWidth != element.__resizeLast__.width ||
@@ -72,7 +72,7 @@
});
}
});
- };
+ }
/* Detect CSS Animations support to detect element display/re-attach */
var animation = false,
@@ -88,11 +88,11 @@
if( animation === false ) {
for( var i = 0; i < domPrefixes.length; i++ ) {
- if( elm.style[ domPrefixes[i] + 'AnimationName' ] !== undefined ) {
- pfx = domPrefixes[ i ];
+ if( elm.style[ domPrefixes[i] + 'AnimationName'] !== undefined) {
+ pfx = domPrefixes[i];
animationstring = pfx + 'Animation';
keyframeprefix = '-' + pfx.toLowerCase() + '-';
- animationstartevent = startEvents[ i ];
+ animationstartevent = startEvents[i];
animation = true;
break;
}
@@ -125,7 +125,7 @@
stylesCreated = true;
}
}
-
+
window.addResizeListener = function(element, fn){
if (attachEvent) element.attachEvent('onresize', fn);
else {
@@ -140,12 +140,17 @@
element.appendChild(element.__resizeTriggers__);
resetTriggers(element);
element.addEventListener('scroll', scrollListener, true);
-
+
/* Listen for a css animation to detect element display/re-attach */
- animationstartevent && element.__resizeTriggers__.addEventListener(animationstartevent, function(e) {
- if(e.animationName == animationName)
- resetTriggers(element);
- });
+ if (animationstartevent) {
+ element.__resizeTriggers__.animationStartListener = function (e) {
+ if (e.animationName == animationName) {
+ resetTriggers(element);
+ }
+ }
+
+ element.__resizeTriggers__.addEventListener(animationstartevent, element.__resizeTriggers__.animationStartListener);
+ }
}
element.__resizeListeners__.push(fn);
}
@@ -156,9 +161,12 @@
else {
element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1);
if (!element.__resizeListeners__.length) {
- element.removeEventListener('scroll', scrollListener);
- element.__resizeTriggers__ = !element.removeChild(element.__resizeTriggers__);
+ element.removeEventListener('scroll', scrollListener, true);
+ if (animationstartevent) {
+ element.__resizeTriggers__.removeEventListener(animationstartevent, element.__resizeTriggers__.animationStartListener);
+ }
+ element.__resizeTriggers__ = !element.removeChild(element.__resizeTriggers__);
}
}
- }
+ };
}( jQuery ));
\ No newline at end of file
From fe7b8679990bbe2363d1ac8d9b65598d68bbfac9 Mon Sep 17 00:00:00 2001
From: Eoin Groat
Date: Fri, 26 Jan 2018 11:25:11 +0000
Subject: [PATCH 3/4] Added ES6 module version, as default, with tests
---
README.md | 14 +++
detect-element-resize.es6.js | 150 ++++++++++++++++++++++++++++++++
package.json | 2 +-
tests/tests-javascript.es6.html | 16 ++++
tests/tests-javascript.es6.js | 93 ++++++++++++++++++++
tests/tests-javascript.html | 8 +-
tests/tests-jquery.html | 8 +-
7 files changed, 282 insertions(+), 9 deletions(-)
create mode 100644 detect-element-resize.es6.js
create mode 100644 tests/tests-javascript.es6.html
create mode 100644 tests/tests-javascript.es6.js
diff --git a/README.md b/README.md
index 73278b4..d767f77 100644
--- a/README.md
+++ b/README.md
@@ -52,6 +52,20 @@ jQuery plugin library usage
```
+ES6 module usage
+----------------
+```javascript
+import Resize from 'detect-element-resize';
+
+var resizeElement = document.getElementById('resizeElement'),
+ resizeCallback = function() {
+ /* do something */
+ };
+
+Resize.addResizeListener(resizeElement, resizeCallback);
+Resize.removeResizeListener(resizeElement, resizeCallback);
+```
+
Compatibility
-------------
Works great on:
diff --git a/detect-element-resize.es6.js b/detect-element-resize.es6.js
new file mode 100644
index 0000000..19ba683
--- /dev/null
+++ b/detect-element-resize.es6.js
@@ -0,0 +1,150 @@
+/**
+* Detect Element Resize
+*
+* https://github.com/sdecima/javascript-detect-element-resize
+* Sebastian Decima
+*
+* version: 0.5.3
+**/
+
+var attachEvent = document.attachEvent,
+ stylesCreated = false;
+
+var resetTriggers, checkTriggers, scrollListener;
+
+if (!attachEvent) {
+ var requestFrame = (function(){
+ var raf = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame ||
+ function(fn){ return window.setTimeout(fn, 20); };
+ return function(fn){ return raf(fn); };
+ })();
+
+ var cancelFrame = (function(){
+ var cancel = window.cancelAnimationFrame || window.mozCancelAnimationFrame || window.webkitCancelAnimationFrame ||
+ window.clearTimeout;
+ return function(id){ return cancel(id); };
+ })();
+
+ resetTriggers = function resetTriggers(element){
+ var triggers = element.__resizeTriggers__,
+ expand = triggers.firstElementChild,
+ contract = triggers.lastElementChild,
+ expandChild = expand.firstElementChild;
+ contract.scrollLeft = contract.scrollWidth;
+ contract.scrollTop = contract.scrollHeight;
+ expandChild.style.width = expand.offsetWidth + 1 + 'px';
+ expandChild.style.height = expand.offsetHeight + 1 + 'px';
+ expand.scrollLeft = expand.scrollWidth;
+ expand.scrollTop = expand.scrollHeight;
+ };
+
+ checkTriggers = function checkTriggers(element){
+ return element.offsetWidth != element.__resizeLast__.width ||
+ element.offsetHeight != element.__resizeLast__.height;
+ }
+
+ scrollListener = function scrollListener(e){
+ var element = this;
+ resetTriggers(this);
+ if (this.__resizeRAF__) cancelFrame(this.__resizeRAF__);
+ this.__resizeRAF__ = requestFrame(function(){
+ if (checkTriggers(element)) {
+ element.__resizeLast__.width = element.offsetWidth;
+ element.__resizeLast__.height = element.offsetHeight;
+ element.__resizeListeners__.forEach(function(fn){
+ fn.call(element, e);
+ });
+ }
+ });
+ };
+
+ /* Detect CSS Animations support to detect element display/re-attach */
+ var animation = false,
+ animationstring = 'animation',
+ keyframeprefix = '',
+ animationstartevent = 'animationstart',
+ domPrefixes = 'Webkit Moz O ms'.split(' '),
+ startEvents = 'webkitAnimationStart animationstart oAnimationStart MSAnimationStart'.split(' '),
+ pfx = '';
+ {
+ var elm = document.createElement('fakeelement');
+ if( elm.style.animationName !== undefined ) { animation = true; }
+
+ if( animation === false ) {
+ for( var i = 0; i < domPrefixes.length; i++ ) {
+ if( elm.style[ domPrefixes[i] + 'AnimationName' ] !== undefined ) {
+ pfx = domPrefixes[ i ];
+ animationstring = pfx + 'Animation';
+ keyframeprefix = '-' + pfx.toLowerCase() + '-';
+ animationstartevent = startEvents[ i ];
+ animation = true;
+ break;
+ }
+ }
+ }
+ }
+
+ var animationName = 'resizeanim';
+ var animationKeyframes = '@' + keyframeprefix + 'keyframes ' + animationName + ' { from { opacity: 0; } to { opacity: 0; } } ';
+ var animationStyle = keyframeprefix + 'animation: 1ms ' + animationName + '; ';
+}
+
+function createStyles() {
+ if (!stylesCreated) {
+ //opacity:0 works around a chrome bug https://code.google.com/p/chromium/issues/detail?id=286360
+ var css = (animationKeyframes ? animationKeyframes : '') +
+ '.resize-triggers { ' + (animationStyle ? animationStyle : '') + 'visibility: hidden; opacity: 0; } ' +
+ '.resize-triggers, .resize-triggers > div, .contract-trigger:before { content: \" \"; display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; } .resize-triggers > div { background: #eee; overflow: auto; } .contract-trigger:before { width: 200%; height: 200%; }',
+ head = document.head || document.getElementsByTagName('head')[0],
+ style = document.createElement('style');
+
+ style.type = 'text/css';
+ if (style.styleSheet) {
+ style.styleSheet.cssText = css;
+ } else {
+ style.appendChild(document.createTextNode(css));
+ }
+
+ head.appendChild(style);
+ stylesCreated = true;
+ }
+}
+
+const Resize = {
+ addResizeListener: function(element, fn){
+ if (attachEvent) element.attachEvent('onresize', fn);
+ else {
+ if (!element.__resizeTriggers__) {
+ if (getComputedStyle(element).position == 'static') element.style.position = 'relative';
+ createStyles();
+ element.__resizeLast__ = {};
+ element.__resizeListeners__ = [];
+ (element.__resizeTriggers__ = document.createElement('div')).className = 'resize-triggers';
+ element.__resizeTriggers__.innerHTML = '' +
+ '';
+ element.appendChild(element.__resizeTriggers__);
+ resetTriggers(element);
+ element.addEventListener('scroll', scrollListener, true);
+
+ /* Listen for a css animation to detect element display/re-attach */
+ animationstartevent && element.__resizeTriggers__.addEventListener(animationstartevent, function(e) {
+ if(e.animationName == animationName)
+ resetTriggers(element);
+ });
+ }
+ element.__resizeListeners__.push(fn);
+ }
+ },
+ removeResizeListener: function(element, fn){
+ if (attachEvent) element.detachEvent('onresize', fn);
+ else {
+ element.__resizeListeners__.splice(element.__resizeListeners__.indexOf(fn), 1);
+ if (!element.__resizeListeners__.length) {
+ element.removeEventListener('scroll', scrollListener);
+ element.__resizeTriggers__ = !element.removeChild(element.__resizeTriggers__);
+ }
+ }
+ }
+};
+
+export default Resize;
diff --git a/package.json b/package.json
index 67c06b8..55002b3 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,7 @@
"name": "javascript-detect-element-resize",
"version": "0.5.3",
"description": "A Cross-Browser, Event-based, Element Resize Detection",
- "main": "detect-element-resize.js",
+ "main": "detect-element-resize.es6.js",
"directories": {
"test": "tests"
},
diff --git a/tests/tests-javascript.es6.html b/tests/tests-javascript.es6.html
new file mode 100644
index 0000000..7fe52e3
--- /dev/null
+++ b/tests/tests-javascript.es6.html
@@ -0,0 +1,16 @@
+
+
+
+
+ javascript-detect-element-resize Tests
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/tests-javascript.es6.js b/tests/tests-javascript.es6.js
new file mode 100644
index 0000000..6e1d471
--- /dev/null
+++ b/tests/tests-javascript.es6.js
@@ -0,0 +1,93 @@
+import Resize from '../detect-element-resize.es6.js';
+const {addResizeListener, removeResizeListener} = Resize;
+
+var container, element, content;
+
+QUnit.module('main', {
+ setup: function() {
+ var fixture = '';
+ $("#qunit-fixture").append(fixture);
+
+ container = document.getElementById('container');
+ element = document.getElementById('resizable-element');
+ content = document.getElementById('content');
+
+ $('#container').hide();
+ addResizeListener(element, detectCallback);
+ $('#container').show();
+ shouldDetect = true;
+ detected = false;
+ },
+ teardown: function() {
+ $('#styleTest').remove();
+ try {
+ removeResizeListener(element, detectCallback);
+ } catch(e) {}
+ }
+});
+
+var newWidth = 0, newHeight = 0, shouldDetect = true, detected = false;
+var detectCallback = function() {
+ detected = true;
+};
+
+var validateEvent = function(assert) {
+ setTimeout(function() {
+ if(shouldDetect) {
+ assert.ok(shouldDetect === true && detected === true, 'resize event fired OK');
+ }
+ assert.ok($(content).width() == newWidth, 'Resize OK');
+
+ QUnit.start();
+ }, 2000);
+};
+
+QUnit.asyncTest( "JS addResizeListener css resize test", function( assert ) {
+ expect( 2 );
+
+ newWidth = 100;
+
+ var myCss = '';
+ $('head').append(myCss);
+
+ validateEvent(assert);
+});
+
+QUnit.asyncTest( "JS addResizeListener script resize test", function( assert ) {
+ expect( 2 );
+
+ newWidth = 30;
+
+ $(content).width(newWidth);
+
+ validateEvent(assert);
+});
+
+QUnit.asyncTest( "JS addResizeListener script reattach element test", function( assert ) {
+ expect( 2 );
+
+ var elem = $(content).detach();
+
+ setTimeout(function() {
+ $(container).append("div").append(elem);
+ //elem.appendTo(container);
+ newWidth = 68;
+ $(content).width(newWidth);
+ }, 500);
+
+ validateEvent(assert);
+});
+
+QUnit.asyncTest( "JS removeResizeListener test", function( assert ) {
+ expect( 1 );
+
+ newWidth = 0;
+ shouldDetect = false;
+
+ removeResizeListener(element, detectCallback);
+
+ $(content).width(newWidth);
+ $(content).height(0);
+
+ validateEvent(assert);
+});
diff --git a/tests/tests-javascript.html b/tests/tests-javascript.html
index dd0f1ae..4edcdf8 100644
--- a/tests/tests-javascript.html
+++ b/tests/tests-javascript.html
@@ -3,15 +3,15 @@
javascript-detect-element-resize Tests
-
+
-
-
+
+
-