PageSourceSearch

https://middachten.nl/wp-content/plugins/ova-framework/assets/libs…/fullpage.extensions.min.js?ver=3.0.4

js middachten.nl collected 2026-10-02 11:16:40 UTC 111,564 bytes, 2,971 lines download raw bytes

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

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.