spinopel.github.io
/
script.js
3125 строк · 117.8 Кб
1/*!
2* fullPage 2.9.4
3* https://github.com/alvarotrigo/fullPage.js
4* @license MIT licensed
5*
6* Copyright (C) 2015 alvarotrigo.com - A project by Alvaro Trigo
7*/
8(function(global, factory) {9'use strict';10if (typeof define === 'function' && define.amd) {11define(['jquery'], function($) {12return factory($, global, global.document, global.Math);13});14} else if (typeof exports === "object" && exports) {15module.exports = factory(require('jquery'), global, global.document, global.Math);16} else {17factory(jQuery, global, global.document, global.Math);18}19})(typeof window !== 'undefined' ? window : this, function($, window, document, Math, undefined) {20'use strict';21
22// keeping central set of classnames and selectors23var WRAPPER = 'fullpage-wrapper';24var WRAPPER_SEL = '.' + WRAPPER;25
26// slimscroll27var SCROLLABLE = 'fp-scrollable';28var SCROLLABLE_SEL = '.' + SCROLLABLE;29
30// util31var RESPONSIVE = 'fp-responsive';32var NO_TRANSITION = 'fp-notransition';33var DESTROYED = 'fp-destroyed';34var ENABLED = 'fp-enabled';35var VIEWING_PREFIX = 'fp-viewing';36var ACTIVE = 'active';37var ACTIVE_SEL = '.' + ACTIVE;38var COMPLETELY = 'fp-completely';39var COMPLETELY_SEL = '.' + COMPLETELY;40
41// section42var SECTION_DEFAULT_SEL = '.section';43var SECTION = 'fp-section';44var SECTION_SEL = '.' + SECTION;45var SECTION_ACTIVE_SEL = SECTION_SEL + ACTIVE_SEL;46var SECTION_FIRST_SEL = SECTION_SEL + ':first';47var SECTION_LAST_SEL = SECTION_SEL + ':last';48var TABLE_CELL = 'fp-tableCell';49var TABLE_CELL_SEL = '.' + TABLE_CELL;50var AUTO_HEIGHT = 'fp-auto-height';51var AUTO_HEIGHT_SEL = '.fp-auto-height';52var NORMAL_SCROLL = 'fp-normal-scroll';53var NORMAL_SCROLL_SEL = '.fp-normal-scroll';54
55// section nav56var SECTION_NAV = 'fp-nav';57var SECTION_NAV_SEL = '#' + SECTION_NAV;58var SECTION_NAV_TOOLTIP = 'fp-tooltip';59var SECTION_NAV_TOOLTIP_SEL='.'+SECTION_NAV_TOOLTIP;60var SHOW_ACTIVE_TOOLTIP = 'fp-show-active';61
62// slide63var SLIDE_DEFAULT_SEL = '.slide';64var SLIDE = 'fp-slide';65var SLIDE_SEL = '.' + SLIDE;66var SLIDE_ACTIVE_SEL = SLIDE_SEL + ACTIVE_SEL;67var SLIDES_WRAPPER = 'fp-slides';68var SLIDES_WRAPPER_SEL = '.' + SLIDES_WRAPPER;69var SLIDES_CONTAINER = 'fp-slidesContainer';70var SLIDES_CONTAINER_SEL = '.' + SLIDES_CONTAINER;71var TABLE = 'fp-table';72
73// slide nav74var SLIDES_NAV = 'fp-slidesNav';75var SLIDES_NAV_SEL = '.' + SLIDES_NAV;76var SLIDES_NAV_LINK_SEL = SLIDES_NAV_SEL + ' a';77var SLIDES_ARROW = 'fp-controlArrow';78var SLIDES_ARROW_SEL = '.' + SLIDES_ARROW;79var SLIDES_PREV = 'fp-prev';80var SLIDES_PREV_SEL = '.' + SLIDES_PREV;81var SLIDES_ARROW_PREV = SLIDES_ARROW + ' ' + SLIDES_PREV;82var SLIDES_ARROW_PREV_SEL = SLIDES_ARROW_SEL + SLIDES_PREV_SEL;83var SLIDES_NEXT = 'fp-next';84var SLIDES_NEXT_SEL = '.' + SLIDES_NEXT;85var SLIDES_ARROW_NEXT = SLIDES_ARROW + ' ' + SLIDES_NEXT;86var SLIDES_ARROW_NEXT_SEL = SLIDES_ARROW_SEL + SLIDES_NEXT_SEL;87
88var $window = $(window);89var $document = $(document);90
91// Default options for iScroll.js used when using scrollOverflow92var iscrollOptions = {93scrollbars: true,94mouseWheel: true,95hideScrollbars: false,96fadeScrollbars: false,97disableMouse: true,98interactiveScrollbars: true99};100
101$.fn.fullpage = function(options) {102//only once my friend!103if($('html').hasClass(ENABLED)){ displayWarnings(); return; }104
105// common jQuery objects106var $htmlBody = $('html, body');107var $body = $('body');108
109var FP = $.fn.fullpage;110
111// Creating some defaults, extending them with any options that were provided112options = $.extend({113//navigation114menu: false,115anchors:[],116lockAnchors: false,117navigation: false,118navigationPosition: 'right',119navigationTooltips: [],120showActiveTooltip: false,121slidesNavigation: false,122slidesNavPosition: 'bottom',123scrollBar: false,124hybrid: false,125
126//scrolling127css3: true,128scrollingSpeed: 700,129autoScrolling: true,130fitToSection: true,131fitToSectionDelay: 1000,132easing: 'easeInOutCubic',133easingcss3: 'ease',134loopBottom: false,135loopTop: false,136loopHorizontal: true,137continuousVertical: false,138continuousHorizontal: false,139scrollHorizontally: false,140interlockedSlides: false,141dragAndMove: false,142offsetSections: false,143resetSliders: false,144fadingEffect: false,145normalScrollElements: null,146scrollOverflow: false,147scrollOverflowReset: false,148scrollOverflowHandler: iscrollHandler,149scrollOverflowOptions: null,150touchSensitivity: 5,151normalScrollElementTouchThreshold: 5,152bigSectionsDestination: null,153
154//Accessibility155keyboardScrolling: true,156animateAnchor: true,157recordHistory: true,158
159//design160controlArrows: true,161controlArrowColor: '#fff',162verticalCentered: true,163sectionsColor : [],164paddingTop: 0,165paddingBottom: 0,166fixedElements: null,167responsive: 0, //backwards compabitility with responsiveWiddth168responsiveWidth: 0,169responsiveHeight: 0,170responsiveSlides: false,171parallax: false,172parallaxOptions: {173type: 'reveal',174percentage: 62,175property: 'translate'176},177
178//Custom selectors179sectionSelector: SECTION_DEFAULT_SEL,180slideSelector: SLIDE_DEFAULT_SEL,181
182//events183afterLoad: null,184onLeave: null,185afterRender: null,186afterResize: null,187afterReBuild: null,188afterSlideLoad: null,189onSlideLeave: null,190afterResponsive: null,191
192lazyLoading: true193}, options);194
195//flag to avoid very fast sliding for landscape sliders196var slideMoving = false;197
198var isTouchDevice = navigator.userAgent.match(/(iPhone|iPod|iPad|Android|playbook|silk|BlackBerry|BB10|Windows Phone|Tizen|Bada|webOS|IEMobile|Opera Mini)/);199var isTouch = (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0) || (navigator.maxTouchPoints));200var container = $(this);201var windowsHeight = $window.height();202var isResizing = false;203var isWindowFocused = true;204var lastScrolledDestiny;205var lastScrolledSlide;206var canScroll = true;207var scrollings = [];208var controlPressed;209var startingSection;210var isScrollAllowed = {};211isScrollAllowed.m = { 'up':true, 'down':true, 'left':true, 'right':true };212isScrollAllowed.k = $.extend(true,{}, isScrollAllowed.m);213var MSPointer = getMSPointer();214var events = {215touchmove: 'ontouchmove' in window ? 'touchmove' : MSPointer.move,216touchstart: 'ontouchstart' in window ? 'touchstart' : MSPointer.down217};218
219//timeouts220var resizeId;221var afterSectionLoadsId;222var afterSlideLoadsId;223var scrollId;224var scrollId2;225var keydownId;226var originals = $.extend(true, {}, options); //deep copy227
228displayWarnings();229
230//fixing bug in iScroll with links: https://github.com/cubiq/iscroll/issues/783231iscrollOptions.click = isTouch; // see #2035232
233//extending iScroll options with the user custom ones234iscrollOptions = $.extend(iscrollOptions, options.scrollOverflowOptions);235
236//easeInOutCubic animation included in the plugin237$.extend($.easing,{ easeInOutCubic: function (x, t, b, c, d) {if ((t/=d/2) < 1) return c/2*t*t*t + b;return c/2*((t-=2)*t*t + 2) + b;}});238
239/**240* Sets the autoScroll option.
241* It changes the scroll bar visibility and the history of the site as a result.
242*/
243function setAutoScrolling(value, type){244//removing the transformation245if(!value){246silentScroll(0);247}248
249setVariableState('autoScrolling', value, type);250
251var element = $(SECTION_ACTIVE_SEL);252
253if(options.autoScrolling && !options.scrollBar){254$htmlBody.css({255'overflow' : 'hidden',256'height' : '100%'257});258
259setRecordHistory(originals.recordHistory, 'internal');260
261//for IE touch devices262container.css({263'-ms-touch-action': 'none',264'touch-action': 'none'265});266
267if(element.length){268//moving the container up269silentScroll(element.position().top);270}271
272}else{273$htmlBody.css({274'overflow' : 'visible',275'height' : 'initial'276});277
278setRecordHistory(false, 'internal');279
280//for IE touch devices281container.css({282'-ms-touch-action': '',283'touch-action': ''284});285
286//scrolling the page to the section with no animation287if (element.length) {288$htmlBody.scrollTop(element.position().top);289}290}291}292
293/**294* Defines wheter to record the history for each hash change in the URL.
295*/
296function setRecordHistory(value, type){297setVariableState('recordHistory', value, type);298}299
300/**301* Defines the scrolling speed
302*/
303function setScrollingSpeed(value, type){304setVariableState('scrollingSpeed', value, type);305}306
307/**308* Sets fitToSection
309*/
310function setFitToSection(value, type){311setVariableState('fitToSection', value, type);312}313
314/**315* Sets lockAnchors
316*/
317function setLockAnchors(value){318options.lockAnchors = value;319}320
321/**322* Adds or remove the possiblity of scrolling through sections by using the mouse wheel or the trackpad.
323*/
324function setMouseWheelScrolling(value){325if(value){326addMouseWheelHandler();327addMiddleWheelHandler();328}else{329removeMouseWheelHandler();330removeMiddleWheelHandler();331}332}333
334/**335* Adds or remove the possibility of scrolling through sections by using the mouse wheel/trackpad or touch gestures.
336* Optionally a second parameter can be used to specify the direction for which the action will be applied.
337*
338* @param directions string containing the direction or directions separated by comma.
339*/
340function setAllowScrolling(value, directions){341if(typeof directions !== 'undefined'){342directions = directions.replace(/ /g,'').split(',');343
344$.each(directions, function (index, direction){345setIsScrollAllowed(value, direction, 'm');346});347}348else if(value){349setMouseWheelScrolling(true);350addTouchHandler();351}else{352setMouseWheelScrolling(false);353removeTouchHandler();354}355}356
357/**358* Adds or remove the possibility of scrolling through sections by using the keyboard arrow keys
359*/
360function setKeyboardScrolling(value, directions){361if(typeof directions !== 'undefined'){362directions = directions.replace(/ /g,'').split(',');363
364$.each(directions, function (index, direction){365setIsScrollAllowed(value, direction, 'k');366});367}else{368options.keyboardScrolling = value;369}370}371
372/**373* Moves the page up one section.
374*/
375function moveSectionUp(){376var prev = $(SECTION_ACTIVE_SEL).prev(SECTION_SEL);377
378//looping to the bottom if there's no more sections above379if (!prev.length && (options.loopTop || options.continuousVertical)) {380prev = $(SECTION_SEL).last();381}382
383if (prev.length) {384scrollPage(prev, null, true);385}386}387
388/**389* Moves the page down one section.
390*/
391function moveSectionDown(){392var next = $(SECTION_ACTIVE_SEL).next(SECTION_SEL);393
394//looping to the top if there's no more sections below395if(!next.length &&396(options.loopBottom || options.continuousVertical)){397next = $(SECTION_SEL).first();398}399
400if(next.length){401scrollPage(next, null, false);402}403}404
405/**406* Moves the page to the given section and slide with no animation.
407* Anchors or index positions can be used as params.
408*/
409function silentMoveTo(sectionAnchor, slideAnchor){410setScrollingSpeed (0, 'internal');411moveTo(sectionAnchor, slideAnchor);412setScrollingSpeed (originals.scrollingSpeed, 'internal');413}414
415/**416* Moves the page to the given section and slide.
417* Anchors or index positions can be used as params.
418*/
419function moveTo(sectionAnchor, slideAnchor){420var destiny = getSectionByAnchor(sectionAnchor);421
422if (typeof slideAnchor !== 'undefined'){423scrollPageAndSlide(sectionAnchor, slideAnchor);424}else if(destiny.length > 0){425scrollPage(destiny);426}427}428
429/**430* Slides right the slider of the active section.
431* Optional `section` param.
432*/
433function moveSlideRight(section){434moveSlide('right', section);435}436
437/**438* Slides left the slider of the active section.
439* Optional `section` param.
440*/
441function moveSlideLeft(section){442moveSlide('left', section);443}444
445/**446* When resizing is finished, we adjust the slides sizes and positions
447*/
448function reBuild(resizing){449if(container.hasClass(DESTROYED)){ return; } //nothing to do if the plugin was destroyed450
451isResizing = true;452
453windowsHeight = $window.height(); //updating global var454
455$(SECTION_SEL).each(function(){456var slidesWrap = $(this).find(SLIDES_WRAPPER_SEL);457var slides = $(this).find(SLIDE_SEL);458
459//adjusting the height of the table-cell for IE and Firefox460if(options.verticalCentered){461$(this).find(TABLE_CELL_SEL).css('height', getTableHeight($(this)) + 'px');462}463
464$(this).css('height', windowsHeight + 'px');465
466//resizing the scrolling divs467if(options.scrollOverflow){468if(slides.length){469slides.each(function(){470createScrollBar($(this));471});472}else{473createScrollBar($(this));474}475}476
477//adjusting the position fo the FULL WIDTH slides...478if (slides.length > 1) {479landscapeScroll(slidesWrap, slidesWrap.find(SLIDE_ACTIVE_SEL));480}481});482
483var activeSection = $(SECTION_ACTIVE_SEL);484var sectionIndex = activeSection.index(SECTION_SEL);485
486//isn't it the first section?487if(sectionIndex){488//adjusting the position for the current section489silentMoveTo(sectionIndex + 1);490}491
492isResizing = false;493$.isFunction( options.afterResize ) && resizing && options.afterResize.call(container);494$.isFunction( options.afterReBuild ) && !resizing && options.afterReBuild.call(container);495}496
497/**498* Turns fullPage.js to normal scrolling mode when the viewport `width` or `height`
499* are smaller than the set limit values.
500*/
501function setResponsive(active){502var isResponsive = $body.hasClass(RESPONSIVE);503
504if(active){505if(!isResponsive){506setAutoScrolling(false, 'internal');507setFitToSection(false, 'internal');508$(SECTION_NAV_SEL).hide();509$body.addClass(RESPONSIVE);510$.isFunction( options.afterResponsive ) && options.afterResponsive.call( container, active);511}512}513else if(isResponsive){514setAutoScrolling(originals.autoScrolling, 'internal');515setFitToSection(originals.autoScrolling, 'internal');516$(SECTION_NAV_SEL).show();517$body.removeClass(RESPONSIVE);518$.isFunction( options.afterResponsive ) && options.afterResponsive.call( container, active);519}520}521
522if($(this).length){523//public functions524FP.setAutoScrolling = setAutoScrolling;525FP.setRecordHistory = setRecordHistory;526FP.setScrollingSpeed = setScrollingSpeed;527FP.setFitToSection = setFitToSection;528FP.setLockAnchors = setLockAnchors;529FP.setMouseWheelScrolling = setMouseWheelScrolling;530FP.setAllowScrolling = setAllowScrolling;531FP.setKeyboardScrolling = setKeyboardScrolling;532FP.moveSectionUp = moveSectionUp;533FP.moveSectionDown = moveSectionDown;534FP.silentMoveTo = silentMoveTo;535FP.moveTo = moveTo;536FP.moveSlideRight = moveSlideRight;537FP.moveSlideLeft = moveSlideLeft;538FP.fitToSection = fitToSection;539FP.reBuild = reBuild;540FP.setResponsive = setResponsive;541FP.destroy = destroy;542
543init();544
545bindEvents();546}547
548function init(){549//if css3 is not supported, it will use jQuery animations550if(options.css3){551options.css3 = support3d();552}553
554options.scrollBar = options.scrollBar || options.hybrid;555
556setOptionsFromDOM();557prepareDom();558setAllowScrolling(true);559setAutoScrolling(options.autoScrolling, 'internal');560responsive();561
562//setting the class for the body element563setBodyClass();564
565if(document.readyState === 'complete'){566scrollToAnchor();567}568$window.on('load', scrollToAnchor);569}570
571function bindEvents(){572$window
573//when scrolling...574.on('scroll', scrollHandler)575
576//detecting any change on the URL to scroll to the given anchor link577//(a way to detect back history button as we play with the hashes on the URL)578.on('hashchange', hashChangeHandler)579
580//when opening a new tab (ctrl + t), `control` won't be pressed when coming back.581.blur(blurHandler)582
583//when resizing the site, we adjust the heights of the sections, slimScroll...584.resize(resizeHandler);585
586$document
587//Sliding with arrow keys, both, vertical and horizontal588.keydown(keydownHandler)589
590//to prevent scrolling while zooming591.keyup(keyUpHandler)592
593//Scrolls to the section when clicking the navigation bullet594.on('click touchstart', SECTION_NAV_SEL + ' a', sectionBulletHandler)595
596//Scrolls the slider to the given slide destination for the given section597.on('click touchstart', SLIDES_NAV_LINK_SEL, slideBulletHandler)598
599.on('click', SECTION_NAV_TOOLTIP_SEL, tooltipTextHandler);600
601//Scrolling horizontally when clicking on the slider controls.602$(SECTION_SEL).on('click touchstart', SLIDES_ARROW_SEL, slideArrowHandler);603
604/**605* Applying normalScroll elements.
606* Ignoring the scrolls over the specified selectors.
607*/
608if(options.normalScrollElements){609$document.on('mouseenter', options.normalScrollElements, function () {610setMouseWheelScrolling(false);611});612
613$document.on('mouseleave', options.normalScrollElements, function(){614setMouseWheelScrolling(true);615});616}617}618
619/**620* Setting options from DOM elements if they are not provided.
621*/
622function setOptionsFromDOM(){623var sections = container.find(options.sectionSelector);624
625//no anchors option? Checking for them in the DOM attributes626if(!options.anchors.length){627options.anchors = sections.filter('[data-anchor]').map(function(){628return $(this).data('anchor').toString();629}).get();630}631
632//no tooltips option? Checking for them in the DOM attributes633if(!options.navigationTooltips.length){634options.navigationTooltips = sections.filter('[data-tooltip]').map(function(){635return $(this).data('tooltip').toString();636}).get();637}638}639
640/**641* Works over the DOM structure to set it up for the current fullpage options.
642*/
643function prepareDom(){644container.css({645'height': '100%',646'position': 'relative'647});648
649//adding a class to recognize the container internally in the code650container.addClass(WRAPPER);651$('html').addClass(ENABLED);652
653//due to https://github.com/alvarotrigo/fullPage.js/issues/1502654windowsHeight = $window.height();655
656container.removeClass(DESTROYED); //in case it was destroyed before initializing it again657
658addInternalSelectors();659
660//styling the sections / slides / menu661$(SECTION_SEL).each(function(index){662var section = $(this);663var slides = section.find(SLIDE_SEL);664var numSlides = slides.length;665
666styleSection(section, index);667styleMenu(section, index);668
669// if there's any slide670if (numSlides > 0) {671styleSlides(section, slides, numSlides);672}else{673if(options.verticalCentered){674addTableClass(section);675}676}677});678
679//fixed elements need to be moved out of the plugin container due to problems with CSS3.680if(options.fixedElements && options.css3){681$(options.fixedElements).appendTo($body);682}683
684//vertical centered of the navigation + active bullet685if(options.navigation){686addVerticalNavigation();687}688
689enableYoutubeAPI();690
691if(options.scrollOverflow){692if(document.readyState === 'complete'){693createScrollBarHandler();694}695//after DOM and images are loaded696$window.on('load', createScrollBarHandler);697}else{698afterRenderActions();699}700}701
702/**703* Styles the horizontal slides for a section.
704*/
705function styleSlides(section, slides, numSlides){706var sliderWidth = numSlides * 100;707var slideWidth = 100 / numSlides;708
709slides.wrapAll('<div class="' + SLIDES_CONTAINER + '" />');710slides.parent().wrap('<div class="' + SLIDES_WRAPPER + '" />');711
712section.find(SLIDES_CONTAINER_SEL).css('width', sliderWidth + '%');713
714if(numSlides > 1){715if(options.controlArrows){716createSlideArrows(section);717}718
719if(options.slidesNavigation){720addSlidesNavigation(section, numSlides);721}722}723
724slides.each(function(index) {725$(this).css('width', slideWidth + '%');726
727if(options.verticalCentered){728addTableClass($(this));729}730});731
732var startingSlide = section.find(SLIDE_ACTIVE_SEL);733
734//if the slide won't be an starting point, the default will be the first one735//the active section isn't the first one? Is not the first slide of the first section? Then we load that section/slide by default.736if( startingSlide.length && ($(SECTION_ACTIVE_SEL).index(SECTION_SEL) !== 0 || ($(SECTION_ACTIVE_SEL).index(SECTION_SEL) === 0 && startingSlide.index() !== 0))){737silentLandscapeScroll(startingSlide, 'internal');738}else{739slides.eq(0).addClass(ACTIVE);740}741}742
743/**744* Styling vertical sections
745*/
746function styleSection(section, index){747//if no active section is defined, the 1st one will be the default one748if(!index && $(SECTION_ACTIVE_SEL).length === 0) {749section.addClass(ACTIVE);750}751startingSection = $(SECTION_ACTIVE_SEL);752
753section.css('height', windowsHeight + 'px');754
755if(options.paddingTop){756section.css('padding-top', options.paddingTop);757}758
759if(options.paddingBottom){760section.css('padding-bottom', options.paddingBottom);761}762
763if (typeof options.sectionsColor[index] !== 'undefined') {764section.css('background-color', options.sectionsColor[index]);765}766
767if (typeof options.anchors[index] !== 'undefined') {768section.attr('data-anchor', options.anchors[index]);769}770}771
772/**773* Sets the data-anchor attributes to the menu elements and activates the current one.
774*/
775function styleMenu(section, index){776if (typeof options.anchors[index] !== 'undefined') {777//activating the menu / nav element on load778if(section.hasClass(ACTIVE)){779activateMenuAndNav(options.anchors[index], index);780}781}782
783//moving the menu outside the main container if it is inside (avoid problems with fixed positions when using CSS3 tranforms)784if(options.menu && options.css3 && $(options.menu).closest(WRAPPER_SEL).length){785$(options.menu).appendTo($body);786}787}788
789/**790* Adds internal classes to be able to provide customizable selectors
791* keeping the link with the style sheet.
792*/
793function addInternalSelectors(){794container.find(options.sectionSelector).addClass(SECTION);795container.find(options.slideSelector).addClass(SLIDE);796}797
798/**799* Creates the control arrows for the given section
800*/
801function createSlideArrows(section){802section.find(SLIDES_WRAPPER_SEL).after('<div class="' + SLIDES_ARROW_PREV + '"></div><div class="' + SLIDES_ARROW_NEXT + '"></div>');803
804if(options.controlArrowColor!='#fff'){805section.find(SLIDES_ARROW_NEXT_SEL).css('border-color', 'transparent transparent transparent '+options.controlArrowColor);806section.find(SLIDES_ARROW_PREV_SEL).css('border-color', 'transparent '+ options.controlArrowColor + ' transparent transparent');807}808
809if(!options.loopHorizontal){810section.find(SLIDES_ARROW_PREV_SEL).hide();811}812}813
814/**815* Creates a vertical navigation bar.
816*/
817function addVerticalNavigation(){818$body.append('<div id="' + SECTION_NAV + '"><ul></ul></div>');819var nav = $(SECTION_NAV_SEL);820
821nav.addClass(function() {822return options.showActiveTooltip ? SHOW_ACTIVE_TOOLTIP + ' ' + options.navigationPosition : options.navigationPosition;823});824
825for (var i = 0; i < $(SECTION_SEL).length; i++) {826var link = '';827if (options.anchors.length) {828link = options.anchors[i];829}830
831var li = '<li><a href="#' + link + '"><span></span></a>';832
833// Only add tooltip if needed (defined by user)834var tooltip = options.navigationTooltips[i];835
836if (typeof tooltip !== 'undefined' && tooltip !== '') {837li += '<div class="' + SECTION_NAV_TOOLTIP + ' ' + options.navigationPosition + '">' + tooltip + '</div>';838}839
840li += '</li>';841
842nav.find('ul').append(li);843}844
845//centering it vertically846$(SECTION_NAV_SEL).css('margin-top', '-' + ($(SECTION_NAV_SEL).height()/2) + 'px');847
848//activating the current active section849$(SECTION_NAV_SEL).find('li').eq($(SECTION_ACTIVE_SEL).index(SECTION_SEL)).find('a').addClass(ACTIVE);850}851
852/**853* Creates the slim scroll scrollbar for the sections and slides inside them.
854*/
855function createScrollBarHandler(){856$(SECTION_SEL).each(function(){857var slides = $(this).find(SLIDE_SEL);858
859if(slides.length){860slides.each(function(){861createScrollBar($(this));862});863}else{864createScrollBar($(this));865}866
867});868afterRenderActions();869}870
871/*872* Enables the Youtube videos API so we can control their flow if necessary.
873*/
874function enableYoutubeAPI(){875container.find('iframe[src*="youtube.com/embed/"]').each(function(){876addURLParam($(this), 'enablejsapi=1');877});878}879
880/**881* Adds a new parameter and its value to the `src` of a given element
882*/
883function addURLParam(element, newParam){884var originalSrc = element.attr('src');885element.attr('src', originalSrc + getUrlParamSign(originalSrc) + newParam);886}887
888/*889* Returns the prefix sign to use for a new parameter in an existen URL.
890*
891* @return {String} ? | &
892*/
893function getUrlParamSign(url){894return ( !/\?/.test( url ) ) ? '?' : '&';895}896
897/**898* Actions and callbacks to fire afterRender
899*/
900function afterRenderActions(){901var section = $(SECTION_ACTIVE_SEL);902
903section.addClass(COMPLETELY);904
905if(options.scrollOverflowHandler.afterRender){906options.scrollOverflowHandler.afterRender(section);907}908lazyLoad(section);909playMedia(section);910options.scrollOverflowHandler.afterLoad();911
912if(isDestinyTheStartingSection()){913$.isFunction( options.afterLoad ) && options.afterLoad.call(section, section.data('anchor'), (section.index(SECTION_SEL) + 1));914}915
916$.isFunction( options.afterRender ) && options.afterRender.call(container);917}918
919/**920* Determines if the URL anchor destiny is the starting section (the one using 'active' class before initialization)
921*/
922function isDestinyTheStartingSection(){923var anchors = window.location.hash.replace('#', '').split('/');924var destinationSection = getSectionByAnchor(decodeURIComponent(anchors[0]));925
926return !destinationSection.length || destinationSection.length && destinationSection.index() === startingSection.index();927}928
929
930var isScrolling = false;931var lastScroll = 0;932
933//when scrolling...934function scrollHandler(){935var currentSection;936
937if(!options.autoScrolling || options.scrollBar){938var currentScroll = $window.scrollTop();939var scrollDirection = getScrollDirection(currentScroll);940var visibleSectionIndex = 0;941var screen_mid = currentScroll + ($window.height() / 2.0);942var isAtBottom = $body.height() - $window.height() === currentScroll;943var sections = document.querySelectorAll(SECTION_SEL);944
945//when using `auto-height` for a small last section it won't be centered in the viewport946if(isAtBottom){947visibleSectionIndex = sections.length - 1;948}949//is at top? when using `auto-height` for a small first section it won't be centered in the viewport950else if(!currentScroll){951visibleSectionIndex = 0;952}953
954//taking the section which is showing more content in the viewport955else{956for (var i = 0; i < sections.length; ++i) {957var section = sections[i];958
959// Pick the the last section which passes the middle line of the screen.960if (section.offsetTop <= screen_mid)961{962visibleSectionIndex = i;963}964}965}966
967if(isCompletelyInViewPort(scrollDirection)){968if(!$(SECTION_ACTIVE_SEL).hasClass(COMPLETELY)){969$(SECTION_ACTIVE_SEL).addClass(COMPLETELY).siblings().removeClass(COMPLETELY);970}971}972
973//geting the last one, the current one on the screen974currentSection = $(sections).eq(visibleSectionIndex);975
976//setting the visible section as active when manually scrolling977//executing only once the first time we reach the section978if(!currentSection.hasClass(ACTIVE)){979isScrolling = true;980var leavingSection = $(SECTION_ACTIVE_SEL);981var leavingSectionIndex = leavingSection.index(SECTION_SEL) + 1;982var yMovement = getYmovement(currentSection);983var anchorLink = currentSection.data('anchor');984var sectionIndex = currentSection.index(SECTION_SEL) + 1;985var activeSlide = currentSection.find(SLIDE_ACTIVE_SEL);986var slideIndex;987var slideAnchorLink;988
989if(activeSlide.length){990slideAnchorLink = activeSlide.data('anchor');991slideIndex = activeSlide.index();992}993
994if(canScroll){995currentSection.addClass(ACTIVE).siblings().removeClass(ACTIVE);996
997$.isFunction( options.onLeave ) && options.onLeave.call( leavingSection, leavingSectionIndex, sectionIndex, yMovement);998$.isFunction( options.afterLoad ) && options.afterLoad.call( currentSection, anchorLink, sectionIndex);999
1000stopMedia(leavingSection);1001lazyLoad(currentSection);1002playMedia(currentSection);1003
1004activateMenuAndNav(anchorLink, sectionIndex - 1);1005
1006if(options.anchors.length){1007//needed to enter in hashChange event when using the menu with anchor links1008lastScrolledDestiny = anchorLink;1009}1010setState(slideIndex, slideAnchorLink, anchorLink, sectionIndex);1011}1012
1013//small timeout in order to avoid entering in hashChange event when scrolling is not finished yet1014clearTimeout(scrollId);1015scrollId = setTimeout(function(){1016isScrolling = false;1017}, 100);1018}1019
1020if(options.fitToSection){1021//for the auto adjust of the viewport to fit a whole section1022clearTimeout(scrollId2);1023
1024scrollId2 = setTimeout(function(){1025//checking it again in case it changed during the delay1026if(options.fitToSection){1027fitToSection();1028}1029}, options.fitToSectionDelay);1030}1031}1032}1033
1034/**1035* Fits the site to the nearest active section
1036*/
1037function fitToSection(){1038//checking fitToSection again in case it was set to false before the timeout delay1039if(canScroll){1040//allows to scroll to an active section and1041//if the section is already active, we prevent firing callbacks1042isResizing = true;1043
1044scrollPage($(SECTION_ACTIVE_SEL));1045isResizing = false;1046}1047}1048
1049/**1050* Determines whether the active section has seen in its whole or not.
1051*/
1052function isCompletelyInViewPort(movement){1053var top = $(SECTION_ACTIVE_SEL).position().top;1054var bottom = top + $window.height();1055
1056if(movement == 'up'){1057return bottom >= ($window.scrollTop() + $window.height());1058}1059return top <= $window.scrollTop();1060}1061
1062/**1063* Gets the directon of the the scrolling fired by the scroll event.
1064*/
1065function getScrollDirection(currentScroll){1066var direction = currentScroll > lastScroll ? 'down' : 'up';1067
1068lastScroll = currentScroll;1069
1070//needed for auto-height sections to determine if we want to scroll to the top or bottom of the destination1071previousDestTop = currentScroll;1072
1073return direction;1074}1075
1076/**1077* Determines the way of scrolling up or down:
1078* by 'automatically' scrolling a section or by using the default and normal scrolling.
1079*/
1080function scrolling(type, scrollable){1081if (!isScrollAllowed.m[type]){1082return;1083}1084var check = (type === 'down') ? 'bottom' : 'top';1085var scrollSection = (type === 'down') ? moveSectionDown : moveSectionUp;1086
1087if(scrollable.length > 0 ){1088//is the scrollbar at the start/end of the scroll?1089if(options.scrollOverflowHandler.isScrolled(check, scrollable)){1090scrollSection();1091}else{1092return true;1093}1094}else{1095// moved up/down1096scrollSection();1097}1098}1099
1100/*1101* Preventing bouncing in iOS #2285
1102*/
1103function preventBouncing(event){1104var e = event.originalEvent;1105if(!checkParentForNormalScrollElement(event.target) && options.autoScrolling && isReallyTouch(e)){1106//preventing the easing on iOS devices1107event.preventDefault();1108}1109}1110
1111var touchStartY = 0;1112var touchStartX = 0;1113var touchEndY = 0;1114var touchEndX = 0;1115
1116/* Detecting touch events1117
1118* As we are changing the top property of the page on scrolling, we can not use the traditional way to detect it.
1119* This way, the touchstart and the touch moves shows an small difference between them which is the
1120* used one to determine the direction.
1121*/
1122function touchMoveHandler(event){1123var e = event.originalEvent;1124var activeSection = $(e.target).closest(SECTION_SEL);1125
1126// additional: if one of the normalScrollElements isn't within options.normalScrollElementTouchThreshold hops up the DOM chain1127if (!checkParentForNormalScrollElement(event.target) && isReallyTouch(e) ) {1128
1129if(options.autoScrolling){1130//preventing the easing on iOS devices1131event.preventDefault();1132}1133
1134var scrollable = options.scrollOverflowHandler.scrollable(activeSection);1135var touchEvents = getEventsPage(e);1136
1137touchEndY = touchEvents.y;1138touchEndX = touchEvents.x;1139
1140//if movement in the X axys is greater than in the Y and the currect section has slides...1141if (activeSection.find(SLIDES_WRAPPER_SEL).length && Math.abs(touchStartX - touchEndX) > (Math.abs(touchStartY - touchEndY))) {1142
1143//is the movement greater than the minimum resistance to scroll?1144if (!slideMoving && Math.abs(touchStartX - touchEndX) > ($window.outerWidth() / 100 * options.touchSensitivity)) {1145if (touchStartX > touchEndX) {1146if(isScrollAllowed.m.right){1147moveSlideRight(activeSection); //next1148}1149} else {1150if(isScrollAllowed.m.left){1151moveSlideLeft(activeSection); //prev1152}1153}1154}1155}1156
1157//vertical scrolling (only when autoScrolling is enabled)1158else if(options.autoScrolling && canScroll){1159
1160//is the movement greater than the minimum resistance to scroll?1161if (Math.abs(touchStartY - touchEndY) > ($window.height() / 100 * options.touchSensitivity)) {1162if (touchStartY > touchEndY) {1163scrolling('down', scrollable);1164} else if (touchEndY > touchStartY) {1165scrolling('up', scrollable);1166}1167}1168}1169}1170}1171
1172/**1173* recursive function to loop up the parent nodes to check if one of them exists in options.normalScrollElements
1174* Currently works well for iOS - Android might need some testing
1175* @param {Element} el target element / jquery selector (in subsequent nodes)
1176* @param {int} hop current hop compared to options.normalScrollElementTouchThreshold
1177* @return {boolean} true if there is a match to options.normalScrollElements
1178*/
1179function checkParentForNormalScrollElement (el, hop) {1180hop = hop || 0;1181var parent = $(el).parent();1182
1183if (hop < options.normalScrollElementTouchThreshold &&1184parent.is(options.normalScrollElements) ) {1185return true;1186} else if (hop == options.normalScrollElementTouchThreshold) {1187return false;1188} else {1189return checkParentForNormalScrollElement(parent, ++hop);1190}1191}1192
1193/**1194* As IE >= 10 fires both touch and mouse events when using a mouse in a touchscreen
1195* this way we make sure that is really a touch event what IE is detecting.
1196*/
1197function isReallyTouch(e){1198//if is not IE || IE is detecting `touch` or `pen`1199return typeof e.pointerType === 'undefined' || e.pointerType != 'mouse';1200}1201
1202/**1203* Handler for the touch start event.
1204*/
1205function touchStartHandler(event){1206var e = event.originalEvent;1207
1208//stopping the auto scroll to adjust to a section1209if(options.fitToSection){1210$htmlBody.stop();1211}1212
1213if(isReallyTouch(e)){1214var touchEvents = getEventsPage(e);1215touchStartY = touchEvents.y;1216touchStartX = touchEvents.x;1217}1218}1219
1220/**1221* Gets the average of the last `number` elements of the given array.
1222*/
1223function getAverage(elements, number){1224var sum = 0;1225
1226//taking `number` elements from the end to make the average, if there are not enought, 11227var lastElements = elements.slice(Math.max(elements.length - number, 1));1228
1229for(var i = 0; i < lastElements.length; i++){1230sum = sum + lastElements[i];1231}1232
1233return Math.ceil(sum/number);1234}1235
1236/**1237* Detecting mousewheel scrolling
1238*
1239* http://blogs.sitepointstatic.com/examples/tech/mouse-wheel/index.html
1240* http://www.sitepoint.com/html5-javascript-mouse-wheel/
1241*/
1242var prevTime = new Date().getTime();1243
1244function MouseWheelHandler(e) {1245var curTime = new Date().getTime();1246var isNormalScroll = $(COMPLETELY_SEL).hasClass(NORMAL_SCROLL);1247
1248//autoscrolling and not zooming?1249if(options.autoScrolling && !controlPressed && !isNormalScroll){1250// cross-browser wheel delta1251e = e || window.event;1252var value = e.wheelDelta || -e.deltaY || -e.detail;1253var delta = Math.max(-1, Math.min(1, value));1254
1255var horizontalDetection = typeof e.wheelDeltaX !== 'undefined' || typeof e.deltaX !== 'undefined';1256var isScrollingVertically = (Math.abs(e.wheelDeltaX) < Math.abs(e.wheelDelta)) || (Math.abs(e.deltaX ) < Math.abs(e.deltaY) || !horizontalDetection);1257
1258//Limiting the array to 150 (lets not waste memory!)1259if(scrollings.length > 149){1260scrollings.shift();1261}1262
1263//keeping record of the previous scrollings1264scrollings.push(Math.abs(value));1265
1266//preventing to scroll the site on mouse wheel when scrollbar is present1267if(options.scrollBar){1268e.preventDefault ? e.preventDefault() : e.returnValue = false;1269}1270
1271var activeSection = $(SECTION_ACTIVE_SEL);1272var scrollable = options.scrollOverflowHandler.scrollable(activeSection);1273
1274//time difference between the last scroll and the current one1275var timeDiff = curTime-prevTime;1276prevTime = curTime;1277
1278//haven't they scrolled in a while?1279//(enough to be consider a different scrolling action to scroll another section)1280if(timeDiff > 200){1281//emptying the array, we dont care about old scrollings for our averages1282scrollings = [];1283}1284
1285if(canScroll){1286var averageEnd = getAverage(scrollings, 10);1287var averageMiddle = getAverage(scrollings, 70);1288var isAccelerating = averageEnd >= averageMiddle;1289
1290//to avoid double swipes...1291if(isAccelerating && isScrollingVertically){1292//scrolling down?1293if (delta < 0) {1294scrolling('down', scrollable);1295
1296//scrolling up?1297}else {1298scrolling('up', scrollable);1299}1300}1301}1302
1303return false;1304}1305
1306if(options.fitToSection){1307//stopping the auto scroll to adjust to a section1308$htmlBody.stop();1309}1310}1311
1312/**1313* Slides a slider to the given direction.
1314* Optional `section` param.
1315*/
1316function moveSlide(direction, section){1317var activeSection = typeof section === 'undefined' ? $(SECTION_ACTIVE_SEL) : section;1318var slides = activeSection.find(SLIDES_WRAPPER_SEL);1319var numSlides = slides.find(SLIDE_SEL).length;1320
1321// more than one slide needed and nothing should be sliding1322if (!slides.length || slideMoving || numSlides < 2) {1323return;1324}1325
1326var currentSlide = slides.find(SLIDE_ACTIVE_SEL);1327var destiny = null;1328
1329if(direction === 'left'){1330destiny = currentSlide.prev(SLIDE_SEL);1331}else{1332destiny = currentSlide.next(SLIDE_SEL);1333}1334
1335//isn't there a next slide in the secuence?1336if(!destiny.length){1337//respect loopHorizontal settin1338if (!options.loopHorizontal) return;1339
1340if(direction === 'left'){1341destiny = currentSlide.siblings(':last');1342}else{1343destiny = currentSlide.siblings(':first');1344}1345}1346
1347slideMoving = true;1348
1349landscapeScroll(slides, destiny, direction);1350}1351
1352/**1353* Maintains the active slides in the viewport
1354* (Because the `scroll` animation might get lost with some actions, such as when using continuousVertical)
1355*/
1356function keepSlidesPosition(){1357$(SLIDE_ACTIVE_SEL).each(function(){1358silentLandscapeScroll($(this), 'internal');1359});1360}1361
1362var previousDestTop = 0;1363/**1364* Returns the destination Y position based on the scrolling direction and
1365* the height of the section.
1366*/
1367function getDestinationPosition(element){1368var elemPosition = element.position();1369
1370//top of the desination will be at the top of the viewport1371var position = elemPosition.top;1372var isScrollingDown = elemPosition.top > previousDestTop;1373var sectionBottom = position - windowsHeight + element.outerHeight();1374var bigSectionsDestination = options.bigSectionsDestination;1375
1376//is the destination element bigger than the viewport?1377if(element.outerHeight() > windowsHeight){1378//scrolling up?1379if(!isScrollingDown && !bigSectionsDestination || bigSectionsDestination === 'bottom' ){1380position = sectionBottom;1381}1382}1383
1384//sections equal or smaller than the viewport height && scrolling down? || is resizing and its in the last section1385else if(isScrollingDown || (isResizing && element.is(':last-child')) ){1386//The bottom of the destination will be at the bottom of the viewport1387position = sectionBottom;1388}1389
1390/*1391Keeping record of the last scrolled position to determine the scrolling direction.
1392No conventional methods can be used as the scroll bar might not be present
1393AND the section might not be active if it is auto-height and didnt reach the middle
1394of the viewport.
1395*/
1396previousDestTop = position;1397return position;1398}1399
1400/**1401* Scrolls the site to the given element and scrolls to the slide if a callback is given.
1402*/
1403function scrollPage(element, callback, isMovementUp){1404if(typeof element === 'undefined'){ return; } //there's no element to scroll, leaving the function1405
1406var dtop = getDestinationPosition(element);1407var slideAnchorLink;1408var slideIndex;1409
1410//local variables1411var v = {1412element: element,1413callback: callback,1414isMovementUp: isMovementUp,1415dtop: dtop,1416yMovement: getYmovement(element),1417anchorLink: element.data('anchor'),1418sectionIndex: element.index(SECTION_SEL),1419activeSlide: element.find(SLIDE_ACTIVE_SEL),1420activeSection: $(SECTION_ACTIVE_SEL),1421leavingSection: $(SECTION_ACTIVE_SEL).index(SECTION_SEL) + 1,1422
1423//caching the value of isResizing at the momment the function is called1424//because it will be checked later inside a setTimeout and the value might change1425localIsResizing: isResizing1426};1427
1428//quiting when destination scroll is the same as the current one1429if((v.activeSection.is(element) && !isResizing) || (options.scrollBar && $window.scrollTop() === v.dtop && !element.hasClass(AUTO_HEIGHT) )){ return; }1430
1431if(v.activeSlide.length){1432slideAnchorLink = v.activeSlide.data('anchor');1433slideIndex = v.activeSlide.index();1434}1435
1436// If continuousVertical && we need to wrap around1437if (options.autoScrolling && options.continuousVertical && typeof (v.isMovementUp) !== "undefined" &&1438((!v.isMovementUp && v.yMovement == 'up') || // Intending to scroll down but about to go up or1439(v.isMovementUp && v.yMovement == 'down'))) { // intending to scroll up but about to go down1440
1441v = createInfiniteSections(v);1442}1443
1444//callback (onLeave) if the site is not just resizing and readjusting the slides1445if($.isFunction(options.onLeave) && !v.localIsResizing){1446if(options.onLeave.call(v.activeSection, v.leavingSection, (v.sectionIndex + 1), v.yMovement) === false){1447return;1448}1449}1450
1451//pausing media of the leaving section (if we are not just resizing, as destinatino will be the same one)1452if(!v.localIsResizing){1453stopMedia(v.activeSection);1454}1455
1456options.scrollOverflowHandler.beforeLeave();1457element.addClass(ACTIVE).siblings().removeClass(ACTIVE);1458lazyLoad(element);1459options.scrollOverflowHandler.onLeave();1460
1461
1462//preventing from activating the MouseWheelHandler event1463//more than once if the page is scrolling1464canScroll = false;1465
1466setState(slideIndex, slideAnchorLink, v.anchorLink, v.sectionIndex);1467
1468performMovement(v);1469
1470//flag to avoid callingn `scrollPage()` twice in case of using anchor links1471lastScrolledDestiny = v.anchorLink;1472
1473//avoid firing it twice (as it does also on scroll)1474activateMenuAndNav(v.anchorLink, v.sectionIndex);1475}1476
1477/**1478* Performs the vertical movement (by CSS3 or by jQuery)
1479*/
1480function performMovement(v){1481// using CSS3 translate functionality1482if (options.css3 && options.autoScrolling && !options.scrollBar) {1483
1484// The first section can have a negative value in iOS 10. Not quite sure why: -0.01428222656251485// that's why we round it to 0.1486var translate3d = 'translate3d(0px, -' + Math.round(v.dtop) + 'px, 0px)';1487transformContainer(translate3d, true);1488
1489//even when the scrollingSpeed is 0 there's a little delay, which might cause the1490//scrollingSpeed to change in case of using silentMoveTo();1491if(options.scrollingSpeed){1492clearTimeout(afterSectionLoadsId);1493afterSectionLoadsId = setTimeout(function () {1494afterSectionLoads(v);1495}, options.scrollingSpeed);1496}else{1497afterSectionLoads(v);1498}1499}1500
1501// using jQuery animate1502else{1503var scrollSettings = getScrollSettings(v);1504
1505$(scrollSettings.element).animate(1506scrollSettings.options,1507options.scrollingSpeed, options.easing).promise().done(function () { //only one single callback in case of animating `html, body`1508if(options.scrollBar){1509
1510/* Hack!1511The timeout prevents setting the most dominant section in the viewport as "active" when the user
1512scrolled to a smaller section by using the mousewheel (auto scrolling) rather than draging the scroll bar.
1513
1514When using scrollBar:true It seems like the scroll events still getting propagated even after the scrolling animation has finished.
1515*/
1516setTimeout(function(){1517afterSectionLoads(v);1518},30);1519}else{1520afterSectionLoads(v);1521}1522});1523}1524}1525
1526/**1527* Gets the scrolling settings depending on the plugin autoScrolling option
1528*/
1529function getScrollSettings(v){1530var scroll = {};1531
1532if(options.autoScrolling && !options.scrollBar){1533scroll.options = { 'top': -v.dtop};1534scroll.element = WRAPPER_SEL;1535}else{1536scroll.options = { 'scrollTop': v.dtop};1537scroll.element = 'html, body';1538}1539
1540return scroll;1541}1542
1543/**1544* Adds sections before or after the current one to create the infinite effect.
1545*/
1546function createInfiniteSections(v){1547// Scrolling down1548if (!v.isMovementUp) {1549// Move all previous sections to after the active section1550$(SECTION_ACTIVE_SEL).after(v.activeSection.prevAll(SECTION_SEL).get().reverse());1551}1552else { // Scrolling up1553// Move all next sections to before the active section1554$(SECTION_ACTIVE_SEL).before(v.activeSection.nextAll(SECTION_SEL));1555}1556
1557// Maintain the displayed position (now that we changed the element order)1558silentScroll($(SECTION_ACTIVE_SEL).position().top);1559
1560// Maintain the active slides visible in the viewport1561keepSlidesPosition();1562
1563// save for later the elements that still need to be reordered1564v.wrapAroundElements = v.activeSection;1565
1566// Recalculate animation variables1567v.dtop = v.element.position().top;1568v.yMovement = getYmovement(v.element);1569
1570return v;1571}1572
1573/**1574* Fix section order after continuousVertical changes have been animated
1575*/
1576function continuousVerticalFixSectionOrder (v) {1577// If continuousVertical is in effect (and autoScrolling would also be in effect then),1578// finish moving the elements around so the direct navigation will function more simply1579if (!v.wrapAroundElements || !v.wrapAroundElements.length) {1580return;1581}1582
1583if (v.isMovementUp) {1584$(SECTION_FIRST_SEL).before(v.wrapAroundElements);1585}1586else {1587$(SECTION_LAST_SEL).after(v.wrapAroundElements);1588}1589
1590silentScroll($(SECTION_ACTIVE_SEL).position().top);1591
1592// Maintain the active slides visible in the viewport1593keepSlidesPosition();1594}1595
1596
1597/**1598* Actions to do once the section is loaded.
1599*/
1600function afterSectionLoads (v){1601continuousVerticalFixSectionOrder(v);1602
1603//callback (afterLoad) if the site is not just resizing and readjusting the slides1604$.isFunction(options.afterLoad) && !v.localIsResizing && options.afterLoad.call(v.element, v.anchorLink, (v.sectionIndex + 1));1605options.scrollOverflowHandler.afterLoad();1606
1607if(!v.localIsResizing){1608playMedia(v.element);1609}1610
1611v.element.addClass(COMPLETELY).siblings().removeClass(COMPLETELY);1612
1613canScroll = true;1614
1615$.isFunction(v.callback) && v.callback.call(this);1616}1617
1618/**1619* Sets the value for the given attribute from the `data-` attribute with the same suffix
1620* ie: data-srcset ==> srcset | data-src ==> src
1621*/
1622function setSrc(element, attribute){1623element
1624.attr(attribute, element.data(attribute))1625.removeAttr('data-' + attribute);1626}1627
1628/**1629* Lazy loads image, video and audio elements.
1630*/
1631function lazyLoad(destiny){1632if (!options.lazyLoading){1633return;1634}1635
1636var panel = getSlideOrSection(destiny);1637var element;1638
1639panel.find('img[data-src], img[data-srcset], source[data-src], audio[data-src], iframe[data-src]').each(function(){1640element = $(this);1641
1642$.each(['src', 'srcset'], function(index, type){1643var attribute = element.attr('data-' + type);1644if(typeof attribute !== 'undefined' && attribute){1645setSrc(element, type);1646}1647});1648
1649if(element.is('source')){1650element.closest('video').get(0).load();1651}1652});1653}1654
1655/**1656* Plays video and audio elements.
1657*/
1658function playMedia(destiny){1659var panel = getSlideOrSection(destiny);1660
1661//playing HTML5 media elements1662panel.find('video, audio').each(function(){1663var element = $(this).get(0);1664
1665if( element.hasAttribute('data-autoplay') && typeof element.play === 'function' ) {1666element.play();1667}1668});1669
1670//youtube videos1671panel.find('iframe[src*="youtube.com/embed/"]').each(function(){1672var element = $(this).get(0);1673
1674if ( element.hasAttribute('data-autoplay') ){1675playYoutube(element);1676}1677
1678//in case the URL was not loaded yet. On page load we need time for the new URL (with the API string) to load.1679element.onload = function() {1680if ( element.hasAttribute('data-autoplay') ){1681playYoutube(element);1682}1683};1684});1685}1686
1687/**1688* Plays a youtube video
1689*/
1690function playYoutube(element){1691element.contentWindow.postMessage('{"event":"command","func":"playVideo","args":""}', '*');1692}1693
1694/**1695* Stops video and audio elements.
1696*/
1697function stopMedia(destiny){1698var panel = getSlideOrSection(destiny);1699
1700//stopping HTML5 media elements1701panel.find('video, audio').each(function(){1702var element = $(this).get(0);1703
1704if( !element.hasAttribute('data-keepplaying') && typeof element.pause === 'function' ) {1705element.pause();1706}1707});1708
1709//youtube videos1710panel.find('iframe[src*="youtube.com/embed/"]').each(function(){1711var element = $(this).get(0);1712
1713if( /youtube\.com\/embed\//.test($(this).attr('src')) && !element.hasAttribute('data-keepplaying')){1714$(this).get(0).contentWindow.postMessage('{"event":"command","func":"pauseVideo","args":""}','*');1715}1716});1717}1718
1719/**1720* Gets the active slide (or section) for the given section
1721*/
1722function getSlideOrSection(destiny){1723var slide = destiny.find(SLIDE_ACTIVE_SEL);1724if( slide.length ) {1725destiny = $(slide);1726}1727
1728return destiny;1729}1730
1731/**1732* Scrolls to the anchor in the URL when loading the site
1733*/
1734function scrollToAnchor(){1735//getting the anchor link in the URL and deleting the `#`1736var value = window.location.hash.replace('#', '').split('/');1737var sectionAnchor = decodeURIComponent(value[0]);1738var slideAnchor = decodeURIComponent(value[1]);1739
1740if(sectionAnchor){ //if theres any #1741if(options.animateAnchor){1742scrollPageAndSlide(sectionAnchor, slideAnchor);1743}else{1744silentMoveTo(sectionAnchor, slideAnchor);1745}1746}1747}1748
1749/**1750* Detecting any change on the URL to scroll to the given anchor link
1751* (a way to detect back history button as we play with the hashes on the URL)
1752*/
1753function hashChangeHandler(){1754if(!isScrolling && !options.lockAnchors){1755var value = window.location.hash.replace('#', '').split('/');1756var sectionAnchor = decodeURIComponent(value[0]);1757var slideAnchor = decodeURIComponent(value[1]);1758
1759//when moving to a slide in the first section for the first time (first time to add an anchor to the URL)1760var isFirstSlideMove = (typeof lastScrolledDestiny === 'undefined');1761var isFirstScrollMove = (typeof lastScrolledDestiny === 'undefined' && typeof slideAnchor === 'undefined' && !slideMoving);1762
1763
1764if(sectionAnchor.length){1765/*in order to call scrollpage() only once for each destination at a time1766It is called twice for each scroll otherwise, as in case of using anchorlinks `hashChange`
1767event is fired on every scroll too.*/
1768if ((sectionAnchor && sectionAnchor !== lastScrolledDestiny) && !isFirstSlideMove || isFirstScrollMove || (!slideMoving && lastScrolledSlide != slideAnchor )) {1769scrollPageAndSlide(sectionAnchor, slideAnchor);1770}1771}1772}1773}1774
1775//Sliding with arrow keys, both, vertical and horizontal1776function keydownHandler(e) {1777
1778clearTimeout(keydownId);1779
1780var activeElement = $(':focus');1781
1782if(!activeElement.is('textarea') && !activeElement.is('input') && !activeElement.is('select') &&1783activeElement.attr('contentEditable') !== "true" && activeElement.attr('contentEditable') !== '' &&1784options.keyboardScrolling && options.autoScrolling){1785var keyCode = e.which;1786
1787//preventing the scroll with arrow keys & spacebar & Page Up & Down keys1788var keyControls = [40, 38, 32, 33, 34];1789if($.inArray(keyCode, keyControls) > -1){1790e.preventDefault();1791}1792
1793controlPressed = e.ctrlKey;1794
1795keydownId = setTimeout(function(){1796onkeydown(e);1797},150);1798}1799}1800
1801function tooltipTextHandler(){1802$(this).prev().trigger('click');1803}1804
1805//to prevent scrolling while zooming1806function keyUpHandler(e){1807if(isWindowFocused){ //the keyup gets fired on new tab ctrl + t in Firefox1808controlPressed = e.ctrlKey;1809}1810}1811
1812//binding the mousemove when the mouse's middle button is released1813function mouseDownHandler(e){1814//middle button1815if (e.which == 2){1816oldPageY = e.pageY;1817container.on('mousemove', mouseMoveHandler);1818}1819}1820
1821//unbinding the mousemove when the mouse's middle button is released1822function mouseUpHandler(e){1823//middle button1824if (e.which == 2){1825container.off('mousemove');1826}1827}1828
1829//Scrolling horizontally when clicking on the slider controls.1830function slideArrowHandler(){1831var section = $(this).closest(SECTION_SEL);1832
1833if ($(this).hasClass(SLIDES_PREV)) {1834if(isScrollAllowed.m.left){1835moveSlideLeft(section);1836}1837} else {1838if(isScrollAllowed.m.right){1839moveSlideRight(section);1840}1841}1842}1843
1844//when opening a new tab (ctrl + t), `control` won't be pressed when coming back.1845function blurHandler(){1846isWindowFocused = false;1847controlPressed = false;1848}1849
1850//Scrolls to the section when clicking the navigation bullet1851function sectionBulletHandler(e){1852e.preventDefault();1853var index = $(this).parent().index();1854scrollPage($(SECTION_SEL).eq(index));1855}1856
1857//Scrolls the slider to the given slide destination for the given section1858function slideBulletHandler(e){1859e.preventDefault();1860var slides = $(this).closest(SECTION_SEL).find(SLIDES_WRAPPER_SEL);1861var destiny = slides.find(SLIDE_SEL).eq($(this).closest('li').index());1862
1863landscapeScroll(slides, destiny);1864}1865
1866/**1867* Keydown event
1868*/
1869function onkeydown(e){1870var shiftPressed = e.shiftKey;1871
1872//do nothing if we can not scroll or we are not using horizotnal key arrows.1873if(!canScroll && [37,39].indexOf(e.which) < 0){1874return;1875}1876
1877switch (e.which) {1878//up1879case 38:1880case 33:1881if(isScrollAllowed.k.up){1882moveSectionUp();1883}1884break;1885
1886//down1887case 32: //spacebar1888if(shiftPressed && isScrollAllowed.k.up){1889moveSectionUp();1890break;1891}1892/* falls through */1893case 40:1894case 34:1895if(isScrollAllowed.k.down){1896moveSectionDown();1897}1898break;1899
1900//Home1901case 36:1902if(isScrollAllowed.k.up){1903moveTo(1);1904}1905break;1906
1907//End1908case 35:1909if(isScrollAllowed.k.down){1910moveTo( $(SECTION_SEL).length );1911}1912break;1913
1914//left1915case 37:1916if(isScrollAllowed.k.left){1917moveSlideLeft();1918}1919break;1920
1921//right1922case 39:1923if(isScrollAllowed.k.right){1924moveSlideRight();1925}1926break;1927
1928default:1929return; // exit this handler for other keys1930}1931}1932
1933/**1934* Detecting the direction of the mouse movement.
1935* Used only for the middle button of the mouse.
1936*/
1937var oldPageY = 0;1938function mouseMoveHandler(e){1939if(canScroll){1940// moving up1941if (e.pageY < oldPageY && isScrollAllowed.m.up){1942moveSectionUp();1943}1944
1945// moving down1946else if(e.pageY > oldPageY && isScrollAllowed.m.down){1947moveSectionDown();1948}1949}1950oldPageY = e.pageY;1951}1952
1953/**1954* Scrolls horizontal sliders.
1955*/
1956function landscapeScroll(slides, destiny, direction){1957var section = slides.closest(SECTION_SEL);1958var v = {1959slides: slides,1960destiny: destiny,1961direction: direction,1962destinyPos: destiny.position(),1963slideIndex: destiny.index(),1964section: section,1965sectionIndex: section.index(SECTION_SEL),1966anchorLink: section.data('anchor'),1967slidesNav: section.find(SLIDES_NAV_SEL),1968slideAnchor: getAnchor(destiny),1969prevSlide: section.find(SLIDE_ACTIVE_SEL),1970prevSlideIndex: section.find(SLIDE_ACTIVE_SEL).index(),1971
1972//caching the value of isResizing at the momment the function is called1973//because it will be checked later inside a setTimeout and the value might change1974localIsResizing: isResizing1975};1976v.xMovement = getXmovement(v.prevSlideIndex, v.slideIndex);1977
1978//important!! Only do it when not resizing1979if(!v.localIsResizing){1980//preventing from scrolling to the next/prev section when using scrollHorizontally1981canScroll = false;1982}1983
1984if(options.onSlideLeave){1985
1986//if the site is not just resizing and readjusting the slides1987if(!v.localIsResizing && v.xMovement!=='none'){1988if($.isFunction( options.onSlideLeave )){1989if(options.onSlideLeave.call( v.prevSlide, v.anchorLink, (v.sectionIndex + 1), v.prevSlideIndex, v.xMovement, v.slideIndex ) === false){1990slideMoving = false;1991return;1992}1993}1994}1995}1996
1997destiny.addClass(ACTIVE).siblings().removeClass(ACTIVE);1998
1999if(!v.localIsResizing){2000stopMedia(v.prevSlide);2001lazyLoad(destiny);2002}2003
2004if(!options.loopHorizontal && options.controlArrows){2005//hidding it for the fist slide, showing for the rest2006section.find(SLIDES_ARROW_PREV_SEL).toggle(v.slideIndex!==0);2007
2008//hidding it for the last slide, showing for the rest2009section.find(SLIDES_ARROW_NEXT_SEL).toggle(!destiny.is(':last-child'));2010}2011
2012//only changing the URL if the slides are in the current section (not for resize re-adjusting)2013if(section.hasClass(ACTIVE) && !v.localIsResizing){2014setState(v.slideIndex, v.slideAnchor, v.anchorLink, v.sectionIndex);2015}2016
2017performHorizontalMove(slides, v, true);2018}2019
2020
2021function afterSlideLoads(v){2022activeSlidesNavigation(v.slidesNav, v.slideIndex);2023
2024//if the site is not just resizing and readjusting the slides2025if(!v.localIsResizing){2026$.isFunction( options.afterSlideLoad ) && options.afterSlideLoad.call( v.destiny, v.anchorLink, (v.sectionIndex + 1), v.slideAnchor, v.slideIndex);2027
2028//needs to be inside the condition to prevent problems with continuousVertical and scrollHorizontally2029//and to prevent double scroll right after a windows resize2030canScroll = true;2031
2032playMedia(v.destiny);2033}2034
2035//letting them slide again2036slideMoving = false;2037}2038
2039/**2040* Performs the horizontal movement. (CSS3 or jQuery)
2041*
2042* @param fireCallback {Bool} - determines whether or not to fire the callback
2043*/
2044function performHorizontalMove(slides, v, fireCallback){2045var destinyPos = v.destinyPos;2046
2047if(options.css3){2048var translate3d = 'translate3d(-' + Math.round(destinyPos.left) + 'px, 0px, 0px)';2049
2050addAnimation(slides.find(SLIDES_CONTAINER_SEL)).css(getTransforms(translate3d));2051
2052afterSlideLoadsId = setTimeout(function(){2053fireCallback && afterSlideLoads(v);2054}, options.scrollingSpeed, options.easing);2055}else{2056slides.animate({2057scrollLeft : Math.round(destinyPos.left)2058}, options.scrollingSpeed, options.easing, function() {2059
2060fireCallback && afterSlideLoads(v);2061});2062}2063}2064
2065/**2066* Sets the state for the horizontal bullet navigations.
2067*/
2068function activeSlidesNavigation(slidesNav, slideIndex){2069slidesNav.find(ACTIVE_SEL).removeClass(ACTIVE);2070slidesNav.find('li').eq(slideIndex).find('a').addClass(ACTIVE);2071}2072
2073var previousHeight = windowsHeight;2074
2075//when resizing the site, we adjust the heights of the sections, slimScroll...2076function resizeHandler(){2077//checking if it needs to get responsive2078responsive();2079
2080// rebuild immediately on touch devices2081if (isTouchDevice) {2082var activeElement = $(document.activeElement);2083
2084//if the keyboard is NOT visible2085if (!activeElement.is('textarea') && !activeElement.is('input') && !activeElement.is('select')) {2086var currentHeight = $window.height();2087
2088//making sure the change in the viewport size is enough to force a rebuild. (20 % of the window to avoid problems when hidding scroll bars)2089if( Math.abs(currentHeight - previousHeight) > (20 * Math.max(previousHeight, currentHeight) / 100) ){2090reBuild(true);2091previousHeight = currentHeight;2092}2093}2094}else{2095//in order to call the functions only when the resize is finished2096//http://stackoverflow.com/questions/4298612/jquery-how-to-call-resize-event-only-once-its-finished-resizing2097clearTimeout(resizeId);2098
2099resizeId = setTimeout(function(){2100reBuild(true);2101}, 350);2102}2103}2104
2105/**2106* Checks if the site needs to get responsive and disables autoScrolling if so.
2107* A class `fp-responsive` is added to the plugin's container in case the user wants to use it for his own responsive CSS.
2108*/
2109function responsive(){2110var widthLimit = options.responsive || options.responsiveWidth; //backwards compatiblity2111var heightLimit = options.responsiveHeight;2112
2113//only calculating what we need. Remember its called on the resize event.2114var isBreakingPointWidth = widthLimit && $window.outerWidth() < widthLimit;2115var isBreakingPointHeight = heightLimit && $window.height() < heightLimit;2116
2117if(widthLimit && heightLimit){2118setResponsive(isBreakingPointWidth || isBreakingPointHeight);2119}2120else if(widthLimit){2121setResponsive(isBreakingPointWidth);2122}2123else if(heightLimit){2124setResponsive(isBreakingPointHeight);2125}2126}2127
2128/**2129* Adds transition animations for the given element
2130*/
2131function addAnimation(element){2132var transition = 'all ' + options.scrollingSpeed + 'ms ' + options.easingcss3;2133
2134element.removeClass(NO_TRANSITION);2135return element.css({2136'-webkit-transition': transition,2137'transition': transition2138});2139}2140
2141/**2142* Remove transition animations for the given element
2143*/
2144function removeAnimation(element){2145return element.addClass(NO_TRANSITION);2146}2147
2148/**2149* Activating the vertical navigation bullets according to the given slide name.
2150*/
2151function activateNavDots(name, sectionIndex){2152if(options.navigation){2153$(SECTION_NAV_SEL).find(ACTIVE_SEL).removeClass(ACTIVE);2154if(name){2155$(SECTION_NAV_SEL).find('a[href="#' + name + '"]').addClass(ACTIVE);2156}else{2157$(SECTION_NAV_SEL).find('li').eq(sectionIndex).find('a').addClass(ACTIVE);2158}2159}2160}2161
2162/**2163* Activating the website main menu elements according to the given slide name.
2164*/
2165function activateMenuElement(name){2166if(options.menu){2167$(options.menu).find(ACTIVE_SEL).removeClass(ACTIVE);2168$(options.menu).find('[data-menuanchor="'+name+'"]').addClass(ACTIVE);2169}2170}2171
2172/**2173* Sets to active the current menu and vertical nav items.
2174*/
2175function activateMenuAndNav(anchor, index){2176activateMenuElement(anchor);2177activateNavDots(anchor, index);2178}2179
2180/**2181* Retuns `up` or `down` depending on the scrolling movement to reach its destination
2182* from the current section.
2183*/
2184function getYmovement(destiny){2185var fromIndex = $(SECTION_ACTIVE_SEL).index(SECTION_SEL);2186var toIndex = destiny.index(SECTION_SEL);2187if( fromIndex == toIndex){2188return 'none';2189}2190if(fromIndex > toIndex){2191return 'up';2192}2193return 'down';2194}2195
2196/**2197* Retuns `right` or `left` depending on the scrolling movement to reach its destination
2198* from the current slide.
2199*/
2200function getXmovement(fromIndex, toIndex){2201if( fromIndex == toIndex){2202return 'none';2203}2204if(fromIndex > toIndex){2205return 'left';2206}2207return 'right';2208}2209
2210/**2211* Checks if the element needs scrollbar and if the user wants to apply it.
2212* If so it creates it.
2213*
2214* @param {Object} element jQuery object of the section or slide
2215*/
2216function createScrollBar(element){2217//User doesn't want scrollbar here? Sayonara baby!2218if(element.hasClass('fp-noscroll')) return;2219
2220//needed to make `scrollHeight` work under Opera 122221element.css('overflow', 'hidden');2222
2223var scrollOverflowHandler = options.scrollOverflowHandler;2224var wrap = scrollOverflowHandler.wrapContent();2225//in case element is a slide2226var section = element.closest(SECTION_SEL);2227var scrollable = scrollOverflowHandler.scrollable(element);2228var contentHeight;2229
2230//if there was scroll, the contentHeight will be the one in the scrollable section2231if(scrollable.length){2232contentHeight = scrollOverflowHandler.scrollHeight(element);2233}else{2234contentHeight = element.get(0).scrollHeight;2235if(options.verticalCentered){2236contentHeight = element.find(TABLE_CELL_SEL).get(0).scrollHeight;2237}2238}2239
2240var scrollHeight = windowsHeight - parseInt(section.css('padding-bottom')) - parseInt(section.css('padding-top'));2241
2242//needs scroll?2243if ( contentHeight > scrollHeight) {2244//did we already have an scrollbar ? Updating it2245if(scrollable.length){2246scrollOverflowHandler.update(element, scrollHeight);2247}2248//creating the scrolling2249else{2250if(options.verticalCentered){2251element.find(TABLE_CELL_SEL).wrapInner(wrap);2252}else{2253element.wrapInner(wrap);2254}2255scrollOverflowHandler.create(element, scrollHeight);2256}2257}2258//removing the scrolling when it is not necessary anymore2259else{2260scrollOverflowHandler.remove(element);2261}2262
2263//undo2264element.css('overflow', '');2265}2266
2267function addTableClass(element){2268//In case we are styling for the 2nd time as in with reponsiveSlides2269if(!element.hasClass(TABLE)){2270element.addClass(TABLE).wrapInner('<div class="' + TABLE_CELL + '" style="height:' + getTableHeight(element) + 'px;" />');2271}2272}2273
2274function getTableHeight(element){2275var sectionHeight = windowsHeight;2276
2277if(options.paddingTop || options.paddingBottom){2278var section = element;2279if(!section.hasClass(SECTION)){2280section = element.closest(SECTION_SEL);2281}2282
2283var paddings = parseInt(section.css('padding-top')) + parseInt(section.css('padding-bottom'));2284sectionHeight = (windowsHeight - paddings);2285}2286
2287return sectionHeight;2288}2289
2290/**2291* Adds a css3 transform property to the container class with or without animation depending on the animated param.
2292*/
2293function transformContainer(translate3d, animated){2294if(animated){2295addAnimation(container);2296}else{2297removeAnimation(container);2298}2299
2300container.css(getTransforms(translate3d));2301
2302//syncronously removing the class after the animation has been applied.2303setTimeout(function(){2304container.removeClass(NO_TRANSITION);2305},10);2306}2307
2308/**2309* Gets a section by its anchor / index
2310*/
2311function getSectionByAnchor(sectionAnchor){2312if(!sectionAnchor) return [];2313
2314var section = container.find(SECTION_SEL + '[data-anchor="'+sectionAnchor+'"]');2315if(!section.length){2316section = $(SECTION_SEL).eq( sectionAnchor -1);2317}2318
2319return section;2320}2321
2322/**2323* Gets a slide inside a given section by its anchor / index
2324*/
2325function getSlideByAnchor(slideAnchor, section){2326var slides = section.find(SLIDES_WRAPPER_SEL);2327var slide = slides.find(SLIDE_SEL + '[data-anchor="'+slideAnchor+'"]');2328
2329if(!slide.length){2330slide = slides.find(SLIDE_SEL).eq(slideAnchor);2331}2332
2333return slide;2334}2335
2336/**2337* Scrolls to the given section and slide anchors
2338*/
2339function scrollPageAndSlide(destiny, slide){2340var section = getSectionByAnchor(destiny);2341
2342//do nothing if there's no section with the given anchor name2343if(!section.length) return;2344
2345//default slide2346if (typeof slide === 'undefined') {2347slide = 0;2348}2349
2350//we need to scroll to the section and then to the slide2351if (destiny !== lastScrolledDestiny && !section.hasClass(ACTIVE)){2352scrollPage(section, function(){2353scrollSlider(section, slide);2354});2355}2356//if we were already in the section2357else{2358scrollSlider(section, slide);2359}2360}2361
2362/**2363* Scrolls the slider to the given slide destination for the given section
2364*/
2365function scrollSlider(section, slideAnchor){2366if(typeof slideAnchor !== 'undefined'){2367var slides = section.find(SLIDES_WRAPPER_SEL);2368var destiny = getSlideByAnchor(slideAnchor, section);2369
2370if(destiny.length){2371landscapeScroll(slides, destiny);2372}2373}2374}2375
2376/**2377* Creates a landscape navigation bar with dots for horizontal sliders.
2378*/
2379function addSlidesNavigation(section, numSlides){2380section.append('<div class="' + SLIDES_NAV + '"><ul></ul></div>');2381var nav = section.find(SLIDES_NAV_SEL);2382
2383//top or bottom2384nav.addClass(options.slidesNavPosition);2385
2386for(var i=0; i< numSlides; i++){2387nav.find('ul').append('<li><a href="#"><span></span></a></li>');2388}2389
2390//centering it2391nav.css('margin-left', '-' + (nav.width()/2) + 'px');2392
2393nav.find('li').first().find('a').addClass(ACTIVE);2394}2395
2396
2397/**2398* Sets the state of the website depending on the active section/slide.
2399* It changes the URL hash when needed and updates the body class.
2400*/
2401function setState(slideIndex, slideAnchor, anchorLink, sectionIndex){2402var sectionHash = '';2403
2404if(options.anchors.length && !options.lockAnchors){2405
2406//isn't it the first slide?2407if(slideIndex){2408if(typeof anchorLink !== 'undefined'){2409sectionHash = anchorLink;2410}2411
2412//slide without anchor link? We take the index instead.2413if(typeof slideAnchor === 'undefined'){2414slideAnchor = slideIndex;2415}2416
2417lastScrolledSlide = slideAnchor;2418setUrlHash(sectionHash + '/' + slideAnchor);2419
2420//first slide won't have slide anchor, just the section one2421}else if(typeof slideIndex !== 'undefined'){2422lastScrolledSlide = slideAnchor;2423setUrlHash(anchorLink);2424}2425
2426//section without slides2427else{2428setUrlHash(anchorLink);2429}2430}2431
2432setBodyClass();2433}2434
2435/**2436* Sets the URL hash.
2437*/
2438function setUrlHash(url){2439if(options.recordHistory){2440location.hash = url;2441}else{2442//Mobile Chrome doesn't work the normal way, so... lets use HTML5 for phones :)2443if(isTouchDevice || isTouch){2444window.history.replaceState(undefined, undefined, '#' + url);2445}else{2446var baseUrl = window.location.href.split('#')[0];2447window.location.replace( baseUrl + '#' + url );2448}2449}2450}2451
2452/**2453* Gets the anchor for the given slide / section. Its index will be used if there's none.
2454*/
2455function getAnchor(element){2456var anchor = element.data('anchor');2457var index = element.index();2458
2459//Slide without anchor link? We take the index instead.2460if(typeof anchor === 'undefined'){2461anchor = index;2462}2463
2464return anchor;2465}2466
2467/**2468* Sets a class for the body of the page depending on the active section / slide
2469*/
2470function setBodyClass(){2471var section = $(SECTION_ACTIVE_SEL);2472var slide = section.find(SLIDE_ACTIVE_SEL);2473
2474var sectionAnchor = getAnchor(section);2475var slideAnchor = getAnchor(slide);2476
2477var text = String(sectionAnchor);2478
2479if(slide.length){2480text = text + '-' + slideAnchor;2481}2482
2483//changing slash for dash to make it a valid CSS style2484text = text.replace('/', '-').replace('#','');2485
2486//removing previous anchor classes2487var classRe = new RegExp('\\b\\s?' + VIEWING_PREFIX + '-[^\\s]+\\b', "g");2488$body[0].className = $body[0].className.replace(classRe, '');2489
2490//adding the current anchor2491$body.addClass(VIEWING_PREFIX + '-' + text);2492}2493
2494/**2495* Checks for translate3d support
2496* @return boolean
2497* http://stackoverflow.com/questions/5661671/detecting-transform-translate3d-support
2498*/
2499function support3d() {2500var el = document.createElement('p'),2501has3d,2502transforms = {2503'webkitTransform':'-webkit-transform',2504'OTransform':'-o-transform',2505'msTransform':'-ms-transform',2506'MozTransform':'-moz-transform',2507'transform':'transform'2508};2509
2510// Add it to the body to get the computed style.2511document.body.insertBefore(el, null);2512
2513for (var t in transforms) {2514if (el.style[t] !== undefined) {2515el.style[t] = 'translate3d(1px,1px,1px)';2516has3d = window.getComputedStyle(el).getPropertyValue(transforms[t]);2517}2518}2519
2520document.body.removeChild(el);2521
2522return (has3d !== undefined && has3d.length > 0 && has3d !== 'none');2523}2524
2525/**2526* Removes the auto scrolling action fired by the mouse wheel and trackpad.
2527* After this function is called, the mousewheel and trackpad movements won't scroll through sections.
2528*/
2529function removeMouseWheelHandler(){2530if (document.addEventListener) {2531document.removeEventListener('mousewheel', MouseWheelHandler, false); //IE9, Chrome, Safari, Oper2532document.removeEventListener('wheel', MouseWheelHandler, false); //Firefox2533document.removeEventListener('MozMousePixelScroll', MouseWheelHandler, false); //old Firefox2534} else {2535document.detachEvent('onmousewheel', MouseWheelHandler); //IE 6/7/82536}2537}2538
2539/**2540* Adds the auto scrolling action for the mouse wheel and trackpad.
2541* After this function is called, the mousewheel and trackpad movements will scroll through sections
2542* https://developer.mozilla.org/en-US/docs/Web/Events/wheel
2543*/
2544function addMouseWheelHandler(){2545var prefix = '';2546var _addEventListener;2547
2548if (window.addEventListener){2549_addEventListener = "addEventListener";2550}else{2551_addEventListener = "attachEvent";2552prefix = 'on';2553}2554
2555// detect available wheel event2556var support = 'onwheel' in document.createElement('div') ? 'wheel' : // Modern browsers support "wheel"2557document.onmousewheel !== undefined ? 'mousewheel' : // Webkit and IE support at least "mousewheel"2558'DOMMouseScroll'; // let's assume that remaining browsers are older Firefox2559
2560
2561if(support == 'DOMMouseScroll'){2562document[ _addEventListener ](prefix + 'MozMousePixelScroll', MouseWheelHandler, false);2563}2564
2565//handle MozMousePixelScroll in older Firefox2566else{2567document[ _addEventListener ](prefix + support, MouseWheelHandler, false);2568}2569}2570
2571/**2572* Binding the mousemove when the mouse's middle button is pressed
2573*/
2574function addMiddleWheelHandler(){2575container
2576.on('mousedown', mouseDownHandler)2577.on('mouseup', mouseUpHandler);2578}2579
2580/**2581* Unbinding the mousemove when the mouse's middle button is released
2582*/
2583function removeMiddleWheelHandler(){2584container
2585.off('mousedown', mouseDownHandler)2586.off('mouseup', mouseUpHandler);2587}2588
2589/**2590* Adds the possibility to auto scroll through sections on touch devices.
2591*/
2592function addTouchHandler(){2593if(isTouchDevice || isTouch){2594if(options.autoScrolling){2595$body.off(events.touchmove).on(events.touchmove, preventBouncing);2596}2597
2598$(WRAPPER_SEL)2599.off(events.touchstart).on(events.touchstart, touchStartHandler)2600.off(events.touchmove).on(events.touchmove, touchMoveHandler);2601}2602}2603
2604/**2605* Removes the auto scrolling for touch devices.
2606*/
2607function removeTouchHandler(){2608if(isTouchDevice || isTouch){2609$(WRAPPER_SEL)2610.off(events.touchstart)2611.off(events.touchmove);2612}2613}2614
2615/*2616* Returns and object with Microsoft pointers (for IE<11 and for IE >= 11)
2617* http://msdn.microsoft.com/en-us/library/ie/dn304886(v=vs.85).aspx
2618*/
2619function getMSPointer(){2620var pointer;2621
2622//IE >= 11 & rest of browsers2623if(window.PointerEvent){2624pointer = { down: 'pointerdown', move: 'pointermove'};2625}2626
2627//IE < 112628else{2629pointer = { down: 'MSPointerDown', move: 'MSPointerMove'};2630}2631
2632return pointer;2633}2634
2635/**2636* Gets the pageX and pageY properties depending on the browser.
2637* https://github.com/alvarotrigo/fullPage.js/issues/194#issuecomment-34069854
2638*/
2639function getEventsPage(e){2640var events = [];2641
2642events.y = (typeof e.pageY !== 'undefined' && (e.pageY || e.pageX) ? e.pageY : e.touches[0].pageY);2643events.x = (typeof e.pageX !== 'undefined' && (e.pageY || e.pageX) ? e.pageX : e.touches[0].pageX);2644
2645//in touch devices with scrollBar:true, e.pageY is detected, but we have to deal with touch events. #10082646if(isTouch && isReallyTouch(e) && options.scrollBar){2647events.y = e.touches[0].pageY;2648events.x = e.touches[0].pageX;2649}2650
2651return events;2652}2653
2654/**2655* Slides silently (with no animation) the active slider to the given slide.
2656* @param noCallback {bool} true or defined -> no callbacks
2657*/
2658function silentLandscapeScroll(activeSlide, noCallbacks){2659setScrollingSpeed (0, 'internal');2660
2661if(typeof noCallbacks !== 'undefined'){2662//preventing firing callbacks afterSlideLoad etc.2663isResizing = true;2664}2665
2666landscapeScroll(activeSlide.closest(SLIDES_WRAPPER_SEL), activeSlide);2667
2668if(typeof noCallbacks !== 'undefined'){2669isResizing = false;2670}2671
2672setScrollingSpeed(originals.scrollingSpeed, 'internal');2673}2674
2675/**2676* Scrolls silently (with no animation) the page to the given Y position.
2677*/
2678function silentScroll(top){2679// The first section can have a negative value in iOS 10. Not quite sure why: -0.01428222656252680// that's why we round it to 0.2681var roundedTop = Math.round(top);2682
2683if (options.css3 && options.autoScrolling && !options.scrollBar){2684var translate3d = 'translate3d(0px, -' + roundedTop + 'px, 0px)';2685transformContainer(translate3d, false);2686}2687else if(options.autoScrolling && !options.scrollBar){2688container.css('top', -roundedTop);2689}2690else{2691$htmlBody.scrollTop(roundedTop);2692}2693}2694
2695/**2696* Returns the cross-browser transform string.
2697*/
2698function getTransforms(translate3d){2699return {2700'-webkit-transform': translate3d,2701'-moz-transform': translate3d,2702'-ms-transform':translate3d,2703'transform': translate3d2704};2705}2706
2707/**2708* Allowing or disallowing the mouse/swipe scroll in a given direction. (not for keyboard)
2709* @type m (mouse) or k (keyboard)
2710*/
2711function setIsScrollAllowed(value, direction, type){2712switch (direction){2713case 'up': isScrollAllowed[type].up = value; break;2714case 'down': isScrollAllowed[type].down = value; break;2715case 'left': isScrollAllowed[type].left = value; break;2716case 'right': isScrollAllowed[type].right = value; break;2717case 'all':2718if(type == 'm'){2719setAllowScrolling(value);2720}else{2721setKeyboardScrolling(value);2722}2723}2724}2725
2726/*2727* Destroys fullpage.js plugin events and optinally its html markup and styles
2728*/
2729function destroy(all){2730setAutoScrolling(false, 'internal');2731setAllowScrolling(false);2732setKeyboardScrolling(false);2733container.addClass(DESTROYED);2734
2735clearTimeout(afterSlideLoadsId);2736clearTimeout(afterSectionLoadsId);2737clearTimeout(resizeId);2738clearTimeout(scrollId);2739clearTimeout(scrollId2);2740
2741$window
2742.off('scroll', scrollHandler)2743.off('hashchange', hashChangeHandler)2744.off('resize', resizeHandler);2745
2746$document
2747.off('click touchstart', SECTION_NAV_SEL + ' a')2748.off('mouseenter', SECTION_NAV_SEL + ' li')2749.off('mouseleave', SECTION_NAV_SEL + ' li')2750.off('click touchstart', SLIDES_NAV_LINK_SEL)2751.off('mouseover', options.normalScrollElements)2752.off('mouseout', options.normalScrollElements);2753
2754$(SECTION_SEL)2755.off('click touchstart', SLIDES_ARROW_SEL);2756
2757clearTimeout(afterSlideLoadsId);2758clearTimeout(afterSectionLoadsId);2759
2760//lets make a mess!2761if(all){2762destroyStructure();2763}2764}2765
2766/*2767* Removes inline styles added by fullpage.js
2768*/
2769function destroyStructure(){2770//reseting the `top` or `translate` properties to 02771silentScroll(0);2772
2773//loading all the lazy load content2774container.find('img[data-src], source[data-src], audio[data-src], iframe[data-src]').each(function(){2775setSrc($(this), 'src');2776});2777
2778container.find('img[data-srcset]').each(function(){2779setSrc($(this), 'srcset');2780});2781
2782$(SECTION_NAV_SEL + ', ' + SLIDES_NAV_SEL + ', ' + SLIDES_ARROW_SEL).remove();2783
2784//removing inline styles2785$(SECTION_SEL).css( {2786'height': '',2787'background-color' : '',2788'padding': ''2789});2790
2791$(SLIDE_SEL).css( {2792'width': ''2793});2794
2795container.css({2796'height': '',2797'position': '',2798'-ms-touch-action': '',2799'touch-action': ''2800});2801
2802$htmlBody.css({2803'overflow': '',2804'height': ''2805});2806
2807// remove .fp-enabled class2808$('html').removeClass(ENABLED);2809
2810// remove .fp-responsive class2811$body.removeClass(RESPONSIVE);2812
2813// remove all of the .fp-viewing- classes2814$.each($body.get(0).className.split(/\s+/), function (index, className) {2815if (className.indexOf(VIEWING_PREFIX) === 0) {2816$body.removeClass(className);2817}2818});2819
2820//removing added classes2821$(SECTION_SEL + ', ' + SLIDE_SEL).each(function(){2822options.scrollOverflowHandler.remove($(this));2823$(this).removeClass(TABLE + ' ' + ACTIVE);2824});2825
2826removeAnimation(container);2827
2828//Unwrapping content2829container.find(TABLE_CELL_SEL + ', ' + SLIDES_CONTAINER_SEL + ', ' + SLIDES_WRAPPER_SEL).each(function(){2830//unwrap not being use in case there's no child element inside and its just text2831$(this).replaceWith(this.childNodes);2832});2833
2834//removing the applied transition from the fullpage wrapper2835container.css({2836'-webkit-transition': 'none',2837'transition': 'none'2838});2839
2840//scrolling the page to the top with no animation2841$htmlBody.scrollTop(0);2842
2843//removing selectors2844var usedSelectors = [SECTION, SLIDE, SLIDES_CONTAINER];2845$.each(usedSelectors, function(index, value){2846$('.' + value).removeClass(value);2847});2848}2849
2850/*2851* Sets the state for a variable with multiple states (original, and temporal)
2852* Some variables such as `autoScrolling` or `recordHistory` might change automatically its state when using `responsive` or `autoScrolling:false`.
2853* This function is used to keep track of both states, the original and the temporal one.
2854* If type is not 'internal', then we assume the user is globally changing the variable.
2855*/
2856function setVariableState(variable, value, type){2857options[variable] = value;2858if(type !== 'internal'){2859originals[variable] = value;2860}2861}2862
2863/**2864* Displays warnings
2865*/
2866function displayWarnings(){2867var extensions = ['fadingEffect', 'continuousHorizontal', 'scrollHorizontally', 'interlockedSlides', 'resetSliders', 'responsiveSlides', 'offsetSections', 'dragAndMove', 'scrollOverflowReset', 'parallax'];2868if($('html').hasClass(ENABLED)){2869showError('error', 'Fullpage.js can only be initialized once and you are doing it multiple times!');2870return;2871}2872
2873// Disable mutually exclusive settings2874if (options.continuousVertical &&2875(options.loopTop || options.loopBottom)) {2876options.continuousVertical = false;2877showError('warn', 'Option `loopTop/loopBottom` is mutually exclusive with `continuousVertical`; `continuousVertical` disabled');2878}2879
2880if(options.scrollBar && options.scrollOverflow){2881showError('warn', 'Option `scrollBar` is mutually exclusive with `scrollOverflow`. Sections with scrollOverflow might not work well in Firefox');2882}2883
2884if(options.continuousVertical && (options.scrollBar || !options.autoScrolling)){2885options.continuousVertical = false;2886showError('warn', 'Scroll bars (`scrollBar:true` or `autoScrolling:false`) are mutually exclusive with `continuousVertical`; `continuousVertical` disabled');2887}2888
2889//using extensions? Wrong file!2890$.each(extensions, function(index, extension){2891//is the option set to true?2892if(options[extension]){2893showError('warn', 'fullpage.js extensions require jquery.fullpage.extensions.min.js file instead of the usual jquery.fullpage.js. Requested: '+ extension);2894}2895});2896
2897//anchors can not have the same value as any element ID or NAME2898$.each(options.anchors, function(index, name){2899
2900//case insensitive selectors (http://stackoverflow.com/a/19465187/1081396)2901var nameAttr = $document.find('[name]').filter(function() {2902return $(this).attr('name') && $(this).attr('name').toLowerCase() == name.toLowerCase();2903});2904
2905var idAttr = $document.find('[id]').filter(function() {2906return $(this).attr('id') && $(this).attr('id').toLowerCase() == name.toLowerCase();2907});2908
2909if(idAttr.length || nameAttr.length ){2910showError('error', 'data-anchor tags can not have the same value as any `id` element on the site (or `name` element for IE).');2911idAttr.length && showError('error', '"' + name + '" is is being used by another element `id` property');2912nameAttr.length && showError('error', '"' + name + '" is is being used by another element `name` property');2913}2914});2915}2916
2917/**2918* Shows a message in the console of the given type.
2919*/
2920function showError(type, text){2921console && console[type] && console[type]('fullPage: ' + text);2922}2923
2924}; //end of $.fn.fullpage2925
2926if(typeof IScroll !== 'undefined'){2927/*2928* Turns iScroll `mousewheel` option off dynamically
2929* https://github.com/cubiq/iscroll/issues/1036
2930*/
2931IScroll.prototype.wheelOn = function () {2932this.wrapper.addEventListener('wheel', this);2933this.wrapper.addEventListener('mousewheel', this);2934this.wrapper.addEventListener('DOMMouseScroll', this);2935};2936
2937/*2938* Turns iScroll `mousewheel` option on dynamically
2939* https://github.com/cubiq/iscroll/issues/1036
2940*/
2941IScroll.prototype.wheelOff = function () {2942this.wrapper.removeEventListener('wheel', this);2943this.wrapper.removeEventListener('mousewheel', this);2944this.wrapper.removeEventListener('DOMMouseScroll', this);2945};2946}2947
2948/**2949* An object to handle overflow scrolling.
2950* This uses jquery.slimScroll to accomplish overflow scrolling.
2951* It is possible to pass in an alternate scrollOverflowHandler
2952* to the fullpage.js option that implements the same functions
2953* as this handler.
2954*
2955* @type {Object}
2956*/
2957var iscrollHandler = {2958refreshId: null,2959iScrollInstances: [],2960
2961// Enables or disables the mouse wheel for the active section or all slides in it2962toggleWheel: function(value){2963var scrollable = $(SECTION_ACTIVE_SEL).find(SCROLLABLE_SEL);2964scrollable.each(function(){2965var iScrollInstance = $(this).data('iscrollInstance');2966if(typeof iScrollInstance !== 'undefined' && iScrollInstance){2967if(value){2968iScrollInstance.wheelOn();2969}2970else{2971iScrollInstance.wheelOff();2972}2973}2974});2975},2976
2977/**2978* Turns off iScroll for the destination section.
2979* When scrolling very fast on some trackpads (and Apple laptops) the inertial scrolling would
2980* scroll the destination section/slide before the sections animations ends.
2981*/
2982onLeave: function(){2983iscrollHandler.toggleWheel(false);2984},2985
2986// Turns off iScroll for the leaving section2987beforeLeave: function(){2988iscrollHandler.onLeave()2989},2990
2991// Turns on iScroll on section load2992afterLoad: function(){2993iscrollHandler.toggleWheel(true);2994},2995
2996/**2997* Called when overflow scrolling is needed for a section.
2998*
2999* @param {Object} element jQuery object containing current section
3000* @param {Number} scrollHeight Current window height in pixels
3001*/
3002create: function(element, scrollHeight) {3003var scrollable = element.find(SCROLLABLE_SEL);3004
3005scrollable.height(scrollHeight);3006scrollable.each(function() {3007var $this = $(this);3008var iScrollInstance = $this.data('iscrollInstance');3009if (iScrollInstance) {3010$.each(iscrollHandler.iScrollInstances, function(){3011$(this).destroy();3012});3013}3014
3015iScrollInstance = new IScroll($this.get(0), iscrollOptions);3016iscrollHandler.iScrollInstances.push(iScrollInstance);3017
3018//off by default until the section gets active3019iScrollInstance.wheelOff();3020
3021$this.data('iscrollInstance', iScrollInstance);3022});3023},3024
3025/**3026* Return a boolean depending on whether the scrollable element is a
3027* the end or at the start of the scrolling depending on the given type.
3028*
3029* @param {String} type Either 'top' or 'bottom'
3030* @param {Object} scrollable jQuery object for the scrollable element
3031* @return {Boolean}
3032*/
3033isScrolled: function(type, scrollable) {3034var scroller = scrollable.data('iscrollInstance');3035
3036//no scroller?3037if (!scroller) {3038return true;3039}3040
3041if (type === 'top') {3042return scroller.y >= 0 && !scrollable.scrollTop();3043} else if (type === 'bottom') {3044return (0 - scroller.y) + scrollable.scrollTop() + 1 + scrollable.innerHeight() >= scrollable[0].scrollHeight;3045}3046},3047
3048/**3049* Returns the scrollable element for the given section.
3050* If there are landscape slides, will only return a scrollable element
3051* if it is in the active slide.
3052*
3053* @param {Object} activeSection jQuery object containing current section
3054* @return {Boolean}
3055*/
3056scrollable: function(activeSection){3057// if there are landscape slides, we check if the scrolling bar is in the current one or not3058if (activeSection.find(SLIDES_WRAPPER_SEL).length) {3059return activeSection.find(SLIDE_ACTIVE_SEL).find(SCROLLABLE_SEL);3060}3061return activeSection.find(SCROLLABLE_SEL);3062},3063
3064/**3065* Returns the scroll height of the wrapped content.
3066* If this is larger than the window height minus section padding,
3067* overflow scrolling is needed.
3068*
3069* @param {Object} element jQuery object containing current section
3070* @return {Number}
3071*/
3072scrollHeight: function(element) {3073return element.find(SCROLLABLE_SEL).children().first().get(0).scrollHeight;3074},3075
3076/**3077* Called when overflow scrolling is no longer needed for a section.
3078*
3079* @param {Object} element jQuery object containing current section
3080*/
3081remove: function(element) {3082var scrollable = element.find(SCROLLABLE_SEL);3083if (scrollable.length) {3084var iScrollInstance = scrollable.data('iscrollInstance');3085iScrollInstance.destroy();3086
3087scrollable.data('iscrollInstance', null);3088}3089element.find(SCROLLABLE_SEL).children().first().children().first().unwrap().unwrap();3090},3091
3092/**3093* Called when overflow scrolling has already been setup but the
3094* window height has potentially changed.
3095*
3096* @param {Object} element jQuery object containing current section
3097* @param {Number} scrollHeight Current window height in pixels
3098*/
3099update: function(element, scrollHeight) {3100//using a timeout in order to execute the refresh function only once when `update` is called multiple times in a3101//short period of time.3102//it also comes on handy because iScroll requires the use of timeout when using `refresh`.3103clearTimeout(iscrollHandler.refreshId);3104iscrollHandler.refreshId = setTimeout(function(){3105$.each(iscrollHandler.iScrollInstances, function(){3106$(this).get(0).refresh();3107});3108}, 150);3109
3110//updating the wrappers height3111element.find(SCROLLABLE_SEL).css('height', scrollHeight + 'px').parent().css('height', scrollHeight + 'px');3112},3113
3114/**3115* Called to get any additional elements needed to wrap the section
3116* content in order to facilitate overflow scrolling.
3117*
3118* @return {String|Object} Can be a string containing HTML,
3119* a DOM element, or jQuery object.
3120*/
3121wrapContent: function() {3122return '<div class="' + SCROLLABLE + '"><div class="fp-scroller"></div></div>';3123}3124};3125});