Browse Source

Merge pull request #39 from raphaeleidus/unload_on_scrollout

Unload on scrollout
pull/46/merge
Todd Motto 11 years ago
parent
commit
16f5237837
  1. 37
      README.md
  2. 87
      dist/echo.js
  3. 2
      dist/echo.min.js
  4. 87
      src/echo.js

37
README.md

@ -17,7 +17,9 @@ Using Echo.js is simple, just add the image you wish to load to a `data-echo` a
<script>
Echo.init({
offset: 100,
throttle: 250
throttle: 250,
unload: false,
callback: function(element, op){ console.log(element, "has been", op+'ed')}
});
// Echo.render(); is also available for non-scroll callbacks
@ -32,17 +34,46 @@ The `init()` API takes a few options
#### offset
Type: `Number|String` Default: `0`
The `offset` option allows you to specify how far below the viewport you want Echo to _begin_ loading your images. If you specify `0`, Echo will load your image as soon as it is visible in the viewport, if you want to load _1000px_ below the viewport, use `1000`.
The `offset` option allows you to specify how far below and above the viewport you want Echo to _begin_ loading your images. If you specify `0`, Echo will load your image as soon as it is visible in the viewport, if you want to load _1000px_ below or above the viewport, use `1000`.
#### offsetTop
Type: `Number|String` Default: `offset`'s value
The `offsetTop` option allows you to specify how far above the viewport you want Echo to _begin_ loading your images.
#### offsetBot
Type: `Number|String` Default: `offset`'s value
The `offsetBot` option allows you to specify how far below the viewport you want Echo to _begin_ loading your images.
#### throttle
Type: `Number|String` Default: `250`
The throttle is managed by an internal function that prevents performance issues from continuous firing of `window.onscroll` events. Using a throttle will set a small timeout when the user scrolls and will keep throttling until the user stops. The default is `250` milliseconds.
#### unload
Type: `Boolean` Default: `false`
This option will tell echo to unload loaded images once they have scrolled beyond the viewport (including the offset area).
This option requires the `placeholder` option also be set.
#### callback
Type: `Function`
The callback will be passed the element that has become in view just after the src has been replaced. This can be useful if you want to add a class like `loaded` to the element
The callback will be passed the element that has been updated and what the update operation was (ie `load` or `unload`). This can be useful if you want to add a class like `loaded` to the element. Or do some logging.
```js
Echo.init({
callback: function(element, op) {
if(op === 'load') {
elemend.classList.add('loaded');
} else {
elemend.classList.remove('loaded');
}
}
});
```
## .render() API

87
dist/echo.js vendored

