(function (global,factory){
"use strict";
if(typeof define==='function'&&define.amd){
define(['jquery'], function($){
return factory($, global, global.document);
});
}else if(typeof module==='object'&&module.exports){
module.exports=factory(require('jquery'), global, global.document);
}else{
factory(jQuery, global, global.document);
}}(typeof window!=='undefined' ? window:this, function ($, window, document, undefined){
"use strict";
var heights=[],
names=[],
elements=[],
overflow=[],
index=0,
currentIndex=0,
interstitialIndex=1,
hasLocation=false,
timeoutId,
timeoutId2,
$window=$(window),
portHeight,
top=$window.scrollTop(),
scrollable=false,
locked=false,
scrolled=false,
manualScroll,
swipeScroll,
util,
disabled=false,
scrollSamples=[],
scrollTime=new Date().getTime(),
firstLoad=true,
initialised=false,
destination=0,
wheelEvent='onwheel' in document ? 'wheel':document.onmousewheel!==undefined ? 'mousewheel':'DOMMouseScroll',
eventListenerOptions={ passive: false },
settings={
section: ".section",
sectionName: "section-name",
interstitialSection: "",
easing: "easeOutExpo",
scrollSpeed: 1100,
offset: 0,
scrollbars: true,
target:"html,body",
standardScrollElements: false,
setHeights: true,
overflowScroll:true,
updateHash: true,
touchScroll:true,
before:function(){},
after:function(){},
afterResize:function(){},
afterRender:function(){}};
function getportHeight(){
return (window.innerHeight + settings.offset);
}
function animateScroll(index,instant,callbacks,toTop){
if(currentIndex===index){
callbacks=false;
}
if(disabled===true){
return true;
}
if(names[index]){
scrollable=false;
if(firstLoad===true){
firstLoad=false;
settings.afterRender();
}
if(callbacks){
if(typeof settings.before=='function'&&settings.before(index,elements)===false){
return true;
}}
interstitialIndex=1;
destination=(!index) ? 0:heights[index];
if(firstLoad===false&&currentIndex>index&&toTop===false){
if(overflow[index]){
portHeight=getportHeight();
interstitialIndex=parseInt(elements[index].outerHeight()/portHeight);
destination=parseInt(heights[index])+(elements[index].outerHeight()-portHeight);
}}
if(settings.updateHash&&settings.sectionName&&!(firstLoad===true&&index===0)){
if(history.pushState){
try {
history.replaceState(null, null, names[index]);
} catch (e){
if(window.console){
console.warn("Scrollify warning: Page must be hosted to manipulate the hash value.");
}}
}else{
window.location.hash=names[index];
}}
currentIndex=index;
if(instant){
$(settings.target).stop().scrollTop(destination);
if(callbacks){
settings.after(index,elements);
}}else{
locked=true;
if($().velocity){
$(settings.target).stop().velocity('scroll', {
duration: settings.scrollSpeed,
easing: settings.easing,
offset: destination,
mobileHA: false
});
}else{
$(settings.target).stop().animate({
scrollTop: destination
}, settings.scrollSpeed,settings.easing);
}
if(window.location.hash.length&&settings.sectionName&&window.console){
try {
if($(window.location.hash).length){
console.warn("Scrollify warning: ID matches hash value - this will cause the page to anchor.");
}} catch (e){}}
$(settings.target).promise().done(function(){
locked=false;
firstLoad=false;
if(callbacks){
settings.after(index,elements);
}});
}}
}
function isAccelerating(samples){
function average(num){
var sum=0;
var lastElements=samples.slice(Math.max(samples.length - num, 1));
for(var i=0; i < lastElements.length; i++){
sum +=lastElements[i];
}
return Math.ceil(sum/num);
}
var avEnd=average(10);
var avMiddle=average(70);
if(avEnd >=avMiddle){
return true;
}else{
return false;
}}
var scrollify=function(options){
initialised=true;
$.easing['easeOutExpo']=function(x, t, b, c, d){
return (t==d) ? b+c:c * (-Math.pow(2, -10 * t/d) + 1) + b;
};
manualScroll={
handleMousedown:function(){
if(disabled===true){
return true;
}
scrollable=false;
scrolled=false;
},
handleMouseup:function(){
if(disabled===true){
return true;
}
scrollable=true;
if(scrolled){
manualScroll.calculateNearest(false,true);
}},
handleScroll:function(){
if(disabled===true){
return true;
}
if(timeoutId){
clearTimeout(timeoutId);
}
timeoutId=setTimeout(function(){
scrolled=true;
if(scrollable===false){
return false;
}
scrollable=false;
manualScroll.calculateNearest(false,true);
}, 200);
},
calculateNearest:function(instant,callbacks){
top=$window.scrollTop();
var i=1,
max=heights.length,
closest=0,
prev=Math.abs(heights[0] - top),
diff;
for(;i<max;i++){
diff=Math.abs(heights[i] - top);
if(diff < prev){
prev=diff;
closest=i;
}}
if((atBottom()&&closest>index)||atTop()){
index=closest;
animateScroll(closest,instant,callbacks,false);
}},
wheelHandler:function(e){
if(disabled===true){
return true;
}else if(settings.standardScrollElements){
if($(e.target).is(settings.standardScrollElements)||$(e.target).closest(settings.standardScrollElements).length){
return true;
}}
if(!overflow[index]){
e.preventDefault();
}
var currentScrollTime=new Date().getTime();
e=e||window.event;
var value;
if(e.originalEvent){
value=e.originalEvent.wheelDelta||-e.originalEvent.deltaY||-e.originalEvent.detail;
}else{
value=e.wheelDelta||-e.deltaY||-e.detail;
}
var delta=Math.max(-1, Math.min(1, value));
if(scrollSamples.length > 149){
scrollSamples.shift();
}
scrollSamples.push(Math.abs(value));
if((currentScrollTime-scrollTime) > 200){
scrollSamples=[];
}
scrollTime=currentScrollTime;
if(locked){
return false;
}
if(delta<0){
if(index<heights.length-1){
if(atBottom()){
if(isAccelerating(scrollSamples)){
e.preventDefault();
index++;
locked=true;
animateScroll(index,false,true, false);
}else{
return false;
}}
}}else if(delta>0){
if(index>0){
if(atTop()){
if(isAccelerating(scrollSamples)){
e.preventDefault();
index--;
locked=true;
animateScroll(index,false,true, false);
}else{
return false
}}
}}
},
keyHandler:function(e){
if(disabled===true||document.activeElement.readOnly===false){
return true;
}else if(settings.standardScrollElements){
if($(e.target).is(settings.standardScrollElements)||$(e.target).closest(settings.standardScrollElements).length){
return true;
}}
if(locked===true){
return false;
}
if(e.keyCode==38||e.keyCode==33){
if(index>0){
if(atTop()){
e.preventDefault();
index--;
animateScroll(index,false,true,false);
}}
}else if(e.keyCode==40||e.keyCode==34){
if(index<heights.length-1){
if(atBottom()){
e.preventDefault();
index++;
animateScroll(index,false,true,false);
}}
}},
init:function(){
if(settings.scrollbars){
$window.on('mousedown', manualScroll.handleMousedown);
$window.on('mouseup', manualScroll.handleMouseup);
$window.on('scroll', manualScroll.handleScroll);
}else{
$("body").css({"overflow":"hidden"});
}
window.addEventListener(wheelEvent, manualScroll.wheelHandler, { passive: false });
$window.on('keydown', manualScroll.keyHandler);
}};
swipeScroll={
touches:{
"touchstart": {"y":-1,"x":-1},
"touchmove":{"y":-1,"x":-1},
"touchend":false,
"direction":"undetermined"
},
options:{
"distance":30,
"timeGap":800,
"timeStamp":new Date().getTime()
},
touchHandler: function(event){
if(disabled===true){
return true;
}else if(settings.standardScrollElements){
if($(event.target).is(settings.standardScrollElements)||$(event.target).closest(settings.standardScrollElements).length){
return true;
}}
var touch;
if(typeof event!=='undefined'){
if(typeof event.touches!=='undefined'){
touch=event.touches[0];
switch (event.type){
case 'touchstart':
swipeScroll.touches.touchstart.y=touch.pageY;
swipeScroll.touches.touchmove.y=-1;
swipeScroll.touches.touchstart.x=touch.pageX;
swipeScroll.touches.touchmove.x=-1;
swipeScroll.options.timeStamp=new Date().getTime();
swipeScroll.touches.touchend=false;
case 'touchmove':
swipeScroll.touches.touchmove.y=touch.pageY;
swipeScroll.touches.touchmove.x=touch.pageX;
if(swipeScroll.touches.touchstart.y!==swipeScroll.touches.touchmove.y&&(Math.abs(swipeScroll.touches.touchstart.y-swipeScroll.touches.touchmove.y)>Math.abs(swipeScroll.touches.touchstart.x-swipeScroll.touches.touchmove.x))){
event.preventDefault();
swipeScroll.touches.direction="y";
if((swipeScroll.options.timeStamp+swipeScroll.options.timeGap)<(new Date().getTime())&&swipeScroll.touches.touchend==false){
swipeScroll.touches.touchend=true;
if(swipeScroll.touches.touchstart.y > -1){
if(Math.abs(swipeScroll.touches.touchmove.y-swipeScroll.touches.touchstart.y)>swipeScroll.options.distance){
if(swipeScroll.touches.touchstart.y < swipeScroll.touches.touchmove.y){
swipeScroll.up();
}else{
swipeScroll.down();
}}
}}
}
break;
case 'touchend':
if(swipeScroll.touches[event.type]===false){
swipeScroll.touches[event.type]=true;
if(swipeScroll.touches.touchstart.y > -1&&swipeScroll.touches.touchmove.y > -1&&swipeScroll.touches.direction==="y"){
if(Math.abs(swipeScroll.touches.touchmove.y-swipeScroll.touches.touchstart.y)>swipeScroll.options.distance){
if(swipeScroll.touches.touchstart.y < swipeScroll.touches.touchmove.y){
swipeScroll.up();
}else{
swipeScroll.down();
}}
swipeScroll.touches.touchstart.y=-1;
swipeScroll.touches.touchstart.x=-1;
swipeScroll.touches.direction="undetermined";
}}
default:
break;
}}
}},
down: function(){
if(index<heights.length){
if(atBottom()&&index<heights.length-1){
index++;
animateScroll(index,false,true,false);
}else{
portHeight=getportHeight();
if(Math.floor(elements[index].height()/portHeight)>interstitialIndex){
interstitialScroll(parseInt(heights[index])+(portHeight*interstitialIndex));
interstitialIndex +=1;
}else{
interstitialScroll(parseInt(heights[index])+(elements[index].outerHeight()-portHeight));
}}
}},
up: function(){
if(index>=0){
if(atTop()&&index>0){
index--;
animateScroll(index,false,true,false);
}else{
if(interstitialIndex>2){
portHeight=getportHeight();
interstitialIndex -=1;
interstitialScroll(parseInt(heights[index])+(portHeight*interstitialIndex));
}else{
interstitialIndex=1;
interstitialScroll(parseInt(heights[index]));
}}
}},
init: function(){
if(document.addEventListener&&settings.touchScroll){
document.addEventListener('touchstart', swipeScroll.touchHandler, eventListenerOptions);
document.addEventListener('touchmove', swipeScroll.touchHandler, eventListenerOptions);
document.addEventListener('touchend', swipeScroll.touchHandler, eventListenerOptions);
}}
};
util={
refresh:function(withCallback,scroll){
clearTimeout(timeoutId2);
timeoutId2=setTimeout(function(){
sizePanels(true);
calculatePositions(scroll,false);
if(withCallback){
settings.afterResize();
}},400);
},
handleUpdate:function(){
util.refresh(false,false);
},
handleResize:function(){
util.refresh(true,false);
},
handleOrientation:function(){
util.refresh(true,true);
}};
settings=$.extend(settings, options);
sizePanels(false);
calculatePositions(false,true);
if(true===hasLocation){
animateScroll(index,false,true,true);
}else{
setTimeout(function(){
manualScroll.calculateNearest(true,false);
},200);
}
if(heights.length){
manualScroll.init();
swipeScroll.init();
$window.on("resize",util.handleResize);
if(document.addEventListener){
window.addEventListener("orientationchange", util.handleOrientation, false);
}}
function interstitialScroll(pos){
if($().velocity){
$(settings.target).stop().velocity('scroll', {
duration: settings.scrollSpeed,
easing: settings.easing,
offset: pos,
mobileHA: false
});
}else{
$(settings.target).stop().animate({
scrollTop: pos
}, settings.scrollSpeed,settings.easing);
}}
function sizePanels(keepPosition){
if(keepPosition){
top=$window.scrollTop();
}
var selector=settings.section;
overflow=[];
if(settings.interstitialSection.length){
selector +="," + settings.interstitialSection;
}
if(settings.scrollbars===false){
settings.overflowScroll=false;
}
portHeight=getportHeight();
$(selector).each(function(i){
var $this=$(this);
if(settings.setHeights){
if($this.is(settings.interstitialSection)){
overflow[i]=false;
}else{
if(($this.css("height","auto").outerHeight()<portHeight)||$this.css("overflow")==="hidden"){
$this.css({"height":portHeight});
overflow[i]=false;
}else{
$this.css({"height":$this.outerHeight()});
if(settings.overflowScroll){
overflow[i]=true;
}else{
overflow[i]=false;
}}
}}else{
if(($this.outerHeight()<portHeight)||(settings.overflowScroll===false)){
overflow[i]=false;
}else{
overflow[i]=true;
}}
});
if(keepPosition){
$window.scrollTop(top);
}}
function calculatePositions(scroll,firstLoad){
var selector=settings.section;
if(settings.interstitialSection.length){
selector +="," + settings.interstitialSection;
}
heights=[];
names=[];
elements=[];
$(selector).each(function(i){
var $this=$(this);
if(i>0){
heights[i]=parseInt($this.offset().top) + settings.offset;
}else{
heights[i]=parseInt($this.offset().top);
}
if(settings.sectionName&&$this.data(settings.sectionName)){
names[i]="#" + $this.data(settings.sectionName).toString().replace(/ /g,"-");
}else{
if($this.is(settings.interstitialSection)===false){
names[i]="#" + (i + 1);
}else{
names[i]="#";
if(i===$(selector).length-1&&i>1){
heights[i]=heights[i-1] + (parseInt($($(selector)[i-1]).outerHeight()) - parseInt($(window).height())) + parseInt($this.outerHeight());
}}
}
elements[i]=$this;
try {
if($(names[i]).length&&window.console){
console.warn("Scrollify warning: Section names can't match IDs - this will cause the browser to anchor.");
}} catch (e){}
if(window.location.hash===names[i]){
index=i;
hasLocation=true;
}});
if(true===scroll){
animateScroll(index,false,false,false);
}}
function atTop(){
if(!overflow[index]){
return true;
}
top=$window.scrollTop();
if(top>parseInt(heights[index])){
return false;
}else{
return true;
}}
function atBottom(){
if(!overflow[index]){
return true;
}
top=$window.scrollTop();
portHeight=getportHeight();
if(top<parseInt(heights[index])+(elements[index].outerHeight()-portHeight)-28){
return false;
}else{
return true;
}}
}
function move(panel,instant){
var z=names.length;
for(;z>=0;z--){
if(typeof panel==='string'){
if(names[z]===panel){
index=z;
animateScroll(z,instant,true,true);
}}else{
if(z===panel){
index=z;
animateScroll(z,instant,true,true);
}}
}}
scrollify.move=function(panel){
if(panel===undefined){
return false;
}
if(typeof panel!=="number"&&panel.originalEvent){
panel=$(this).attr("href");
}
move(panel,false);
};
scrollify.instantMove=function(panel){
if(panel===undefined){
return false;
}
move(panel,true);
};
scrollify.next=function(){
if(index<names.length){
index +=1;
animateScroll(index,false,true,true);
}};
scrollify.previous=function(){
if(index>0){
index -=1;
animateScroll(index,false,true,true);
}};
scrollify.instantNext=function(){
if(index<names.length){
index +=1;
animateScroll(index,true,true,true);
}};
scrollify.instantPrevious=function(){
if(index>0){
index -=1;
animateScroll(index,true,true,true);
}};
scrollify.destroy=function(){
if(!initialised){
return false;
}
if(settings.setHeights){
$(settings.section).each(function(){
$(this).css("height","auto");
});
}
$window.off("resize",util.handleResize);
if(settings.scrollbars){
$window.off('mousedown', manualScroll.handleMousedown);
$window.off('mouseup', manualScroll.handleMouseup);
$window.off('scroll', manualScroll.handleScroll);
}
window.removeEventListener(wheelEvent,manualScroll.wheelHandler);
$window.off('keydown', manualScroll.keyHandler);
if(document.addEventListener&&settings.touchScroll){
document.removeEventListener('touchstart', swipeScroll.touchHandler, eventListenerOptions);
document.removeEventListener('touchmove', swipeScroll.touchHandler, eventListenerOptions);
document.removeEventListener('touchend', swipeScroll.touchHandler, eventListenerOptions);
}
heights=[];
names=[];
elements=[];
overflow=[];
firstLoad=true;
initialised=false;
};
scrollify.update=function(){
if(!initialised){
return false;
}
util.handleUpdate();
};
scrollify.current=function(){
return elements[index];
};
scrollify.currentIndex=function(){
return index;
};
scrollify.disable=function(){
disabled=true;
};
scrollify.enable=function(){
disabled=false;
if(initialised){
manualScroll.calculateNearest(false,false);
}};
scrollify.isDisabled=function(){
return disabled;
};
scrollify.setOptions=function(updatedOptions){
if(!initialised){
return false;
}
if(typeof updatedOptions==="object"){
settings=$.extend(settings, updatedOptions);
util.handleUpdate();
}else if(window.console){
console.warn("Scrollify warning: setOptions expects an object.");
}};
$.scrollify=scrollify;
return scrollify;
}));