site-musique/vendor/appear/appear.js

249 lines
7.9 KiB
JavaScript
Raw Normal View History

/* appear.js 1.0.3 */
appear = (function(){
'use strict';
var scrollLastPos = null, scrollTimer = 0, scroll = {};
function track(){
var newPos = window.scrollY || window.pageYOffset; // pageYOffset for IE9
if ( scrollLastPos != null ){
scroll.velocity = newPos - scrollLastPos;
scroll.delta = (scroll.velocity >= 0) ? scroll.velocity : (-1 * scroll.velocity);
}
scrollLastPos = newPos;
if(scrollTimer){
clearTimeout(scrollTimer);
}
scrollTimer = setTimeout(function(){
scrollLastPos = null;
}, 30);
}
addEventListener('scroll', track, false);
// determine if a given element (plus an additional "bounds" area around it) is in the viewport
function viewable(el, bounds){
var rect = el.getBoundingClientRect();
return (
(rect.top + rect.height) >= 0 &&
(rect.left + rect.width) >= 0 &&
(rect.bottom - rect.height) <= ( (window.innerHeight || document.documentElement.clientHeight) + bounds) &&
(rect.right - rect.width) <= ( (window.innerWidth || document.documentElement.clientWidth) + bounds)
);
}
return function(obj){
return (function(obj){
var initd = false, elements = [], elementsLength, reappear = [],
appeared = 0, disappeared = 0, timer, deltaSet, opts = {}, done;
// handle debouncing a function for better performance on scroll
function debounce(fn, delay) {
return function () {
var self = this, args = arguments;
clearTimeout(timer);
timer = setTimeout(function () {
fn.apply(self, args);
}, delay);
};
}
// called on scroll and resize event, so debounce the actual function that does
// the heavy work of determining if an item is viewable and then "appearing" it
function checkAppear() {
if(scroll.delta < opts.delta.speed) {
if(!deltaSet) {
deltaSet = true;
doCheckAppear();
setTimeout(function(){
deltaSet = false;
}, opts.delta.timeout);
}
}
(debounce(function() {
doCheckAppear();
}, opts.debounce)());
}
function begin() {
// initial appear check before any scroll or resize event
doCheckAppear();
// add relevant listeners
addEventListener('scroll', checkAppear, false);
addEventListener('resize', checkAppear, false);
}
function end() {
elements = [];
if(timer) {
clearTimeout(timer);
}
removeListeners();
}
function removeListeners() {
removeEventListener('scroll', checkAppear, false);
removeEventListener('resize', checkAppear, false);
}
function doCheckAppear() {
if(done) {
return;
}
elements.forEach(function(n, i){
if(n && viewable(n, opts.bounds)) {
// only act if the element is eligible to reappear
if(reappear[i]) {
// mark this element as not eligible to appear
reappear[i] = false;
// increment the count of appeared items
appeared++;
// call the appear fn
if(opts.appear) {
opts.appear(n);
}
// if not tracking reappears or disappears, need to remove node here
if(!opts.disappear && !opts.reappear) {
// stop tracking this node, which is now viewable
elements[i] = null;
}
}
} else {
if(reappear[i] === false) {
if(opts.disappear) {
opts.disappear(n);
}
// increment the dissappeared count
disappeared++;
// if not tracking reappears, need to remove node here
if(!opts.reappear) {
// stop tracking this node, which is now viewable
elements[i] = null;
}
}
// element is out of view and eligible to be appeared again
reappear[i] = true;
}
});
// remove listeners if all items have (re)appeared
if(!opts.reappear && (!opts.appear || opts.appear && appeared === elementsLength) && (!opts.disappear || opts.disappear && disappeared === elementsLength)) {
// ensure done is only called once (could be called from a trailing debounce/throttle)
done = true;
removeListeners();
// all items have appeared, so call the done fn
if(opts.done){
opts.done();
}
}
}
function init() {
// make sure we only init once
if(initd) {
return;
}
initd = true;
// call the obj init fn
if(opts.init) {
opts.init();
}
// get the elements to work with
var els;
if(typeof opts.elements === 'function') {
els = opts.elements();
} else {
els = opts.elements;
}
if(els) {
// put elements into an array object to work with
elementsLength = els.length;
for(var i = 0; i < elementsLength; i += 1) {
elements.push(els[i]);
reappear.push(true);
}
begin();
}
}
return function(obj) {
obj = obj || {};
// assign the fn to execute when a node is visible
opts = {
// a function to be run when the dom is ready (allows for any setup work)
init: obj.init,
// either an array of elements or a function that will return an htmlCollection
elements: obj.elements,
// function to call when an element is "viewable", will be passed the element to work with
appear: obj.appear,
// function to call when an element is no longer "viewable", will be passed the element to work with
disappear: obj.disappear,
// function to call when all the elements have "appeared"
done: obj.done,
// keep tracking the elements
reappear: obj.reappear,
// the extra border around an element to make it viewable outside of the true viewport
bounds: obj.bounds || 0,
// the debounce timeout
debounce: obj.debounce || 50,
// appear.js will also check for items on continuous slow scrolling
// you can controll how slow the scrolling should be (deltaSpeed)
// and when it will check again (deltaTimeout) after it has inspected the dom/viewport;
delta: {
speed: obj.deltaSpeed || 50,
timeout: obj.deltaTimeout || 500
}
};
// add an event listener to init when dom is ready
addEventListener('DOMContentLoaded', init, false);
var isIE10 = false;
if (Function('/*@cc_on return document.documentMode===10@*/')()){
isIE10 = true;
}
var completeOrLoaded = document.readyState === 'complete' || document.readyState === 'loaded';
// call init if document is ready to be worked with and we missed the event
if (isIE10) {
if (completeOrLoaded) {
init();
}
} else {
if (completeOrLoaded || document.readyState === 'interactive') {
init();
}
}
return {
// manually fire check for visibility of tracked elements
trigger: function trigger(){
doCheckAppear();
},
// pause tracking of elements
pause: function pause(){
removeListeners();
},
// resume tracking of elements after a pause
resume: function resume(){
begin();
},
// provide a means to stop monitoring all elements
destroy: function destroy() {
end();
}
};
};
}()(obj));
};
}());