/*! * jQuery Scrollify * Version 1.0.14 * * Requires: * - jQuery 1.7 or higher * * https://github.com/lukehaas/Scrollify * * Copyright 2016, Luke Haas * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. if touchScroll is false - update index */ (function (global,factory) { "use strict"; if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. define(['jquery'], function($) { return factory($, global, global.document); }); } else if (typeof module === 'object' && module.exports) { // Node/CommonJS module.exports = factory(require('jquery'), global, global.document); } else { // Browser globals 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), 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', settings = { //section should be an identifier that is the same for each section 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 animateScroll(index,instant,callbacks,toTop) { if(currentIndex===index) { callbacks = false; } if(disabled===true) { return true; } if(names[index]) { scrollable = false; if(callbacks) { settings.before(index,elements); } interstitialIndex = 1; destination = heights[index]; if(firstLoad===false && currentIndex>index && toTop===false) { //We're going backwards if(overflow[index]) { interstitialIndex = parseInt(elements[index].outerHeight()/$window.height()); destination = parseInt(heights[index])+(elements[index].outerHeight()-$window.height()); } } 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]; } } if(firstLoad) { settings.afterRender(); firstLoad = false; } 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) { //instant,callbacks 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; //instant,callbacks 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(;iindex) || atTop()) { index = closest; //index, instant, callbacks, toTop 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 = e.originalEvent.wheelDelta || -e.originalEvent.deltaY || -e.originalEvent.detail; var delta = Math.max(-1, Math.min(1, value)); //delta = delta || -e.originalEvent.detail / 3 || e.originalEvent.wheelDelta / 120; if(scrollSamples.length > 149){ scrollSamples.shift(); } //scrollSamples.push(Math.abs(delta*10)); scrollSamples.push(Math.abs(value)); if((currentScrollTime-scrollTime) > 200){ scrollSamples = []; } scrollTime = currentScrollTime; if(locked) { return false; } if(delta<0) { if(index0) { if(index>0) { if(atTop()) { if(isAccelerating(scrollSamples)) { e.preventDefault(); index--; locked = true; //index, instant, callbacks, toTop animateScroll(index,false,true, false); } else { return false } } } } }, keyHandler:function(e) { if(disabled===true) { return true; } if(locked===true) { return false; } if(e.keyCode==38 || e.keyCode==33) { if(index>0) { if(atTop()) { e.preventDefault(); index--; //index, instant, callbacks, toTop animateScroll(index,false,true,false); } } } else if(e.keyCode==40 || e.keyCode==34) { if(indexMath.abs(swipeScroll.touches.touchstart.x-swipeScroll.touches.touchmove.x))) { //if(!overflow[index]) { 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(indexinterstitialIndex) { interstitialScroll(parseInt(heights[index])+($window.height()*interstitialIndex)); interstitialIndex += 1; } else { interstitialScroll(parseInt(heights[index])+(elements[index].outerHeight()-$window.height())); } } } }, up: function() { if(index>=0) { if(atTop() && index>0) { index--; //index, instant, callbacks, toTop animateScroll(index,false,true,false); } else { if(interstitialIndex>2) { interstitialIndex -= 1; interstitialScroll(parseInt(heights[index])+($window.height()*interstitialIndex)); } else { interstitialIndex = 1; interstitialScroll(parseInt(heights[index])); } } } }, init: function() { if (document.addEventListener && settings.touchScroll) { document.addEventListener('touchstart', swipeScroll.touchHandler, false); document.addEventListener('touchmove', swipeScroll.touchHandler, false); document.addEventListener('touchend', swipeScroll.touchHandler, false); } } }; util = { refresh:function(withCallback,scroll) { clearTimeout(timeoutId2); timeoutId2 = setTimeout(function() { //retain position sizePanels(true); //scroll, firstLoad calculatePositions(scroll,false); if(withCallback) { settings.afterResize(); } },400); }, handleUpdate:function() { //callbacks, scroll //changed from false,true to false,false util.refresh(false,false); }, handleResize:function() { //callbacks, scroll util.refresh(true,false); }, handleOrientation:function() { //callbacks, scroll util.refresh(true,true); } }; settings = $.extend(settings, options); //retain position sizePanels(false); calculatePositions(false,true); if(true===hasLocation) { //index, instant, callbacks, toTop animateScroll(index,false,true,true); } else { setTimeout(function() { //instant,callbacks 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; } $(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()<$window.height()) || $this.css("overflow")==="hidden") { $this.css({"height":$window.height()}); overflow[i] = false; } else { $this.css({"height":$this.height()}); if(settings.overflowScroll) { overflow[i] = true; } else { overflow[i] = false; } } } } else { if(($this.outerHeight()<$window.height()) || (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) { //index, instant, callbacks, toTop 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(); if(top=0;z--) { if(typeof panel === 'string') { if (names[z]===panel) { index = z; //index, instant, callbacks, toTop animateScroll(z,instant,true,true); } } else { if(z===panel) { index = z; //index, instant, callbacks, toTop animateScroll(z,instant,true,true); } } } } scrollify.move = function(panel) { if(panel===undefined) { return false; } if(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(index0) { index -= 1; //index, instant, callbacks, toTop animateScroll(index,false,true,true); } }; scrollify.instantNext = function() { if(index0) { index -= 1; //index, instant, callbacks, toTop 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.off(wheelEvent,manualScroll.wheelHandler); $window.off('keydown', manualScroll.keyHandler); if (document.addEventListener && settings.touchScroll) { document.removeEventListener('touchstart', swipeScroll.touchHandler, false); document.removeEventListener('touchmove', swipeScroll.touchHandler, false); document.removeEventListener('touchend', swipeScroll.touchHandler, false); } heights = []; names = []; elements = []; overflow = []; }; scrollify.update = function() { if(!initialised) { return false; } util.handleUpdate(); }; scrollify.current = function() { return elements[index]; }; scrollify.disable = function() { disabled = true; }; scrollify.enable = function() { disabled = false; if (initialised) { //instant,callbacks 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; }));