@ -4,10 +4,16 @@ window.Echo = (function (global, document, undefined) {
'use strict';
/**
* store
* toBeLoaded
* @type {Array}
*/
var store = [];
var toBeLoaded = [];
/**
* toBeUnloaded
* @type {Array}
*/
var toBeUnloaded = [];
/**
* callback - initialized to a no-op so that no validations on it's presence need to be made
@ -16,9 +22,9 @@ window.Echo = (function (global, document, undefined) {
var callback = function(){};
/**
* offset, throttle, poll, vars
* offsetBot, offsetTop throttle, poll, unload vars
*/
var offset, throttle, poll;
var offsetBot, offsetTop, throttle, poll, unload;
/**
* _inView
@ -28,7 +34,9 @@ window.Echo = (function (global, document, undefined) {
*/
var _inView = function (element) {
var coords = element.getBoundingClientRect();
return ((coords.top >= 0 && coords.left >= 0 && coords.top) <= (window.innerHeight || document.documentElement.clientHeight) + offset);
var topInView = coords.top >= 0 && coords.left >= 0 && coords.top <= (window.innerHeight || document.documentElement.clientHeight) + offsetBot && coords.top >= -1 * offsetTop;
var botInView = coords.bottom >= -1 * offsetTop && coords.left >= 0 && coords.bottom <= (window.innerHeight || document.documentElement.clientHeight) + offsetBot;
return topInView || botInView;
};
/**
@ -37,25 +45,42 @@ window.Echo = (function (global, document, undefined) {
* @private
*/
var _pollImages = function () {
var length = store.length;
if (length > 0) {
for (var i = 0; i < length; i++) {
var self = store[i];
var loadingLength = toBeLoaded.length,
unloadingLength,
i,
self;
if (loadingLength > 0) {
for (i = 0; i < loadingLength; i++) {
self = toBeLoaded[i];
if (self && _inView(self)) {
if(unload) {
self.setAttribute('data-echo-placeholder', self.src);
toBeUnloaded.push(self);
}
self.src = self.getAttribute('data-echo');
callback(self);
store.splice(i, 1);
length = store.length;
callback(self, 'load');
toBeLoaded.splice(i, 1);
loadingLength = toBeLoaded.length;
i--;
}
}
} else {
if (document.removeEventListener) {
global.removeEventListener('scroll', _throttle);
} else {
global.detachEvent('onscroll', _throttle);
}
unloadingLength = toBeUnloaded.length;
if (unloadingLength > 0) {
for(i = 0; i < unloadingLength; i++) {
self = toBeUnloaded[i];
if (self && !_inView(self)) {
self.src = self.getAttribute('data-echo-placeholder');
callback(self, 'unload');
toBeUnloaded.splice(i, 1);
unloadingLength = toBeUnloaded.length;
i--;
toBeLoaded.push(self);
}
}
clearTimeout(poll);
}
if(unloadingLength === 0 && loadingLength === 0) {
detach();
}
};
@ -73,18 +98,27 @@ window.Echo = (function (global, document, undefined) {
* @param {Object} [obj] Passed in Object with options
* @param {Number|String} [obj.throttle]
* @param {Number|String} [obj.offset]
* @param {Number|String} [obj.offsetBot]
* @param {Number|String} [obj.offsetTop]
* @param {Boolean} [obj.unload]
* @param {Function} [obj.callback]
*/
var init = function (obj) {
var nodes = document.querySelectorAll('[data-echo]');
var opts = obj || {};
offset = parseInt(opts.offset || 0);
var offset = parseInt(opts.offset || 0);
offsetBot = parseInt(opts.offsetBot || offset);
offsetTop = parseInt(opts.offsetTop || offset);
throttle = parseInt(opts.throttle || 250);
unload = !!opts.unload;
callback = opts.callback || callback;
toBeLoaded = [];
toBeUnloaded = [];
for (var i = 0; i < nodes.length; i++) {
store.push(nodes[i]);
toBeLoaded.push(nodes[i]);
}
_pollImages();
@ -99,12 +133,25 @@ window.Echo = (function (global, document, undefined) {
};
/**
* detach remove listeners
*/
var detach = function() {
if (document.removeEventListener) {
global.removeEventListener('scroll', _throttle);
} else {
global.detachEvent('onscroll', _throttle);
}
clearTimeout(poll);
};
/**
* return Public methods
* @returns {Object}
*/
return {
init: init,
detach: detach,
render: _pollImages
};

2
dist/echo.min.js vendored

@ -1,2 +1,2 @@
/*! Echo v1.5.0 | (c) 2014 @toddmotto | MIT license | github.com/toddmotto/echo */
window.Echo=function(a,b){"use strict";var c,d,e,f=[],g=function(){},h=function(a){var d=a.getBoundingClientRect();return(d.top>=0&&d.left>=0&&d.top)<=(window.innerHeight||b.documentElement.clientHeight)+c},i=function(){var c=f.length;if(c>0)for(var d=0;c>d;d++){var i=f[d];i&&h(i)&&(i.src=i.getAttribute("data-echo"),g(i),f.splice(d,1),c=f.length,d--)}else b.removeEventListener?a.removeEventListener("scroll",j):a.detachEvent("onscroll",j),clearTimeout(e)},j=function(){clearTimeout(e),e=setTimeout(i,d)},k=function(e){var h=b.querySelectorAll("[data-echo]"),k=e||{};c=parseInt(k.offset||0),d=parseInt(k.throttle||250),g=k.callback||g;for(var l=0;l<h.length;l++)f.push(h[l]);i(),b.addEventListener?(a.addEventListener("scroll",j,!1),a.addEventListener("load",j,!1)):(a.attachEvent("onscroll",j),a.attachEvent("onload",j))};return{init:k,render:i}}(this,document);
window.Echo=function(a,b){"use strict";var c,d,e,f,g,h=[],i=[],j=function(){},k=function(a){var e=a.getBoundingClientRect(),f=e.top>=0&&e.left>=0&&e.top<=(window.innerHeight||b.documentElement.clientHeight)+c&&e.top>=-1*d,g=e.bottom>=-1*d&&e.left>=0&&e.bottom<=(window.innerHeight||b.documentElement.clientHeight)+c;return f||g},l=function(){var a,b,c,d=h.length;if(d>0)for(b=0;d>b;b++)c=h[b],c&&k(c)&&(g&&(c.setAttribute("data-echo-placeholder",c.src),i.push(c)),c.src=c.getAttribute("data-echo"),j(c,"load"),h.splice(b,1),d=h.length,b--);if(a=i.length,a>0)for(b=0;a>b;b++)c=i[b],c&&!k(c)&&(c.src=c.getAttribute("data-echo-placeholder"),j(c,"unload"),i.splice(b,1),a=i.length,b--,h.push(c));0===a&&0===d&&o()},m=function(){clearTimeout(f),f=setTimeout(l,e)},n=function(f){var k=b.querySelectorAll("[data-echo]"),n=f||{},o=parseInt(n.offset||0);c=parseInt(n.offsetBot||o),d=parseInt(n.offsetTop||o),e=parseInt(n.throttle||250),g=!!n.unload,j=n.callback||j,h=[],i=[];for(var p=0;p<k.length;p++)h.push(k[p]);l(),b.addEventListener?(a.addEventListener("scroll",m,!1),a.addEventListener("load",m,!1)):(a.attachEvent("onscroll",m),a.attachEvent("onload",m))},o=function(){b.removeEventListener?a.removeEventListener("scroll",m):a.detachEvent("onscroll",m),clearTimeout(f)};return{init:n,detach:o,render:l}}(this,document);

87
src/echo.js

@ -3,10 +3,16 @@ window.Echo = (function (global, document, undefined) {
'use strict';
/**
* store
* toBeLoaded
* @type {Array}
*/
var store = [];
var toBeLoaded = [];
/**
* toBeUnloaded
* @type {Array}
*/
var toBeUnloaded = [];
/**
* callback - initialized to a no-op so that no validations on it's presence need to be made
@ -15,9 +21,9 @@ window.Echo = (function (global, document, undefined) {
var callback = function(){};
/**
* offset, throttle, poll, vars
* offsetBot, offsetTop throttle, poll, unload vars
*/
var offset, throttle, poll;
var offsetBot, offsetTop, throttle, poll, unload;
/**
* _inView
@ -27,7 +33,9 @@ window.Echo = (function (global, document, undefined) {
*/
var _inView = function (element) {
var coords = element.getBoundingClientRect();
return ((coords.top >= 0 && coords.left >= 0 && coords.top) <= (window.innerHeight || document.documentElement.clientHeight) + offset);
var topInView = coords.top >= 0 && coords.left >= 0 && coords.top <= (window.innerHeight || document.documentElement.clientHeight) + offsetBot && coords.top >= -1 * offsetTop;
var botInView = coords.bottom >= -1 * offsetTop && coords.left >= 0 && coords.bottom <= (window.innerHeight || document.documentElement.clientHeight) + offsetBot;
return topInView || botInView;
};
/**
@ -36,25 +44,42 @@ window.Echo = (function (global, document, undefined) {
* @private
*/
var _pollImages = function () {
var length = store.length;
if (length > 0) {
for (var i = 0; i < length; i++) {
var self = store[i];
var loadingLength = toBeLoaded.length,
unloadingLength,
i,
self;
if (loadingLength > 0) {
for (i = 0; i < loadingLength; i++) {
self = toBeLoaded[i];
if (self && _inView(self)) {
if(unload) {
self.setAttribute('data-echo-placeholder', self.src);
toBeUnloaded.push(self);
}
self.src = self.getAttribute('data-echo');
callback(self);
store.splice(i, 1);
length = store.length;
callback(self, 'load');
toBeLoaded.splice(i, 1);
loadingLength = toBeLoaded.length;
i--;
}
}
} else {
if (document.removeEventListener) {
global.removeEventListener('scroll', _throttle);
} else {
global.detachEvent('onscroll', _throttle);
}
unloadingLength = toBeUnloaded.length;
if (unloadingLength > 0) {
for(i = 0; i < unloadingLength; i++) {
self = toBeUnloaded[i];
if (self && !_inView(self)) {
self.src = self.getAttribute('data-echo-placeholder');
callback(self, 'unload');
toBeUnloaded.splice(i, 1);
unloadingLength = toBeUnloaded.length;
i--;
toBeLoaded.push(self);
}
}
clearTimeout(poll);
}
if(unloadingLength === 0 && loadingLength === 0) {
detach();
}
};
@ -72,18 +97,27 @@ window.Echo = (function (global, document, undefined) {
* @param {Object} [obj] Passed in Object with options
* @param {Number|String} [obj.throttle]
* @param {Number|String} [obj.offset]
* @param {Number|String} [obj.offsetBot]
* @param {Number|String} [obj.offsetTop]
* @param {Boolean} [obj.unload]
* @param {Function} [obj.callback]
*/
var init = function (obj) {
var nodes = document.querySelectorAll('img[data-echo]');
var opts = obj || {};
offset = parseInt(opts.offset || 0);
var offset = parseInt(opts.offset || 0);
offsetBot = parseInt(opts.offsetBot || offset);
offsetTop = parseInt(opts.offsetTop || offset);
throttle = parseInt(opts.throttle || 250);
unload = !!opts.unload;
callback = opts.callback || callback;
toBeLoaded = [];
toBeUnloaded = [];
for (var i = 0; i < nodes.length; i++) {
store.push(nodes[i]);
toBeLoaded.push(nodes[i]);
}
_pollImages();
@ -98,12 +132,25 @@ window.Echo = (function (global, document, undefined) {
};
/**
* detach remove listeners
*/
var detach = function() {
if (document.removeEventListener) {
global.removeEventListener('scroll', _throttle);
} else {
global.detachEvent('onscroll', _throttle);
}
clearTimeout(poll);
};
/**
* return Public methods
* @returns {Object}
*/
return {
init: init,
detach: detach,
render: _pollImages
};

Loading…
Cancel
Save