PageSourceSearch

https://nscc.co.kr/static/pc/js/libs/fullpage.js

js nscc.co.kr collected 2026-10-04 10:43:44 UTC 142,864 bytes, 3,865 lines download raw bytes

1/*!
2 * fullPage 3.0.0
3 * https://github.com/alvarotrigo/fullPage.js
4 *
5 * @license GPLv3 for open source use only
6 * or Fullpage Commercial License for commercial use
7 * http://alvarotrigo.com/fullPage/pricing/
8 *
9 * Copyright (C) 2018 http://alvarotrigo.com/fullPage - A project by Alvaro Trigo
10 */
11(function( root, window, document, factory, undefined) {
12    if( typeof define === 'function' && define.amd ) {
13        // AMD. Register as an anonymous module.
14        define( function() {
15            root.fullpage = factory(window, document);
16            return root.fullpage;
17        } );
18    } else if( typeof exports === 'object' ) {
19        // Node. Does not work with strict CommonJS.
20        module.exports = factory(window, document);
21    } else {
22        // Browser globals.
23        window.fullpage = factory(window, document);
24    }
25}(this, window, document, function(window, document){
26    'use strict';
27
28    // keeping central set of classnames and selectors
29    var WRAPPER =               'fullpage-wrapper';
30    var WRAPPER_SEL =           '.' + WRAPPER;
31
32    // slimscroll
33    var SCROLLABLE =            'fp-scrollable';
34    var SCROLLABLE_SEL =        '.' + SCROLLABLE;
35
36    // util
37    var RESPONSIVE =            'fp-responsive';
38    var NO_TRANSITION =         'fp-notransition';
39    var DESTROYED =             'fp-destroyed';
40    var ENABLED =               'fp-enabled';
41    var VIEWING_PREFIX =        'fp-viewing';
42    var ACTIVE =                'active';
43    var ACTIVE_SEL =            '.' + ACTIVE;
44    var COMPLETELY =            'fp-completely';
45    var COMPLETELY_SEL =        '.' + COMPLETELY;
46
47    // section
48    var SECTION_DEFAULT_SEL =   '.section';
49    var SECTION =               'fp-section';
50    var SECTION_SEL =           '.' + SECTION;
51    var SECTION_ACTIVE_SEL =    SECTION_SEL + ACTIVE_SEL;
52    var TABLE_CELL =            'fp-tableCell';
53    var TABLE_CELL_SEL =        '.' + TABLE_CELL;
54    var AUTO_HEIGHT =           'fp-auto-height';
55    var AUTO_HEIGHT_SEL =       '.' + AUTO_HEIGHT;
56    var NORMAL_SCROLL =         'fp-normal-scroll';
57    var NORMAL_SCROLL_SEL =     '.' + NORMAL_SCROLL;
58
59    // section nav
60    var SECTION_NAV =           'fp-nav';
61    var SECTION_NAV_SEL =       '#' + SECTION_NAV;
62    var SECTION_NAV_TOOLTIP =   'fp-tooltip';
63    var SECTION_NAV_TOOLTIP_SEL='.'+SECTION_NAV_TOOLTIP;
64    var SHOW_ACTIVE_TOOLTIP =   'fp-show-active';
65
66    // slide
67    var SLIDE_DEFAULT_SEL =     '.slide';
68    var SLIDE =                 'fp-slide';
69    var SLIDE_SEL =             '.' + SLIDE;
70    var SLIDE_ACTIVE_SEL =      SLIDE_SEL + ACTIVE_SEL;
71    var SLIDES_WRAPPER =        'fp-slides';
72    var SLIDES_WRAPPER_SEL =    '.' + SLIDES_WRAPPER;
73    var SLIDES_CONTAINER =      'fp-slidesContainer';
74    var SLIDES_CONTAINER_SEL =  '.' + SLIDES_CONTAINER;
75    var TABLE =                 'fp-table';
76
77    // slide nav
78    var SLIDES_NAV =            'fp-slidesNav';
79    var SLIDES_NAV_SEL =        '.' + SLIDES_NAV;
80    var SLIDES_NAV_LINK_SEL =   SLIDES_NAV_SEL + ' a';
81    var SLIDES_ARROW =          'fp-controlArrow';
82    var SLIDES_ARROW_SEL =      '.' + SLIDES_ARROW;
83    var SLIDES_PREV =           'fp-prev';
84    var SLIDES_PREV_SEL =       '.' + SLIDES_PREV;
85    var SLIDES_ARROW_PREV =     SLIDES_ARROW + ' ' + SLIDES_PREV;
86    var SLIDES_ARROW_PREV_SEL = SLIDES_ARROW_SEL + SLIDES_PREV_SEL;
87    var SLIDES_NEXT =           'fp-next';
88    var SLIDES_NEXT_SEL =       '.' + SLIDES_NEXT;
89    var SLIDES_ARROW_NEXT =     SLIDES_ARROW + ' ' + SLIDES_NEXT;
90    var SLIDES_ARROW_NEXT_SEL = SLIDES_ARROW_SEL + SLIDES_NEXT_SEL;
91
92    function initialise(containerSelector, options) {
93        var isLicenseValid = options && new RegExp('([\\d\\w]{8}-){3}[\\d\\w]{8}|OPEN-SOURCE-GPLV3-LICENSE').test(options.licenseKey) || document.domain.indexOf('alvarotrigo.com') > -1;
94
95        //only once my friend!
96        if(hasClass($('html'), ENABLED)){ displayWarnings(); return; }
97
98        // common jQuery objects
99        var $htmlBody = $('html, body');
100        var $body = $('body')[0];
101
102        var FP = {};
103
104        // Creating some defaults, extending them with any options that were provided
105        options = deepExtend({
106            //navigation
107            menu: false,
108            anchors:[],
109            lockAnchors: false,
110            navigation: false,
111            navigationPosition: 'right',
112            navigationTooltips: [],
113            showActiveTooltip: false,
114            slidesNavigation: false,
115            slidesNavPosition: 'bottom',
116            scrollBar: false,
117            hybrid: false,
118
119            //scrolling
120            css3: true,
121            scrollingSpeed: 700,
122            autoScrolling: true,
123            fitToSection: true,
124            fitToSectionDelay: 1000,
125            easing: 'easeInOutCubic',
126            easingcss3: 'ease',
127            loopBottom: false,
128            loopTop: false,
129            loopHorizontal: true,
130            continuousVertical: false,
131            continuousHorizontal: false,
132            scrollHorizontally: false,
133            interlockedSlides: false,
134            dragAndMove: false,
135            offsetSections: false,
136            resetSliders: false,
137            fadingEffect: false,
138            normalScrollElements: null,
139            scrollOverflow: false,
140            scrollOverflowReset: false,
141            scrollOverflowHandler: window.fp_scrolloverflow ? window.fp_scrolloverflow.iscrollHandler : null,
142            scrollOverflowOptions: null,
143            touchSensitivity: 5,
144            normalScrollElementTouchThreshold: 5,
145            bigSectionsDestination: null,
146
147            //Accessibility
148            keyboardScrolling: true,
149            animateAnchor: true,
150            recordHistory: true,
151
152            //design
153            controlArrows: true,
154            controlArrowColor: '#fff',
155            verticalCentered: true,
156            sectionsColor : [],
157            paddingTop: 0,
158            paddingBottom: 0,
159            fixedElements: null,
160            responsive: 0, //backwards compabitility with responsiveWiddth
161            responsiveWidth: 0,
162            responsiveHeight: 0,
163            responsiveSlides: false,
164            parallax: false,
165            parallaxOptions: {
166                type: 'reveal',
167                percentage: 62,
168                property: 'translate'
169            },
170
171            //Custom selectors
172            sectionSelector: SECTION_DEFAULT_SEL,
173            slideSelector: SLIDE_DEFAULT_SEL,
174
175            //events
176            v2compatible: false,
177            afterLoad: null,
178            onLeave: null,
179            afterRender: null,
180            afterResize: null,
181            afterReBuild: null,
182            afterSlideLoad: null,
183            onSlideLeave: null,
184            afterResponsive: null,
185
186            lazyLoading: true
187        }, options);
188
189        //flag to avoid very fast sliding for landscape sliders
190        var slideMoving = false;
191
192        var isTouchDevice = navigator.userAgent.match(/(iPhone|iPod|iPad|Android|playbook|silk|BlackBerry|BB10|Windows Phone|Tizen|Bada|webOS|IEMobile|Opera Mini)/);
193        var isTouch = (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0) || (navigator.maxTouchPoints));
194        var container = $(containerSelector)[0];
195        var windowsHeight = getWindowHeight();
196        var isResizing = false;
197        var isWindowFocused = true;
198        var lastScrolledDestiny;
199        var lastScrolledSlide;
200        var canScroll = true;
201        var scrollings = [];
202        var controlPressed;
203        var startingSection;
204        var isScrollAllowed = {};
205        isScrollAllowed.m = {  'up':true, 'down':true, 'left':true, 'right':true };
206        isScrollAllowed.k = deepExtend({}, isScrollAllowed.m);
207        var MSPointer = getMSPointer();
208        var events = {
209            touchmove: 'ontouchmove' in window ? 'touchmove' :  MSPointer.move,
210            touchstart: 'ontouchstart' in window ? 'touchstart' :  MSPointer.down
211        };
212        var scrollBarHandler;
213
214        // taken from https://github.com/udacity/ud891/blob/gh-pages/lesson2-focus/07-modals-and-keyboard-traps/solution/modal.js
215        var focusableElementsString = 'a[href], area[href], input
215:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex="0"], [contenteditable]';
216
217        //timeouts
218        var resizeId;
219        var afterSectionLoadsId;
220        var afterSlideLoadsId;
221        var scrollId;
222        var scrollId2;
223        var keydownId;
224        var originals = deepExtend({}, options); //deep copy
225        var activeAnimation;
226
227    //    displayWarnings();
228
229        //easeInOutCubic animation included in the plugin
230        window.fp_easings = deepExtend(window.fp_easings, {
231            easeInOutCubic: function (t, b, c, d) {
232                if ((t/=d/2) < 1) return c/2*t*t*t + b;return c/2*((t-=2)*t*t + 2) + b;
233            }
234        });
235
236        /**
237        * Sets the autoScroll option.
238        * It changes the scroll bar visibility and the history of the site as a result.
239        */
240        function setAutoScrolling(value, type){
241            //removing the transformation
242            if(!value){
243                silentScroll(0);
244            }
245
246            setVariableState('autoScrolling', value, type);
247
248            var element = $(SECTION_ACTIVE_SEL)[0];
249
250            if(options.autoScrolling && !options.scrollBar){
251                css($htmlBody, {
252                    'overflow': 'hidden',
253                    'height': '100%'
254                });
255
256                setRecordHistory(originals.recordHistory, 'internal');
257
258                //for IE touch devices
259                css(container, {
260                    '-ms-touch-action': 'none',
261                    'touch-action': 'none'
262                });
263
264                if(element != null){
265                    //moving the container up
266                    silentScroll(element.offsetTop);
267                }
268
269            }else{
270                css($htmlBody, {
271                    'overflow' : 'visible',
272                    'height' : 'initial'
273                });
274
275                setRecordHistory(false, 'internal');
276
277                //for IE touch devices
278                css(container, {
279                    '-ms-touch-action': '',
280                    'touch-action': ''
281                });
282
283                //scrolling the page to the section with no animation
284                if (element != null) {
285                    var scrollSettings = getScrollSettings(element.offsetTop);
286                    scrollSettings.element.scrollTo(0, scrollSettings.options);
287                }
288            }
289        }
290
291        /**
292        * Defines wheter to record the history for each hash change in the URL.
293        */
294        function setRecordHistory(value, type){
295            setVariableState('recordHistory', value, type);
296        }
297
298        /**
299        * Defines the scrolling speed
300        */
301        function setScrollingSpeed(value, type){
302            setVariableState('scrollingSpeed', value, type);
303        }
304
305        /**
306        * Sets fitToSection
307        */
308        function setFitToSection(value, type){
309            setVariableState('fitToSection', value, type);
310        }
311
312        /**
313        * Sets lockAnchors
314        */
315        function setLockAnchors(value){
316            options.lockAnchors = value;
317        }
318
319        /**
320        * Adds or remove the possibility of scrolling through sections by using the mouse wheel or the trackpad.
321        */
322        function setMouseWheelScrolling(value){
323            if(value){
324                addMouseWheelHandler();
325                addMiddleWheelHandler();
326            }else{
327                removeMouseWheelHandler();
328                removeMiddleWheelHandler();
329            }
330        }
331
332        /**
333        * Adds or remove the possibility of scrolling through sections by using the mouse wheel/trackpad or touch gestures.
334        * Optionally a second parameter can be used to specify the direction for which the action will be applied.
335        *
336        * @param directions string containing the direction or directions separated by comma.
337        */
338        function setAllowScrolling(value, directions){
339            if(typeof directions !== 'undefined'){
340                directions = directions.replace(/ /g,'').split(',');
341
342                directions.forEach(function (direction){
343                    setIsScrollAllowed(value, direction, 'm');
344                });
345            }
346            else{
347                setIsScrollAllowed(value, 'all', 'm');
348
349                if(value){
350                    setMouseWheelScrolling(true);
351                    addTouchHandler();
352                }else{
353                    setMouseWheelScrolling(false);
354                    removeTouchHandler();
355                }
356            }
357        }
358
359        /**
360        * Adds or remove the possibility of scrolling through sections by using the keyboard arrow keys
361        */
362        function setKeyboardScrolling(value, directions){
363            if(typeof directions !== 'undefined'){
364                directions = directions.replace(/ /g,'').split(',');
365
366                directions.forEach(function(direction){
367                    setIsScrollAllowed(value, direction, 'k');
368                });
369            }else{
370                setIsScrollAllowed(value, 'all', 'k');
371                options.keyboardScrolling = value;
372            }
373        }
374
375        /**
376        * Moves the page up one section.
377        */
378        function moveSectionUp(){
379            var prev = prevUntil($(SECTION_ACTIVE_SEL)[0], SECTION_SEL);
380
381            //looping to the bottom if there's no more sections above
382            if (!prev && (options.loopTop || options.continuousVertical)) {
383                prev = last($(SECTION_SEL));
384            }
385
386            if (prev != null) {
387                scrollPage(prev, null, true);
388            }
389        }
390
391        /**
392        * Moves the page down one section.
393        */
394        function moveSectionDown(){
395            var next = nextUntil($(SECTION_ACTIVE_SEL)[0], SECTION_SEL);
396
397            //looping to the top if there's no more sections below
398            if(!next &&
399                (options.loopBottom || options.continuousVertical)){
400                next = $(SECTION_SEL)[0];
401            }
402
403            if(next != null){
404                scrollPage(next, null, false);
405            }
406        }
407
408        /**
409        * Moves the page to the given section and slide with no animation.
410        * Anchors or index positions can be used as params.
411        */
412        function silentMoveTo(sectionAnchor, slideAnchor){
413            setScrollingSpeed (0, 'internal');
414            moveTo(sectionAnchor, slideAnchor);
415            setScrollingSpeed (originals.scrollingSpeed, 'internal');
416        }
417
418        /**
419        * Moves the page to the given section and slide.
420        * Anchors or index positions can be used as params.
421        */
422        function moveTo(sectionAnchor, slideAnchor){
423            var destiny = getSectionByAnchor(sectionAnchor);
424
425            if (typeof slideAnchor !== 'undefined'){
426                scrollPageAndSlide(sectionAnchor, slideAnchor);
427            }else if(destiny != null){
428                scrollPage(destiny);
429            }
430        }
431
432        /**
433        * Slides right the slider of the active section.
434        * Optional `section` param.
435        */
436        function moveSlideRight(section){
437            moveSlide('right', section);
438        }
439
440        /**
441        * Slides left the slider of the active section.
442        * Optional `section` param.
443        */
444        function moveSlideLeft(section){
445            moveSlide('left', section);
446        }
447
448        /**
449         * When resizing is finished, we adjust the slides sizes and positions
450         */
451        function reBuild(resizing){
452            if(hasClass(container, DESTROYED)){ return; }  //nothing to do if the plugin was destroyed
453
454            isResizing = true;
455
456            windowsHeight = getWindowHeight();  //updating global var
457
458            var sections = $(SECTION_SEL);
459            for (var i = 0; i < sections.length; ++i) {
460                var section = sections[i];
461                var slidesWrap = $(SLIDES_WRAPPER_SEL, section)[0];
462                var slides = $(SLIDE_SEL, section);
463
464                //adjusting the height of the table-cell for IE and Firefox
465                if(options.verticalCentered){
466                    css($(TABLE_CELL_SEL, section), {'height': getTableHeight(section) + 'px'});
467                }
468
469                css(section, {'height': windowsHeight + 'px'});
470
471                //adjusting the position fo the FULL WIDTH slides...
472                if (slides.length > 1) {
473                    landscapeScroll(slidesWrap, $(SLIDE_ACTIVE_SEL, slidesWrap)[0]);
474                }
475            }
476
477            if(options.scrollOverflow){
478                scrollBarHandler.createScrollBarForAll();
479            }
480
481            var activeSection = $(SECTION_ACTIVE_SEL)[0];
482            var sectionIndex = index(activeSection, SECTION_SEL);
483
484            //isn't it the first section?
485            if(sectionIndex){
486                //adjusting the position for the current section
487                silentMoveTo(sectionIndex + 1);
488            }
489
490            isResizing = false;
491            if(isFunction( options.afterResize ) && resizing){
492                options.afterResize.call(container, window.innerWidth, window.innerHeight);
493            }
494            if(isFunction( options.afterReBuild ) && !resizing){
495                options.afterReBuild.call(container);
496            }
497        }
498
499        /**
500        * Turns fullPage.js to normal scrolling mode when the viewport `width` or `height`
501        * are smaller than the set limit values.
502        */
503        function setResponsive(active){
504            var isResponsive = hasClass($body, RESPONSIVE);
505
506            if(active){
507                if(!isResponsive){
508                    setAutoScrolling(false, 'internal');
509                    setFitToSection(false, 'internal');
510                    hide($(SECTION_NAV_SEL));
511                    addClass($body, RESPONSIVE);
512                    if(isFunction( options.afterResponsive )){
513                        options.afterResponsive.call( container, active);
514                    }
515                }
516            }
517            else if(isResponsive){
518                setAutoScrolling(originals.autoScrolling, 'internal');
519                setFitToSection(originals.autoScrolling, 'internal');
520                show($(SECTION_NAV_SEL));
521                removeClass($body, RESPONSIVE);
522                if(isFunction( options.afterResponsive )){
523                    options.afterResponsive.call( container, active);
524                }
525            }
526        }
527
528        if($(containerSelector).length){
529            //public functions
530            FP.version = '3.0.0';
531            FP.setAutoScrolling = setAutoScrolling;
532            FP.setRecordHistory = setRecordHistory;
533            FP.setScrollingSpeed = setScrollingSpeed;
534            FP.setFitToSection = setFitToSection;
535            FP.setLockAnchors = setLockAnchors;
536            FP.setMouseWheelScrolling = setMouseWheelScrolling;
537            FP.setAllowScrolling = setAllowScrolling;
538            FP.setKeyboardScrolling = setKeyboardScrolling;
539            FP.moveSectionUp = moveSectionUp;
540            FP.moveSectionDown = moveSectionDown;
541            FP.silentMoveTo = silentMoveTo;
542            FP.moveTo = moveTo;
543            FP.moveSlideRight = moveSlideRight;
544            FP.moveSlideLeft = moveSlideLeft;
545            FP.fitToSection = fitToSection;
546            FP.reBuild = reBuild;
547            FP.setResponsive = setResponsive;
548            FP.getFullpageData = options;
549            FP.destroy = destroy;
550            FP.getActiveSection = getActiveSection;
551            FP.getActiveSlide = getActiveSlide;
552
553            FP.test = {
554                top: '0px',
555                translate3d: 'translate3d(0px, 0px, 0px)',
556                translate3dH: (function(){
557                    var a = [];
558                    for(var i = 0; i < $(options.sectionSelector, container).length; i++){
559                        a.push('translate3d(0px, 0px, 0px)');
560                    }
561                    return a;
562                })(),
563                left: (function(){
564                    var a = [];
565                    for(var i = 0; i < $(options.sectionSelector, container).length; i++){
566                        a.push(0);
567                    }
568                    return a;
569                })(),
570                options: options,
571                setAutoScrolling: setAutoScrolling
572            };
573
574            //functions we want to share across files but which are not
575            //mean to be used on their own by developers
576            FP.shared = {
577                afterRenderActions: afterRenderActions
578            };
579
580            window.fullpage_api = FP;
581
582            init();
583
584            bindEvents();
585        }
586
587        function init(){
588            //if css3 is not supported, it will use jQuery animations
589            if(options.css3){
590                options.css3 = support3d();
591            }
592
593            options.scrollBar = options.scrollBar || options.hybrid;
594
595            setOptionsFromDOM();
596            prepareDom();
597            setAllowScrolling(true);
598            setAutoScrolling(options.autoScrolling, 'internal');
599            responsive();
600
601            //setting the class for the body element
602            setBodyClass();
603
604            if(document.readyState === 'complete'){
605                scrollToAnchor();
606            }
607            window.addEventListener('load', scrollToAnchor);
608        }
609
610        function bindEvents(){
611
612            //when scrolling...
613            window.addEventListener('scroll', scrollHandler);
614
615            //detecting any change on the URL to scroll to the given anchor link
616            //(a way to detect back history button as we play with the hashes on the URL)
617            window.addEventListener('hashchange', hashChangeHandler);
618
619            //when opening a new tab (ctrl + t), `control` won't be pressed when coming back.
620            window.addEventListener('blur', blurHandler);
621
622            //when resizing the site, we adjust the heights of the sections, slimScroll...
623            window.addEventListener('resize', resizeHandler);
624
625            //Sliding with arrow keys, both, vertical and horizontal
626            document.addEventListener('keydown', keydownHandler);
627
628            //to prevent scrolling while zooming
629            document.addEventListener('keyup', keyUpHandler);
630
631            //Scrolls to the section when clicking the navigation bullet
632            //simulating the jQuery .on('click') event using delegation
633            ['click', 'touchstart'].forEach(function(eventName){
634                document.addEventListener(eventName, function(e){
635                    var target = e.target;
636
637                    if(target && matches(target, SECTION_NAV_SEL + ' a')){
638                        sectionBulletHandler.call(target);
639                    }
640                    else if(matches(target, SECTION_NAV_TOOLTIP_SEL)){
641                        tooltipTextHandler.call(target);
642                    }
643                    else if(matches(target, SLIDES_ARROW_SEL)){
644                        slideArrowHandler.call(target, e);
645                    }
646                    else if(matches(target, SLIDES_NAV_LINK_SEL) || closest(target, SLIDES_NAV_LINK_SEL) != null){
647                        slideBulletHandler.call(target, e);
648                    }
649                });
650            });
651
652            /**
653            * Applying normalScroll elements.
654            * Ignoring the scrolls over the specified selectors.
655            */
656            if(options.normalScrollElements){
657                ['mouseenter', 'touchstart'].forEach(function(eventName){
658                    forMouseLeaveOrTOuch(eventName, false);
659                });
660
661                ['mouseleave', 'touchend'].forEach(function(eventName){
662                   forMouseLeaveOrTOuch(eventName, true);
663                });
664            }
665        }
666
667        function forMouseLeaveOrTOuch(eventName, allowScrolling){
668            //a way to pass arguments to the onMouseEnterOrLeave function
669            document['fp_' + eventName] = allowScrolling;
670            document.addEventListener(eventName, onMouseEnterOrLeave, true); //capturing phase
671        }
672
673        function onMouseEnterOrLeave(e) {
674            if(e.target == document){
675                return;
676            }
677            var normalSelectors = options.normalScrollElements.split(',');
678            normalSelectors.forEach(function(normalSelector){
679                if(matches(e.target, normalSelector)){
680                    setAllowScrolling(document['fp_' + e.type]); //e.type = eventName
681                }
682            });
683        }
684
685        /**
686        * Setting options from DOM elements if they are not provided.
687        */
688        function setOptionsFromDOM(){
689
690            //no anchors option? Checking for them in the DOM attributes
691            if(!options.anchors.length){
692                var anchors = $(SECTION_SEL+'[data-anchor]');
693                if(anchors.length){
694                    anchors.forEach(function(item){
695                        options.anchors.push(item.getAttribute('data-anchor').toString());
696                    });
697                }
698            }
699
700            //no tooltips option? Checking for them in the DOM attributes
701            if(!options.navigationTooltips.length){
702                var tooltips = $('[data-tooltip]', container);
703                if(tooltips.length){
704                    tooltips.forEach(function(item){
705                        options.navigationTooltips.push(item.getAttribute('data-tooltip').toString());
706                    });
707                }
708            }
709        }
710
711        /**
712        * Works over the DOM structure to set it up for the current fullpage options.
713        */
714        function prepareDom(){
715            css(container, {
716                'height': '100%',
717                'position': 'relative'
718            });
719
720            //adding a class to recognize the container internally in the code
721            addClass(container, WRAPPER);
722            addClass($('html'), ENABLED);
723
724            //due to https://github.com/alvarotrigo/fullPage.js/issues/1502
725            windowsHeight = getWindowHeight();
726
727            removeClass(container, DESTROYED); //in case it was destroyed before initializing it again
728
729            addInternalSelectors();
730
731            var sections = $(SECTION_SEL);
732
733            //styling the sections / slides / menu
734            for(var i = 0; i<sections.length; i++){
735                var index = i;
736                var section = sections[i];
737                var slides = $(SLIDE_SEL, section);
738                var numSlides = slides.length;
739
740                //caching the original styles to add them back on destroy('all')
741                section.setAttribute('data-fp-styles', section.getAttribute('style'));
742
743                styleSection(section, index);
744                styleMenu(section, index);
745
746                // if there's any slide
747                if (numSlides > 0) {
748                    styleSlides(section, slides, numSlides);
749                }else{
750                    if(options.verticalCentered){
751                        addTableClass(section);
752                    }
753                }
754            }
755
756            //fixed elements need to be moved out of the plugin container due to problems with CSS3.
757            if(options.fixedElements && options.css3){
758                $(options.fixedElements).forEach(function(item){
759                    $body.appendChild(item);
760                });
761            }
762
763            //vertical centered of the navigation + active bullet
764            if(options.navigation){
765                addVerticalNavigation();
766            }
767
768            enableYoutubeAPI();
769
770            if(options.scrollOverflow){
771                scrollBarHandler = options.scrollOverflowHandler.init(options);
772            }else{
773                afterRenderActions();
774            }
775        }
776
777        /**
778        * Styles the horizontal slides for a section.
779        */
780        function styleSlides(section, slides, numSlides){
781            var sliderWidth = numSlides * 100;
782            var slideWidth = 100 / numSlides;
783
784            var slidesWrapper = document.createElement('div');
785            slidesWrapper.className = SLIDES_WRAPPER; //fp-slides
786            wrapAll(slides, slidesWrapper);
787
788            var slidesContainer = document.createElement('div');
789            slidesContainer.className = SLIDES_CONTAINER; //fp-slidesContainer
790            wrapAll(slides, slidesContainer);
791
792            css($(SLIDES_CONTAINER_SEL, section), {'width': sliderWidth + '%'});
793
794            if(numSlides > 1){
795                if(options.controlArrows){
796                    createSlideArrows(section);
797                }
798
799                if(options.slidesNavigation){
800                    addSlidesNavigation(section, numSlides);
801                }
802            }
803
804            slides.forEach(function(slide) {
805                css(slide, {'width': slideWidth + '%'});
806
807                if(options.verticalCentered){
808                    addTableClass(slide);
809                }
810            });
811
812            var startingSlide = $(SLIDE_ACTIVE_SEL, section)[0];
813
814            //if the slide won't be an starting point, the default will be the first one
815            //the active section isn't the first one? Is not the first slide of the first section? Then we load that section/sl
815ide by default.
816            if( startingSlide != null && (index($(SECTION_ACTIVE_SEL), SECTION_SEL) !== 0 || (index($(SECTION_ACTIVE_SEL), SECTION_SEL) === 0 && index(startingSlide) !== 0))){
817                silentLandscapeScroll(startingSlide, 'internal');
818            }else{
819                addClass(slides[0], ACTIVE);
820            }
821        }
822
823        /**
824        * Styling vertical sections
825        */
826        function styleSection(section, index){
827            //if no active section is defined, the 1st one will be the default one
828            if(!index && $(SECTION_ACTIVE_SEL)[0] == null) {
829                addClass(section, ACTIVE);
830            }
831            startingSection = $(SECTION_ACTIVE_SEL)[0];
832
833            css(section, {'height': windowsHeight + 'px'});
834
835            if(options.paddingTop){
836                css(section, {'padding-top': options.paddingTop});
837            }
838
839            if(options.paddingBottom){
840                css(section, {'padding-bottom': options.paddingBottom});
841            }
842
843            if (typeof options.sectionsColor[index] !==  'undefined') {
844                css(section, {'background-color': options.sectionsColor[index]});
845            }
846
847            if (typeof options.anchors[index] !== 'undefined') {
848                section.setAttribute('data-anchor', options.anchors[index]);
849            }
850        }
851
852        /**
853        * Sets the data-anchor attributes to the menu elements and activates the current one.
854        */
855        function styleMenu(section, index){
856            if (typeof options.anchors[index] !== 'undefined') {
857                //activating the menu / nav element on load
858                if(hasClass(section, ACTIVE)){
859                    activateMenuAndNav(options.anchors[index], index);
860                }
861            }
862
863            //moving the menu outside the main container if it is inside (avoid problems with fixed positions when using CSS3 tranforms)
864            if(options.menu && options.css3 && closest($(options.menu)[0], WRAPPER_SEL) != null){
865                $body.appendChild($(options.menu)[0]);
866            }
867        }
868
869        /**
870        * Adds internal classes to be able to provide customizable selectors
871        * keeping the link with the style sheet.
872        */
873        function addInternalSelectors(){
874            addClass($(options.sectionSelector, container), SECTION);
875            addClass($(options.slideSelector, container), SLIDE);
876        }
877
878        /**
879        * Creates the control arrows for the given section
880        */
881        function createSlideArrows(section){
882            var arrows = [createElementFromHTML('<div class="' + SLIDES_ARROW_PREV + '"></div>'), createElementFromHTML('<div class="' + SLIDES_ARROW_NEXT + '"></div>')];
883            after($(SLIDES_WRAPPER_SEL, section)[0], arrows);
884
885            if(options.controlArrowColor !== '#fff'){
886                css($(SLIDES_ARROW_NEXT_SEL, section), {'border-color': 'transparent transparent transparent '+options.controlArrowColor});
887                css($(SLIDES_ARROW_PREV_SEL, section), {'border-color': 'transparent '+ options.controlArrowColor + ' transparent transparent'});
888            }
889
890            if(!options.loopHorizontal){
891                hide($(SLIDES_ARROW_PREV_SEL, section));
892            }
893        }
894
895        /**
896        * Creates a vertical navigation bar.
897        */
898        function addVerticalNavigation(){
899            var navigation = document.createElement('div');
900            navigation.setAttribute('id', SECTION_NAV);
901
902            var divUl = document.createElement('ul');
903            navigation.appendChild(divUl);
904
905            appendTo(navigation, $body);
906            var nav = $(SECTION_NAV_SEL)[0];
907
908            addClass(nav, 'fp-' + options.navigationPosition);
909
910            if(options.showActiveTooltip){
911                addClass(nav, SHOW_ACTIVE_TOOLTIP);
912            }
913
914            var li = '';
915
916            for (var i = 0; i < $(SECTION_SEL).length; i++) {
917                var link = '';
918                if (options.anchors.length) {
919                    link = options.anchors[i];
920                }
921
922                li += '<li><a href="#' + link + '"><span></span></a>';
923
924                // Only add tooltip if needed (defined by user)
925                var tooltip = options.navigationTooltips[i];
926
927                if (typeof tooltip !== 'undefined' && tooltip !== '') {
928                    li += '<div class="' + SECTION_NAV_TOOLTIP + ' ' + options.navigationPosition + '">' + tooltip + '</div>';
929                }
930
931                li += '</li>';
932            }
933            $('ul', nav)[0].innerHTML = li;
934
935            //centering it vertically
936            css($(SECTION_NAV_SEL), {'margin-top': '-' + ($(SECTION_NAV_SEL)[0].offsetHeight/2) + 'px'});
937
938            //activating the current active section
939
940            var bullet = $('li', $(SECTION_NAV_SEL)[0])[index($(SECTION_ACTIVE_SEL)[0], SECTION_SEL)];
941            addClass($('a', bullet), ACTIVE);
942        }
943
944        /*
945        * Enables the Youtube videos API so we can control their flow if necessary.
946        */
947        function enableYoutubeAPI(){
948            $('iframe[src*="youtube.com/embed/"]', container).forEach(function(item){
949                addURLParam(item, 'enablejsapi=1');
950            });
951        }
952
953        /**
954        * Adds a new parameter and its value to the `src` of a given element
955        */
956        function addURLParam(element, newParam){
957            var originalSrc = element.getAttribute('src');
958            element.setAttribute('src', originalSrc + getUrlParamSign(originalSrc) + newParam);
959        }
960
961        /*
962        * Returns the prefix sign to use for a new parameter in an existen URL.
963        *
964        * @return {String}  ? | &
965        */
966        function getUrlParamSign(url){
967            return ( !/\?/.test( url ) ) ? '?' : '&';
968        }
969
970        /**
971        * Actions and callbacks to fire afterRender
972        */
973        function afterRenderActions(){
974            var section = $(SECTION_ACTIVE_SEL)[0];
975
976            addClass(section, COMPLETELY);
977
978            lazyLoad(section);
979            playMedia(section);
980
981            if(options.scrollOverflow){
982                options.scrollOverflowHandler.afterLoad();
983            }
984
985            if(isDestinyTheStartingSection() && isFunction(options.afterLoad) ){
986                fireCallback('afterLoad', {
987                    activeSection: null,
988                    element: section,
989                    direction: null,
990
991                    //for backwards compatibility callback (to be removed in a future!)
992                    anchorLink: section.getAttribute('data-anchor'),
993                    sectionIndex: index(section, SECTION_SEL)
994                });
995            }
996
997            if(isFunction(options.afterRender)){
998                fireCallback('afterRender');
999            }
1000        }
1001
1002        /**
1003        * Determines if the URL anchor destiny is the starting section (the one using 'active' class before initialization)
1004        */
1005        function isDestinyTheStartingSection(){
1006            var destinationSection = getSectionByAnchor(getAnchorsURL().section);
1007            return !destinationSection || typeof destinationSection !=='undefined' && index(destinationSection) === index(startingSection);
1008        }
1009
1010        var isScrolling = false;
1011        var lastScroll = 0;
1012
1013        //when scrolling...
1014        function scrollHandler(){
1015            var currentSection;
1016
1017            if(!options.autoScrolling || options.scrollBar){
1018                var currentScroll = getScrollTop();
1019                var scrollDirection = getScrollDirection(currentScroll);
1020                var visibleSectionIndex = 0;
1021                var screen_mid = currentScroll + (getWindowHeight() / 2.0);
1022                var isAtBottom = $body.offsetHeight - getWindowHeight() === currentScroll;
1023                var sections =  $(SECTION_SEL);
1024
1025                //when using `auto-height` for a small last section it won't be centered in the viewport
1026                if(isAtBottom){
1027                    visibleSectionIndex = sections.length - 1;
1028                }
1029                //is at top? when using `auto-height` for a small first section it won't be centered in the viewport
1030                else if(!currentScroll){
1031                    visibleSectionIndex = 0;
1032                }
1033
1034                //taking the section which is showing more content in the viewport
1035                else{
1036                    for (var i = 0; i < sections.length; ++i) {
1037                        var section = sections[i];
1038
1039                        // Pick the the last section which passes the middle line of the screen.
1040                        if (section.offsetTop <= screen_mid)
1041                        {
1042                            visibleSectionIndex = i;
1043                        }
1044                    }
1045                }
1046
1047                if(isCompletelyInViewPort(scrollDirection)){
1048                    if(!hasClass($(SECTION_ACTIVE_SEL)[0], COMPLETELY)){
1049                        addClass($(SECTION_ACTIVE_SEL)[0], COMPLETELY);
1050                        removeClass(siblings($(SECTION_ACTIVE_SEL)[0]), COMPLETELY);
1051                    }
1052                }
1053
1054                //geting the last one, the current one on the screen
1055                currentSection = sections[visibleSectionIndex];
1056
1057                //setting the visible section as active when manually scrolling
1058                //executing only once the first time we reach the section
1059                if(!hasClass(currentSection, ACTIVE)){
1060                    isScrolling = true;
1061                    var leavingSection = $(SECTION_ACTIVE_SEL)[0];
1062                    var leavingSectionIndex = index(leavingSection, SECTION_SEL) + 1;
1063                    var yMovement = getYmovement(currentSection);
1064                    var anchorLink  = currentSection.getAttribute('data-anchor');
1065                    var sectionIndex = index(currentSection, SECTION_SEL) + 1;
1066                    var activeSlide = $(SLIDE_ACTIVE_SEL, currentSection)[0];
1067                    var slideIndex;
1068                    var slideAnchorLink;
1069                    var callbacksParams = {
1070                        activeSection: leavingSection,
1071                        sectionIndex: sectionIndex -1,
1072                        anchorLink: anchorLink,
1073                        element: currentSection,
1074                        leavingSection: leavingSectionIndex,
1075                        direction: yMovement
1076                    };
1077
1078                    if(activeSlide){
1079                        slideAnchorLink = activeSlide.getAttribute('data-anchor');
1080                        slideIndex = index(activeSlide);
1081                    }
1082
1083                    if(canScroll){
1084                        addClass(currentSection, ACTIVE);
1085                        removeClass(siblings(currentSection), ACTIVE);
1086
1087                        if(isFunction( options.onLeave )){
1088                            fireCallback('onLeave', callbacksParams);
1089                        }
1090                        if(isFunction( options.afterLoad )){
1091                            fireCallback('afterLoad', callbacksParams);
1092                        }
1093
1094                        stopMedia(leavingSection);
1095                        lazyLoad(currentSection);
1096                        playMedia(currentSection);
1097
1098                        activateMenuAndNav(anchorLink, sectionIndex - 1);
1099
1100                        if(options.anchors.length){
1101                            //needed to enter in hashChange event when using the menu with anchor links
1102                            lastScrolledDestiny = anchorLink;
1103                        }
1104                        setState(slideIndex, slideAnchorLink, anchorLink, sectionIndex);
1105                    }
1106
1107                    //small timeout in order to avoid entering in hashChange event when scrolling is not finished yet
1108                    clearTimeout(scrollId);
1109                    scrollId = setTimeout(function(){
1110                        isScrolling = false;
1111                    }, 100);
1112                }
1113
1114                if(options.fitToSection){
1115                    //for the auto adjust of the viewport to fit a whole section
1116                    clearTimeout(scrollId2);
1117
1118                    scrollId2 = setTimeout(function(){
1119                        //checking it again in case it changed during the delay
1120                        if(options.fitToSection &&
1121
1122                            //is the destination element bigger than the viewport?
1123                            $(SECTION_ACTIVE_SEL)[0].offsetHeight <= windowsHeight
1124                        ){
1125                            fitToSection();
1126                        }
1127                    }, options.fitToSectionDelay);
1128                }
1129            }
1130        }
1131
1132        /**
1133        * Fits the site to the nearest active section
1134        */
1135        function fitToSection(){
1136            //checking fitToSection again in case it was set to false before the timeout delay
1137            if(canScroll){
1138                //allows to scroll to an active section and
1139                //if the section is already active, we prevent firing callbacks
1140                isResizing = true;
1141
1142                scrollPage($(SECTION_ACTIVE_SEL)[0]);
1143                isResizing = false;
1144            }
1145        }
1146
1147        /**
1148        * Determines whether the active section has seen in its whole or not.
1149        */
1150        function isCompletelyInViewPort(movement){
1151            var top = $(SECTION_ACTIVE_SEL)[0].offsetTop;
1152            var bottom = top + getWindowHeight();
1153
1154            if(movement == 'up'){
1155                return bottom >= (getScrollTop() + getWindowHeight());
1156            }
1157            return top <= getScrollTop();
1158        }
1159
1160        /**
1161        * Gets the directon of the the scrolling fired by the scroll event.
1162        */
1163        function getScrollDirection(currentScroll){
1164            var direction = currentScroll > lastScroll ? 'down' : 'up';
1165
1166            lastScroll = currentScroll;
1167
1168            //needed for auto-height sections to determine if we want to scroll to the top or bottom of the destination
1169            previousDestTop = currentScroll;
1170
1171            return direction;
1172        }
1173
1174        /**
1175        * Determines the way of scrolling up or down:
1176        * by 'automatically' scrolling a section or by using the default and n
1176ormal scrolling.
1177        */
1178        function scrolling(type){
1179            if (!isScrollAllowed.m[type]){
1180                return;
1181            }
1182
1183            var scrollSection = (type === 'down') ? moveSectionDown : moveSectionUp;
1184
1185            if(options.scrollOverflow){
1186                var scrollable = options.scrollOverflowHandler.scrollable($(SECTION_ACTIVE_SEL)[0]);
1187                var check = (type === 'down') ? 'bottom' : 'top';
1188
1189                if(scrollable != null ){
1190                    //is the scrollbar at the start/end of the scroll?
1191                    if(options.scrollOverflowHandler.isScrolled(check, scrollable)){
1192                        scrollSection();
1193                    }else{
1194                        return true;
1195                    }
1196                }else{
1197                    // moved up/down
1198                    scrollSection();
1199                }
1200            }else{
1201                // moved up/down
1202                scrollSection();
1203            }
1204        }
1205
1206        /*
1207        * Preventing bouncing in iOS #2285
1208        */
1209        function preventBouncing(e){
1210            if(options.autoScrolling && isReallyTouch(e)){
1211                //preventing the easing on iOS devices
1212                preventDefault(e);
1213            }
1214        }
1215
1216        var touchStartY = 0;
1217        var touchStartX = 0;
1218        var touchEndY = 0;
1219        var touchEndX = 0;
1220
1221        /* Detecting touch events
1222
1223        * As we are changing the top property of the page on scrolling, we can not use the traditional way to detect it.
1224        * This way, the touchstart and the touch moves shows an small difference between them which is the
1225        * used one to determine the direction.
1226        */
1227        function touchMoveHandler(e){
1228            var activeSection = closest(e.target, SECTION_SEL);
1229
1230            // additional: if one of the normalScrollElements isn't within options.normalScrollElementTouchThreshold hops up the DOM chain
1231            if (isReallyTouch(e) ) {
1232
1233                if(options.autoScrolling){
1234                    //preventing the easing on iOS devices
1235                    preventDefault(e);
1236                }
1237
1238                var touchEvents = getEventsPage(e);
1239
1240                touchEndY = touchEvents.y;
1241                touchEndX = touchEvents.x;
1242
1243                //if movement in the X axys is greater than in the Y and the currect section has slides...
1244                if ($(SLIDES_WRAPPER_SEL, activeSection).length && Math.abs(touchStartX - touchEndX) > (Math.abs(touchStartY - touchEndY))) {
1245
1246                    //is the movement greater than the minimum resistance to scroll?
1247                    if (!slideMoving && Math.abs(touchStartX - touchEndX) > (window.innerWidth / 100 * options.touchSensitivity)) {
1248                        if (touchStartX > touchEndX) {
1249                            if(isScrollAllowed.m.right){
1250                                moveSlideRight(activeSection); //next
1251                            }
1252                        } else {
1253                            if(isScrollAllowed.m.left){
1254                                moveSlideLeft(activeSection); //prev
1255                            }
1256                        }
1257                    }
1258                }
1259
1260                //vertical scrolling (only when autoScrolling is enabled)
1261                else if(options.autoScrolling && canScroll){
1262
1263                    //is the movement greater than the minimum resistance to scroll?
1264                    if (Math.abs(touchStartY - touchEndY) > (window.innerHeight / 100 * options.touchSensitivity)) {
1265                        if (touchStartY > touchEndY) {
1266                            scrolling('down');
1267                        } else if (touchEndY > touchStartY) {
1268                            scrolling('up');
1269                        }
1270                    }
1271                }
1272            }
1273        }
1274
1275        /**
1276        * As IE >= 10 fires both touch and mouse events when using a mouse in a touchscreen
1277        * this way we make sure that is really a touch event what IE is detecting.
1278        */
1279        function isReallyTouch(e){
1280            //if is not IE   ||  IE is detecting `touch` or `pen`
1281            return typeof e.pointerType === 'undefined' || e.pointerType != 'mouse';
1282        }
1283
1284        /**
1285        * Handler for the touch start event.
1286        */
1287        function touchStartHandler(e){
1288
1289            //stopping the auto scroll to adjust to a section
1290            if(options.fitToSection){
1291                activeAnimation = false;
1292            }
1293
1294            if(isReallyTouch(e)){
1295                var touchEvents = getEventsPage(e);
1296                touchStartY = touchEvents.y;
1297                touchStartX = touchEvents.x;
1298            }
1299        }
1300
1301        /**
1302        * Gets the average of the last `number` elements of the given array.
1303        */
1304        function getAverage(elements, number){
1305            var sum = 0;
1306
1307            //taking `number` elements from the end to make the average, if there are not enought, 1
1308            var lastElements = elements.slice(Math.max(elements.length - number, 1));
1309
1310            for(var i = 0; i < lastElements.length; i++){
1311                sum = sum + lastElements[i];
1312            }
1313
1314            return Math.ceil(sum/number);
1315        }
1316
1317        /**
1318         * Detecting mousewheel scrolling
1319         *
1320         * http://blogs.sitepointstatic.com/examples/tech/mouse-wheel/index.html
1321         * http://www.sitepoint.com/html5-javascript-mouse-wheel/
1322         */
1323        var prevTime = new Date().getTime();
1324
1325        function MouseWheelHandler(e) {
1326            var curTime = new Date().getTime();
1327            var isNormalScroll = hasClass($(COMPLETELY_SEL)[0], NORMAL_SCROLL);
1328
1329            //autoscrolling and not zooming?
1330            if(options.autoScrolling && !controlPressed && !isNormalScroll){
1331                // cross-browser wheel delta
1332                e = e || window.event;
1333                var value = e.wheelDelta || -e.deltaY || -e.detail;
1334                var delta = Math.max(-1, Math.min(1, value));
1335
1336                var horizontalDetection = typeof e.wheelDeltaX !== 'undefined' || typeof e.deltaX !== 'undefined';
1337                var isScrollingVertically = (Math.abs(e.wheelDeltaX) < Math.abs(e.wheelDelta)) || (Math.abs(e.deltaX ) < Math.abs(e.deltaY) || !horizontalDetection);
1338
1339                //Limiting the array to 150 (lets not waste memory!)
1340                if(scrollings.length > 149){
1341                    scrollings.shift();
1342                }
1343
1344                //keeping record of the previous scrollings
1345                scrollings.push(Math.abs(value));
1346
1347                //preventing to scroll the site on mouse wheel when scrollbar is present
1348                if(options.scrollBar){
1349                   preventDefault(e);
1350                }
1351
1352                //time difference between the last scroll and the current one
1353                var timeDiff = curTime-prevTime;
1354                prevTime = curTime;
1355
1356                //haven't they scrolled in a while?
1357                //(enough to be consider a different scrolling action to scroll another section)
1358                if(timeDiff > 200){
1359                    //emptying the array, we dont care about old scrollings for our averages
1360                    scrollings = [];
1361                }
1362
1363                if(canScroll){
1364                    var averageEnd = getAverage(scrollings, 10);
1365                    var averageMiddle = getAverage(scrollings, 70);
1366                    var isAccelerating = averageEnd >= averageMiddle;
1367
1368                    //to avoid double swipes...
1369                    if(isAccelerating && isScrollingVertically){
1370                        //scrolling down?
1371                        if (delta < 0) {
1372                            scrolling('down');
1373
1374                        //scrolling up?
1375                        }else {
1376                            scrolling('up');
1377                        }
1378                    }
1379                }
1380
1381                return false;
1382            }
1383
1384            if(options.fitToSection){
1385                //stopping the auto scroll to adjust to a section
1386                activeAnimation = false;
1387            }
1388        }
1389
1390        /**
1391        * Slides a slider to the given direction.
1392        * Optional `section` param.
1393        */
1394        function moveSlide(direction, section){
1395            var activeSection = section == null ? $(SECTION_ACTIVE_SEL)[0] : section;
1396            var slides = $(SLIDES_WRAPPER_SEL, activeSection)[0];
1397
1398            // more than one slide needed and nothing should be sliding
1399            if (slides == null || slideMoving || $(SLIDE_SEL, slides).length < 2) {
1400                return;
1401            }
1402
1403            var currentSlide = $(SLIDE_ACTIVE_SEL, slides)[0];
1404            var destiny = null;
1405
1406            if(direction === 'left'){
1407                destiny = prevUntil(currentSlide, SLIDE_SEL);
1408            }else{
1409                destiny = nextUntil(currentSlide, SLIDE_SEL);
1410            }
1411
1412            //isn't there a next slide in the secuence?
1413            if(destiny == null){
1414                //respect loopHorizontal settin
1415                if (!options.loopHorizontal) return;
1416
1417                var slideSiblings = siblings(currentSlide);
1418                if(direction === 'left'){
1419                    destiny = slideSiblings[slideSiblings.length - 1]; //last
1420                }else{
1421                    destiny = slideSiblings[0]; //first
1422                }
1423            }
1424
1425            slideMoving = true && !FP.test.isTesting;
1426            landscapeScroll(slides, destiny, direction);
1427        }
1428
1429        /**
1430        * Maintains the active slides in the viewport
1431        * (Because the `scroll` animation might get lost with some actions, such as when using continuousVertical)
1432        */
1433        function keepSlidesPosition(){
1434            var activeSlides = $(SLIDE_ACTIVE_SEL);
1435            for( var i =0; i<activeSlides.length; i++){
1436                silentLandscapeScroll(activeSlides[i], 'internal');
1437            }
1438        }
1439
1440        var previousDestTop = 0;
1441        /**
1442        * Returns the destination Y position based on the scrolling direction and
1443        * the height of the section.
1444        */
1445        function getDestinationPosition(element){
1446            var elementHeight = element.offsetHeight;
1447            var elementTop = element.offsetTop;
1448
1449            //top of the desination will be at the top of the viewport
1450            var position = elementTop;
1451            var isScrollingDown =  elementTop > previousDestTop;
1452            var sectionBottom = position - windowsHeight + elementHeight;
1453            var bigSectionsDestination = options.bigSectionsDestination;
1454
1455            //is the destination element bigger than the viewport?
1456            if(elementHeight > windowsHeight){
1457                //scrolling up?
1458                if(!isScrollingDown && !bigSectionsDestination || bigSectionsDestination === 'bottom' ){
1459                    position = sectionBottom;
1460                }
1461            }
1462
1463            //sections equal or smaller than the viewport height && scrolling down? ||  is resizing and its in the last section
1464            else if(isScrollingDown || (isResizing && next(element) == null) ){
1465                //The bottom of the destination will be at the bottom of the viewport
1466                position = sectionBottom;
1467            }
1468
1469            /*
1470            Keeping record of the last scrolled position to determine the scrolling direction.
1471            No conventional methods can be used as the scroll bar might not be present
1472            AND the section might not be active if it is auto-height and didnt reach the middle
1473            of the viewport.
1474            */
1475            previousDestTop = position;
1476            return position;
1477        }
1478
1479        /**
1480        * Scrolls the site to the given element and scrolls to the slide if a callback is given.
1481        */
1482        function scrollPage(element, callback, isMovementUp){
1483            if(element == null){ return; } //there's no element to scroll, leaving the function
1484
1485            var dtop = getDestinationPosition(element);
1486            var slideAnchorLink;
1487            var slideIndex;
1488
1489            //local variables
1490            var v = {
1491                element: element,
1492                callback: callback,
1493                isMovementUp: isMovementUp,
1494                dtop: dtop,
1495                yMovement: getYmovement(element),
1496                anchorLink: element.getAttribute('data-anchor'),
1497                sectionIndex: index(element, SECTION_SEL),
1498                activeSlide: $(SLIDE_ACTIVE_SEL, element)[0],
1499                activeSection: $(SECTION_ACTIVE_SEL)[0],
1500                leavingSection: index($(SECTION_ACTIVE_SEL), SECTION_SEL) + 1,
1501
1502                //caching the value of isResizing at the momment the function is called
1503                //because it will be checked later inside a setTimeout and the value might change
1504                localIsResizing: isResizing
1505            };
1506
1507            //quiting when destination scroll is the same as the current one
1508            if((v.activeSection == element && !isResizing) || (options.scrollBar && getScrollTop() === v.dtop && !hasClass(element, AUTO_HEIGHT) )){ return; }
1509
1510            if(v.activeSlide != null){
1511                slideAnchorLink = v.activeSlide.getAttribute('data-anchor');
1512                slideIndex = index(v.activeSlide);
1513            }
1514
1515            //callback (onLeave) if the site is not just resizing and readjusting the slides
1516            if(isFunction(options.onLeave) && !v.localIsResizing){
1517                var direction = v.yMovement;
1518
1519                //required for continousVertical
1520                if(typeof isMovementUp !== 'undefined'){
1521                    direction = isMovementUp ? 'up' : 'down';
1522                }
1523
1524                //for the callback
1525                v.direction = direction;
1526
1527                if(fireCallback('onLeave', v) === false){
1528                    return;
1529                }
1530            }
1531
1532            // If continuousVertical && we need to wrap around
1533            if (options.autoScrolling && options.continuousVertical && typeof (v.isMovementUp) !== "undefined" &&
1534                ((!v.isMovementUp && v.yMovement == 'up') || // Intending to scroll down but about to go up or
1535                (v.isMovementUp && v.yMovement == 'down'))) { // intending to scroll up but about to go down
1536
1537                v = createInfiniteSections(v);
1538            }
1539
1540            //pausing media of the leaving section (if we are not just resizing, as destinatino will be the same one)
1541            if(!v.localIsResizing){
1542                stopMedia(v.activeSection);
1543            }
1544
1545            if(options.scrollOverflow){
1546                options.scrollOverflowHandler.beforeLeave();
1547            }
1548
1549            addClass(element, ACTIVE);
1550            removeClass(siblings(element), ACTIVE);
1551            lazyLoad(element);
1552
1553            if(options.scrollOverflow){
1554                options.scrollOverflowHandler.onLeave();
1555            }
1556
1557            //preventing from activating the MouseWheelHandler event
1558            //more than once if the page is scrolling
1559            canScroll = false || FP.test.isTesting;
1560
1561            setState(slideIndex, slideAnchorLink, v.anchorLink, v.sectionIndex);
1562
1563            performMovement(v);
1564
1565            //flag to avoid callingn `scrollPage()` twice in case of using anchor links
1566            lastScrolledDestiny = v.anchorLink;
1567
1568            //avoid firing it twice (as it does also on scroll)
1569            activateMenuAndNav(v.anchorLink, v.sectionIndex);
1570        }
1571
1572        /**
1573        * Dispatch events & callbacks making sure it does it on the right format, depending on
1574        * whether v2compatible is being used or not.
1575        */
1576        function fireCallback(eventName, v){
1577            var eventData = getEventData(eventName, v);
1578
1579            if(!options.v2compatible){
1580                trigger(container, eventName, eventData);
1581
1582                if(options[eventName].apply(eventData[Object.keys(eventData)[0]], toArray(eventData)) === false){
1583                    return false;
1584                }
1585            }
1586            else{
1587                if(options[eventName].apply(eventData[0], eventData.slice(1)) === false){
1588                    return false;
1589                }
1590            }
1591
1592            return true;
1593        }
1594
1595        /**
1596        * Makes sure to only create a Panel object if the element exist
1597        */
1598        function nullOrSection(el){
1599            return el ? new Section(el) : null;
1600        }
1601
1602        function nullOrSlide(el){
1603            return el ? new Slide(el) : null;
1604        }
1605
1606        /**
1607        * Gets the event's data for the given event on the right format. Depending on whether
1608        * v2compatible is being used or not.
1609        */
1610        function getEventData(eventName, v){
1611            var paramsPerEvent;
1612
1613            if(!options.v2compatible){
1614
1615                //using functions to run only the necessary bits within the object
1616                paramsPerEvent = {
1617                    afterRender: function(){
1618                        return {
1619                            section: nullOrSection($(SECTION_ACTIVE_SEL)[0]),
1620                            slide: nullOrSlide($(SLIDE_ACTIVE_SEL, $(SECTION_ACTIVE_SEL)[0])[0])
1621                        };
1622                    },
1623                    onLeave: function(){
1624                        return {
1625                            origin: nullOrSection(v.activeSection),
1626                            destination: nullOrSection(v.element),
1627                            direction: v.direction
1628                        };
1629                    },
1630
1631                    afterLoad: function(){
1632                        return paramsPerEvent.onLeave();
1633                    },
1634
1635                    afterSlideLoad: function(){
1636                        return {
1637                            section: nullOrSection(v.section),
1638                            origin: nullOrSlide(v.prevSlide),
1639                            destination: nullOrSlide(v.destiny),
1640                            direction: v.direction
1641                        };
1642                    },
1643
1644                    onSlideLeave: function(){
1645                        return paramsPerEvent.afterSlideLoad();
1646                    }
1647                };
1648            }
1649            else{
1650                paramsPerEvent = {
1651                    afterRender: function(){ return [container]; },
1652                    onLeave: function(){ return [v.activeSection, v.leavingSection, (v.sectionIndex + 1), v.direction]; },
1653                    afterLoad: function(){ return [v.element, v.anchorLink, (v.sectionIndex + 1)]; },
1654                    afterSlideLoad: function(){ return [v.destiny, v.anchorLink, (v.sectionIndex + 1), v.slideAnchor, v.slideIndex]; },
1655                    onSlideLeave: function(){ return [v.prevSlide, v.anchorLink, (v.sectionIndex + 1), v.prevSlideIndex, v.direction, v.slideIndex]; },
1656                };
1657            }
1658
1659            return paramsPerEvent[eventName]();
1660        }
1661
1662        /**
1663        * Performs the vertical movement (by CSS3 or by jQuery)
1664        */
1665        function performMovement(v){
1666            // using CSS3 translate functionality
1667            if (options.css3 && options.autoScrolling && !options.scrollBar) {
1668
1669                // The first section can have a negative value in iOS 10. Not quite sure why: -0.0142822265625
1670                // that's why we round it to 0.
1671                var translate3d = 'translate3d(0px, -' + Math.round(v.dtop) + 'px, 0px)';
1672                transformContainer(translate3d, true);
1673
1674                //even when the scrollingSpeed is 0 there's a little delay, which might cause the
1675                //scrollingSpeed to change in case of using silentMoveTo();
1676                if(options.scrollingSpeed){
1677                    clearTimeout(afterSectionLoadsId);
1678                    afterSectionLoadsId = setTimeout(function () {
1679                        afterSectionLoads(v);
1680                    }, options.scrollingSpeed);
1681                }else{
1682                    afterSectionLoads(v);
1683                }
1684            }
1685
1686            // using JS to animate
1687            else{
1688                var scrollSettings = getScrollSettings(v.dtop);
1689                FP.test.top = -v.dtop + 'px';
1690
1691                scrollTo(scrollSettings.element, scrollSettings.options, options.scrollingSpeed, function(){
1692                    if(options.scrollBar){
1693
1694                        /* Hack!
1695                        The timeout prevents setting the most dominant section in the viewport as "active" when the user
1696                        scrolled to a smaller section by using the mousewheel (auto scrolling) rather than draging the scroll bar.
1697
1698                        When using scrollBar:true It seems like the scroll events still getting propagated even after the scrolling animation has finished.
1699                        */
1700                        setTimeout(function(){
1701                            afterSectionLoads(v);
1702                        },30);
1703                    }else{
1704                        afterSectionLoads(v);
1705                    }
1706                });
1707            }
1708        }
1709
1710        /**
1711        * Gets the scrolling settings depending on the plugin autoScrolling option
1712        */
1713        function getScrollSettings(top){
1714            var scroll = {};
1715
1716            //top property animation
1717            if(options.autoScrolling && !options.scrollBar){
1718                scroll.options = -top;
1719                scroll.element = $(WRAPPER_SEL)[0];
1720            }
1721
1722            //window real scrolling
1723            else{
1724                scroll.options = top;
1725                scroll.element = window;
1726            }
1727
1728            return scroll;
1729        }
1730
1731        /**
1732        * Adds sections before or after the current one to create the infinite effect.
1733        */
1734        function createInfiniteSections(v){
1735            // Scrolling down
1736            if (!v.isMovementUp) {
1737                // Move all previous sections to after the active section
1738                after($(SECTION_ACTIVE_SEL)[0], prevAll(v.activeSection, SECTION_SEL).reverse());
1739            }
1740            else { // Scrolling up
1741                // Move all next sections to before the active section
1742                before($(SECTION_ACTIVE_SEL)[0], nextAll(v.activeSection, SECTION_SEL));
1743            }
1744
1745            // Maintain the displayed position (now that we changed the element order)
1746            silentScroll($(SECTION_ACTIVE_SEL)[0].offsetTop);
1747
1748            // Maintain the active slides visible in the viewport
1749            keepSlidesPosition();
1750
1751            // save for later the elements that still need to be reordered
1752            v.wrapAroundElements = v.activeSection;
1753
1754            // Recalculate animation variables
1755            v.dtop = v.element.offsetTop;
1756            v.yMovement = getYmovement(v.element);
1757
1758            //sections will temporally have another position in the DOM
1759            //updating this values in case we need them
1760            v.leavingSection = index(v.activeSection, SECTION_SEL) + 1;
1761            v.sectionIndex = index(v.element, SECTION_SEL);
1762
1763            return v;
1764        }
1765
1766        /**
1767        * Fix section order after continuousVertical changes have been animated
1768        */
1769        function continuousVerticalFixSectionOrder (v) {
1770            // If continuousVertical is in effect (and autoScrolling would also be in effect then),
1771            // finish moving the elements around so the direct navigation will function more simply
1772            if (v.wrapAroundElements == null) {
1773                return;
1774            }
1775
1776            if (v.isMovementUp) {
1777                before($(SECTION_SEL)[0], v.wrapAroundElements);
1778            }
1779            else {
1780                after($(SECTION_SEL)[$(SECTION_SEL).length-1], v.wrapAroundElements);
1781            }
1782
1783            silentScroll($(SECTION_ACTIVE_SEL)[0].offsetTop);
1784
1785            // Maintain the active slides visible in the viewport
1786            keepSlidesPosition();
1787        }
1788
1789
1790        /**
1791        * Actions to do once the section is loaded.
1792        */
1793        function afterSectionLoads (v){
1794            continuousVerticalFixSectionOrder(v);
1795
1796            //callback (afterLoad) if the site is not just resizing and readjusting the slides
1797            if(isFunction(options.afterLoad) && !v.localIsResizing){
1798                fireCallback('afterLoad', v);
1799            }
1800
1801            if(options.scrollOverflow){
1802                options.scrollOverflowHandler.afterLoad();
1803            }
1804
1805            if(!v.localIsResizing){
1806                playMedia(v.element);
1807            }
1808
1809            addClass(v.element, COMPLETELY);
1810            removeClass(siblings(v.element), COMPLETELY);
1811
1812            canScroll = true;
1813
1814            if(isFunction(v.callback)){
1815                v.callback();
1816            }
1817        }
1818
1819        /**
1820        * Sets the value for the given attribute from the `data-` attribute with the same suffix
1821        * ie: data-srcset ==> srcset  |  data-src ==> src
1822        */
1823        function setSrc(element, attribute){
1824            element.setAttribute(attribute, element.getAttribute('data-' + attribute));
1825            element.removeAttribute('data-' + attribute);
1826        }
1827
1828        /**
1829        * Lazy loads image, video and audio elements.
1830        */
1831        function lazyLoad(destiny){
1832            if (!options.lazyLoading){
1833                return;
1834            }
1835
1836            var panel = getSlideOrSection(destiny);
1837
1838            $('img[data-src], img[data-srcset], source[data-src], source[data-srcset], video[data-src], audio[data-src], iframe[data-src]', panel).forEach(function(element){
1839                ['src', 'srcset'].forEach(function(type){
1840                    var attribute = element.getAttribute('data-' + type);
1841                    if(attribute != null && attribute){
1842                        setSrc(element, type);
1843                    }
1844                });
1845
1846                if(matches(element, 'source')){
1847                    var typeToPlay = closest(element, 'video') != null ? 'video' : 'audio';
1848                    closest(element, typeToPlay).load();
1849                    }
1850            });
1851        }
1852
1853        /**
1854        * Plays video and audio elements.
1855        */
1856        function playMedia(destiny){
1857            var panel = getSlideOrSection(destiny);
1858
1859            //playing HTML5 media elements
1860            $('video, audio', panel).forEach(function(element){
1861                if( element.hasAttribute('data-autoplay') && typeof element.play === 'function' ) {
1862                    element.play();
1863                }
1864            });
1865
1866            //youtube videos
1867            $('iframe[src*="youtube.com/embed/"]', panel).forEach(function(element){
1868                if ( element.hasAttribute('data-autoplay') ){
1869                    playYoutube(element);
1870                }
1871
1872                //in case the URL was not loaded yet. On page load we need time for the new URL (with the API string) to load.
1873                element.onload = function() {
1874                    if ( element.hasAttribute('data-autoplay') ){
1875                        playYoutube(element);
1876                    }
1877                };
1878            });
1879        }
1880
1881        /**
1882        * Plays a youtube video
1883        */
1884        function playYoutube(element){
1885            element.contentWindow.postMessage('{"event":"command","func":"playVideo","args":""}', '*');
1886        }
1887
1888        /**
1889        * Stops video and audio elements.
1890        */
1891        function stopMedia(destiny){
1892            var panel = getSlideOrSection(destiny);
1893
1894            //stopping HTML5 media elements
1895            $('video, audio', panel).forEach(function(element){
1896                if( !element.hasAttribute('data-keepplaying') && typeof element.pause === 'function' ) {
1897                    element.pause();
1898                }
1899            });
1900
1901            //youtube videos
1902            $('iframe[src*="youtube.com/embed/"]', panel).forEach(function(element){
1903                if( /youtube\.com\/embed\//.test(element.getAttribute('src')) && !element.hasAttribute('data-keepplaying')){
1904                    element.contentWindow.postMessage('{"event":"command","func":"pauseVideo","args":""}','*');
1905                }
1906            });
1907        }
1908
1909        /**
1910        * Gets the active slide (or section) for the given section
1911        */
1912        function getSlideOrSection(destiny){
1913            var slide = $(SLIDE_ACTIVE_SEL, destiny);
1914            if( slide.length ) {
1915                destiny = slide[0];
1916            }
1917
1918            return destiny;
1919        }
1920
1921        /**
1922        * Scrolls to the anchor in the URL when loading the site
1923        */
1924        function scrollToAnchor(){
1925            var anchors =  getAnchorsURL();
1926            var sectionAnchor = anchors.section;
1927            var slideAnchor = anchors.slide;
1928
1929            if(sectionAnchor){  //if theres any #
1930                if(options.animateAnchor){
1931                    scrollPageAndSlide(sectionAnchor, slideAnchor);
1932                }else{
1933                    silentMoveTo(sectionAnchor, slideAnchor);
1934                }
1935            }
1936        }
1937
1938        /**
1939        * Detecting any change on the URL to scroll to the given anchor link
1940        * (a way to detect back history button as we play with the hashes on the URL)
1941        */
1942        function hashChangeHandler(){
1943            if(!isScrolling && !options.lockAnchors){
1944                var anchors = getAnchorsURL();
1945                var sectionAnchor = anchors.section;
1946                var slideAnchor = anchors.slide;
1947
1948                //when moving to a slide in the first section for the first time (first time to add an anchor to the URL)
1949                var isFirstSlideMove =  (typeof lastScrolledDestiny === 'undefined');
1950                var isFirstScrollMove = (typeof lastScrolledDestiny === 'undefined' && typeof slideAnchor === 'undefined' && !slideMoving);
1951
1952                if(sectionAnchor && sectionAnchor.length){
1953                    /*in order to call scrollpage() only once for each destination at a time
1954                    It is called twice for each scroll otherwise, as in case of using anchorlinks `hashChange`
1955                    event is fired on every scroll too.*/
1956                    if ((sectionAnchor && sectionAnchor !== lastScrolledDestiny) && !isFirstSlideMove
1957                        || isFirstScrollMove
1958                        || (!slideMoving && lastScrolledSlide != slideAnchor )){
1959
1960                        scrollPageAndSlide(sectionAnchor, slideAnchor);
1961                    }
1962                }
1963            }
1964        }
1965
1966        //gets the URL anchors (section and slide)
1967        function getAnchorsURL(){
1968            var section;
1969            var slide;
1970            var hash = window.location.hash;
1971
1972            if(hash.length){
1973                //getting the anchor link in the URL and deleting the `#`
1974                var anchorsParts =  hash.replace('#', '').split('/');
1975
1976                //using / for visual reasons and not as a section/slide separator #2803
1977                var isFunkyAnchor = hash.indexOf('#/') > -1;
1978
1979                section = isFunkyAnchor ? '/' + anchorsParts[1] : decodeURIComponent(anchorsParts[0]);
1980
1981                var slideAnchor = isFunkyAnchor ? anchorsParts[2] : anchorsParts[1];
1982                if(slideAnchor && slideAnchor.length){
1983                    slide = decodeURIComponent(slideAnchor);
1984                }
1985            }
1986
1987            return {
1988                section: section,
1989                slide: slide
1990            };
1991        }
1992
1993        //Sliding with arrow keys, both, vertical and horizontal
1994        function keydownHandler(e) {
1995            clearTimeout(keydownId);
1996
1997            var activeElement = document.activeElement;
1998            var keyCode = e.keyCode;
1999
2000            //tab?
2001            if(keyCode === 9){
2002                onTab(e);
2003            }
2004
2005            else if(!matches(activeElement, 'textarea') && !matches(activeElement, 'input') && !matches(activeElement, 'select') &&
2006                activeElement.getAttribute('contentEditable') !== "true" && activeElement.getAttribute('contentEditable') !== '' &&
2007                options.keyboardScrolling && options.autoScrolling){
2008
2009                //preventing the scroll with arrow keys & spacebar & Page Up & Down keys
2010                var keyControls = [40, 38, 32, 33, 34];
2011                if(keyControls.indexOf(keyCode) > -1){
2012                    preventDefault(e);
2013                }
2014
2015                controlPressed = e.ctrlKey;
2016
2017                keydownId = setTimeout(function(){
2018                    onkeydown(e);
2019                },150);
2020            }
2021        }
2022
2023        function tooltipTextHandler(){
2024            /*jshint validthis:true */
2025            trigger(prev(this), 'click');
2026        }
2027
2028        //to prevent scrolling while zooming
2029        function keyUpHandler(e){
2030            if(isWindowFocused){ //the keyup gets fired on new tab ctrl + t in Firefox
2031                controlPressed = e.ctrlKey;
2032            }
2033        }
2034
2035        //binding the mousemove when the mouse's middle button is released
2036        function mouseDownHandler(e){
2037            //middle button
2038            if (e.which == 2){
2039                oldPageY = e.pageY;
2040                container.addEventListener('mousemove', mouseMoveHandler);
2041            }
2042        }
2043
2044        //unbinding the mousemove when the mouse's middle button is released
2045        function mouseUpHandler(e){
2046            //middle button
2047            if (e.which == 2){
2048                container.removeEventListener('mousemove', mouseMoveHandler);
2049            }
2050        }
2051
2052        /**
2053        * Makes sure the tab key will only focus elements within the current section/slide
2054        * preventing this way from breaking the page.
2055        * Based on "Modals and keyboard traps"
2056        * from https://developers.google.com/web/fundamentals/accessibility/focus/using-tabindex
2057        */
2058        function onTab(e){
2059            var isShiftPressed = e.shiftKey;
2060            var activeElement = document.activeElement;
2061            var activeSection = $(SECTION_ACTIVE_SEL)[0];
2062            var activeSlide = $(SLIDE_ACTIVE_SEL, activeSection)[0];
2063            var focusableWrapper = activeSlide ? activeSlide : activeSection;
2064            var focusableElements = $(focusableElementsString + ':not([tabindex="-1"])', focusableWrapper);
2065
2066            function preventAndFocusFirst(e){
2067                preventDefault(e);
2068                return focusableElements[0].focus();
2069            }
2070
2071            //is there an element with focus?
2072            if(activeElement.length){
2073                if(closest(activeElement, SECTION_ACTIVE_SEL + ',' + SLIDE_ACTIVE_SEL) == null){
2074                    activeElement = preventAndFocusFirst(e);
2075                }
2076            }
2077
2078            //no element if focused? Let's focus the first one of the section/slide
2079            else{
2080                preventAndFocusFirst(e);
2081            }
2082
2083            //when reached the first or last focusable element of the section/slide
2084            //we prevent the tab action to keep it in the last focusable element
2085            if(!isShiftPressed && activeElement == focusableElements[focusableElements.length - 1] ||
2086                isShiftPressed && activeElement == focusableElements[0]
2087            ){
2088                preventDefault(e);
2089            }
2090        }
2091
2092        //Scrolling horizontally when clicking on the slider controls.
2093        function slideArrowHandler(){
2094            /*jshint validthis:true */
2095            var section = closest(this, SECTION_SEL);
2096
2097            /*jshint validthis:true */
2098            if (hasClass(this, SLIDES_PREV)) {
2099                if(isScrollAllowed.m.left){
2100                    moveSlideLeft(section);
2101                }
2102            } else {
2103                if(isScrollAllowed.m.right){
2104                    moveSlideRight(section);
2105                }
2106            }
2107        }
2108
2109        //when opening a new tab (ctrl + t), `control` won't be pressed when coming back.
2110        function blurHandler(){
2111            isWindowFocused = false;
2112            controlPressed = false;
2113        }
2114
2115        //Scrolls to the section when clicking the navigation bullet
2116        function sectionBulletHandler(e){
2117            preventDefault(e);
2118
2119            /*jshint validthis:true */
2120            var index = index(this.parentNode);
2121            scrollPage($(SECTION_SEL)[index]);
2122        }
2123
2124        //Scrolls the slider to the given slide destination for the given section
2125        function slideBulletHandler(e){
2126            preventDefault(e);
2127
2128            /*jshint validthis: true */
2129            var slides = $(SLIDES_WRAPPER_SEL, closest(this, SECTION_SEL))[0];
2130            var destiny = $(SLIDE_SEL, slides)[index(closest(this, 'li'))];
2131
2132            landscapeScroll(slides, destiny);
2133        }
2134
2135        /**
2136        * Keydown event
2137        */
2138        function onkeydown(e){
2139            var shiftPressed = e.shiftKey;
2140
2141            //do nothing if we can not scroll or we are not using horizotnal key arrows.
2142            if(!canScroll && [37,39].indexOf(e.keyCode) < 0){
2143                return;
2144            }
2145
2146            switch (e.keyCode) {
2147                //up
2148                case 38:
2149                case 33:
2150                    if(isScrollAllowed.k.up){
2151                        moveSectionUp();
2152                    }
2153                    break;
2154
2155                //down
2156                case 32: //spacebar
2157                    if(shiftPressed && isScrollAllowed.k.up){
2158                        moveSectionUp();
2159                        break;
2160                    }
2161                /* falls through */
2162                case 40:
2163                case 34:
2164                    if(isScrollAllowed.k.down){
2165                        moveSectionDown();
2166                    }
2167                    break;
2168
2169                //Home
2170                case 36:
2171                    if(isScrollAllowed.k.up){
2172                        moveTo(1);
2173                    }
2174                    break;
2175
2176                //End
2177                case 35:
2178                     if(isScrollAllowed.k.down){
2179                        moveTo( $(SECTION_SEL).length );
2180                    }
2181                    break;
2182
2183                //left
2184                case 37:
2185                    if(isScrollAllowed.k.left){
2186                        moveSlideLeft();
2187                    }
2188                    break;
2189
2190                //right
2191                case 39:
2192                    if(isScrollAllowed.k.right){
2193                        moveSlideRight();
2194                    }
2195                    break;
2196
2197                default:
2198                    return; // exit this handler for other keys
2199            }
2200        }
2201
2202        /**
2203        * Detecting the direction of the mouse movement.
2204        * Used only for the middle button of the mouse.
2205        */
2206        var oldPageY = 0;
2207        function mouseMoveHandler(e){
2208            if(canScroll){
2209                // moving up
2210                if (e.pageY < oldPageY && isScrollAllowed.m.up){
2211                    moveSectionUp();
2212                }
2213
2214                // moving down
2215                else if(e.pageY > oldPageY && isScrollAllowed.m.down){
2216                    moveSectionDown();
2217                }
2218            }
2219            oldPageY = e.pageY;
2220        }
2221
2222        /**
2223        * Scrolls horizontal sliders.
2224        */
2225        function landscapeScroll(slides, destiny, direction){
2226            var section = closest(slides, SECTION_SEL);
2227            var v = {
2228                slides: slides,
2229                destiny: destiny,
2230                direction: direction,
2231                destinyPos: {left: destiny.offsetLeft},
2232                slideIndex: index(destiny),
2233                section: section,
2234                sectionIndex: index(section, SECTION_SEL),
2235                anchorLink: section.getAttribute('data-anchor'),
2236                slidesNav: $(SLIDES_NAV_SEL, section)[0],
2237                slideAnchor: getAnchor(destiny),
2238                prevSlide: $(SLIDE_ACTIVE_SEL, section)[0],
2239                prevSlideIndex: index($(SLIDE_ACTIVE_SEL, section)[0]),
2240
2241                //caching the value of isResizing at the momment the function is called
2242                //because it will be checked later inside a setTimeout and the value might change
2243                localIsResizing: isResizing
2244            };
2245            v.xMovement = getXmovement(v.prevSlideIndex, v.slideIndex);
2246
2247            //important!! Only do it when not resizing
2248            if(!v.localIsResizing){
2249                //preventing from scrolling to the next/prev section when using scrollHorizontally
2250                canScroll = false;
2251            }
2252
2253            if(options.onSlideLeave){
2254
2255                //if the site is not just resizing and readjusting the slides
2256                if(!v.localIsResizing && v.xMovement!=='none'){
2257                    if(isFunction( options.onSlideLeave )){
2258                        if( fireCallback('onSlideLeave', v) === false){
2259                            slideMoving = false;
2260                            return;
2261                        }
2262                    }
2263                }
2264            }
2265
2266            addClass(destiny, ACTIVE);
2267            removeClass(siblings(destiny), ACTIVE);
2268
2269            if(!v.localIsResizing){
2270                stopMedia(v.prevSlide);
2271                lazyLoad(destiny);
2272            }
2273
2274            if(!options.loopHorizontal && options.controlArrows){
2275                //hidding it for the fist slide, showing for the rest
2276                toggle($(SLIDES_ARROW_PREV_SEL, section), v.slideIndex!==0);
2277
2278                //hidding it for the last slide, showing for the rest
2279                toggle($(SLIDES_ARROW_NEXT_SEL, section), next(destiny) != null);
2280            }
2281
2282            //only changing the URL if the slides are in the current section (not for resize re-adjusting)
2283            if(hasClass(section, ACTIVE) && !v.localIsResizing){
2284                setState(v.slideIndex, v.slideAnchor, v.anchorLink, v.sectionIndex);
2285            }
2286
2287            performHorizontalMove(slides, v, true);
2288        }
2289
2290
2291        function afterSlideLoads(v){
2292            activeSlidesNavigation(v.slidesNav, v.slideIndex);
2293
2294            //if the site is not just resizing and readjusting the slides
2295            if(!v.localIsResizing){
2296                if(isFunction( options.afterSlideLoad )){
2297                    fireCallback('afterSlideLoad', v);
2298                }
2299
2300                //needs to be inside the condition to prevent problems with continuousVertical and scrollHorizontally
2301                //and to prevent double scroll right after a windows resize
2302                canScroll = true;
2303
2304                playMedia(v.destiny);
2305            }
2306
2307            //letting them slide again
2308            slideMoving = false;
2309        }
2310
2311        /**
2312        * Performs the horizontal movement. (CSS3 or jQuery)
2313        *
2314        * @param fireCallback {Bool} - determines whether or not to fire the callback
2315        */
2316        function performHorizontalMove(slides, v, fireCallback){
2317            var destinyPos = v.destinyPos;
2318
2319            if(options.css3){
2320                var translate3d = 'translate3d(-' + Math.round(destinyPos.left) + 'px, 0px, 0px)';
2321
2322                FP.test.translate3dH[v.sectionIndex] = translate3d;
2323                css(addAnimation($(SLIDES_CONTAINER_SEL, slides)), getTransforms(translate3d));
2324
2325                afterSlideLoadsId = setTimeout(function(){
2326                    if(fireCallback){
2327                        afterSlideLoads(v);
2328                    }
2329                }, options.scrollingSpeed);
2330            }else{
2331                FP.test.left[v.sectionIndex] = Math.round(destinyPos.left);
2332
2333                scrollTo(slides, Math.round(destinyPos.left), options.scrollingSpeed, function(){
2334                    if(fireCallback){
2335                        afterSlideLoads(v);
2336                    }
2337                });
2338            }
2339        }
2340
2341        /**
2342        * Sets the state for the horizontal bullet navigations.
2343        */
2344        function activeSlidesNavigation(slidesNav, slideIndex){
2345            if(options.slidesNavigation && slidesNav != null){
2346                removeClass($(ACTIVE_SEL, slidesNav), ACTIVE);
2347                addClass( $('a', $('li', slidesNav)[slideIndex] ), ACTIVE);
2348            }
2349        }
2350
2351        var previousHeight = windowsHeight;
2352
2353        //when resizing the site, we adjust the heights of the sections, slimScroll...
2354        function resizeHandler(){
2355            //checking if it needs to get responsive
2356            responsive();
2357
2358            // rebuild immediately on touch devices
2359            if (isTouchDevice) {
2360                var activeElement = document.activeElement;
2361
2362                //if the keyboard is NOT visible
2363                if (!matches(activeElement, 'textarea') && !matches(activeElement, 'input') && !matches(activeElement, 'select')) {
2364                    var currentHeight = getWindowHeight();
2365
2366                    //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)
2367                    if( Math.abs(currentHeight - previousHeight) > (20 * Math.max(previousHeight, currentHeight) / 100) ){
2368                        reBuild(true);
2369                        previousHeight = currentHeight;
2370                    }
2371                }
2372            }else{
2373                //in order to call the functions only when the resize is finished
2374                //http://stackoverflow.com/questions/4298612/jquery-how-to-call-resize-event-only-once-its-finished-resizing
2375                clearTimeout(resizeId);
2376
2377                resizeId = setTimeout(function(){
2378                    reBuild(true);
2379                }, 350);
2380            }
2381        }
2382
2383        /**
2384        * Checks if the site needs to get responsive and disables autoScrolling if so.
2385        * A class `fp-responsive` is added to the plugin's container in case the user wants to use it for his own responsive CSS.
2386        */
2387        function responsive(){
2388            var widthLimit = options.responsive || options.responsiveWidth; //backwards compatiblity
2389            var heightLimit = options.responsiveHeight;
2390
2391            //only calculating what we need. Remember its called on the resize event.
2392            var isBreakingPointWidth = widthLimit && window.innerWidth < widthLimit;
2393            var isBreakingPointHeight = heightLimit && window.innerHeight < heightLimit;
2394
2395            if(widthLimit && heightLimit){
2396                setResponsive(isBreakingPointWidth || isBreakingPointHeight);
2397            }
2398            else if(widthLimit){
2399                setResponsive(isBreakingPointWidth);
2400            }
2401            else if(heightLimit){
2402                setResponsive(isBreakingPointHeight);
2403            }
2404        }
2405
2406        /**
2407        * Adds transition animations for the given element
2408        */
2409        function addAnimation(element){
2410            var transition = 'all ' + options.scrollingSpeed + 'ms ' + options.easingcss3;
2411
2412            removeClass(element, NO_TRANSITION);
2413            return css(element, {
2414                '-webkit-transition': transition,
2415                'transition': transition
2416            });
2417        }
2418
2419        /**
2420        * Remove transition animations for the given element
2421        */
2422        function removeAnimation(element){
2423            return addClass(element, NO_TRANSITION);
2424        }
2425
2426        /**
2427        * Activating the vertical navigation bullets according to the given slide name.
2428        */
2429        function activateNavDots(name, sectionIndex){
2430            if(options.navigation && $(SECTION_NAV_SEL)[0] != null){
2431                    removeClass($(ACTIVE_SEL, $(SECTION_NAV_SEL)[0]), ACTIVE);
2432                if(name){
2433                    addClass( $('a[href="#' + name + '"]', $(SECTION_NAV_SEL)[0]), ACTIVE);
2434                }else{
2435                    addClass($('a', $('li', $(SECTION_NAV_SEL)[0])[sectionIndex]), ACTIVE);
2436                }
2437            }
2438        }
2439
2440        /**
2441        * Activating the website main menu elements according to the given slide name.
2442        */
2443        function activateMenuElement(name){
2444            var menu = $(options.menu)[0];
2445            if(options.menu && menu != null){
2446                removeClass($(ACTIVE_SEL, menu), ACTIVE);
2447                addClass($('[data-menuanchor="'+name+'"]', menu), ACTIVE);
2448            }
2449        }
2450
2451        /**
2452        * Sets to active the current menu and vertical nav items.
2453        */
2454        function activateMenuAndNav(anchor, index){
2455            activateMenuElement(anchor);
2456            activateNavDots(anchor, index);
2457        }
2458
2459        /**
2460        * Retuns `up` or `down` depending on the scrolling movement to reach its destination
2461        * from the current section.
2462        */
2463        function getYmovement(destiny){
2464            var fromIndex = index($(SECTION_ACTIVE_SEL)[0], SECTION_SEL);
2465            var toIndex = index(destiny, SECTION_SEL);
2466            if( fromIndex == toIndex){
2467                return 'none';
2468            }
2469            if(fromIndex > toIndex){
2470                return 'up';
2471            }
2472            return 'down';
2473        }
2474
2475        /**
2476        * Retuns `right` or `left` depending on the scrolling movement to reach its destination
2477        * from the current slide.
2478        */
2479        function getXmovement(fromIndex, toIndex){
2480            if( fromIndex == toIndex){
2481                return 'none';
2482            }
2483            if(fromIndex > toIndex){
2484                return 'left';
2485            }
2486            return 'right';
2487        }
2488
2489        function addTableClass(element){
2490            //In case we are styling for the 2nd time as in with reponsiveSlides
2491            if(!hasClass(element, TABLE)){
2492                var wrapper = document.createElement('div');
2493                wrapper.className = TABLE_CELL;
2494                wrapper.style.height = getTableHeight(element) + 'px';
2495
2496                addClass(element, TABLE);
2497                wrapInner(element, wrapper);
2498            }
2499        }
2500
2501        function getTableHeight(element){
2502            var sectionHeight = windowsHeight;
2503
2504            if(options.paddingTop || options.paddingBottom){
2505                var section = element;
2506                if(!hasClass(section, SECTION)){
2507                    section = closest(element, SECTION_SEL);
2508                }
2509
2510                var paddings = parseInt(getComputedStyle(section)['padding-top']) + parseInt(getComputedStyle(section)['padding-bottom']);
2511                sectionHeight = (windowsHeight - paddings);
2512            }
2513
2514            return sectionHeight;
2515        }
2516
2517        /**
2518        * Adds a css3 transform property to the container class with or without animation depending on the animated param.
2519        */
2520        function transformContainer(translate3d, animated){
2521            if(animated){
2522                addAnimation(container);
2523            }else{
2524                removeAnimation(container);
2525            }
2526
2527            css(container, getTransforms(translate3d));
2528            FP.test.translate3d = translate3d;
2529
2530            //syncronously removing the class after the animation has been applied.
2531            setTimeout(function(){
2532                removeClass(container, NO_TRANSITION);
2533            },10);
2534        }
2535
2536        /**
2537        * Gets a section by its anchor / index
2538        */
2539        function getSectionByAnchor(sectionAnchor){
2540            var section = $(SECTION_SEL + '[data-anchor="'+sectionAnchor+'"]', container)[0];
2541            if(!section){
2542                var sectionIndex = typeof sectionAnchor !== 'undefined' ? sectionAnchor -1 : 0;
2543                section = $(SECTION_SEL)[sectionIndex];
2544            }
2545
2546            return section;
2547        }
2548
2549        /**
2550        * Gets a slide inside a given section by its anchor / index
2551        */
2552        function getSlideByAnchor(slideAnchor, section){
2553            var slide = $(SLIDE_SEL + '[data-anchor="'+slideAnchor+'"]', section)[0];
2554            if(slide == null){
2555                slideAnchor = typeof slideAnchor !== 'undefined' ? slideAnchor : 0;
2556                slide = $(SLIDE_SEL, section)[slideAnchor];
2557            }
2558
2559            return slide;
2560        }
2561
2562        /**
2563        * Scrolls to the given section and slide anchors
2564        */
2565        function scrollPageAndSlide(sectionAnchor, slideAnchor){
2566            var section = getSectionByAnchor(sectionAnchor);
2567
2568            //do nothing if there's no section with the given anchor name
2569            if(section == null) return;
2570
2571            var slide = getSlideByAnchor(slideAnchor, section);
2572
2573            //we need to scroll to the section and then to the slide
2574            if (sectionAnchor !== lastScrolledDestiny && !hasClass(section, ACTIVE)){
2575                scrollPage(section, function(){
2576                    scrollSlider(slide);
2577                });
2578            }
2579            //if we were already in the section
2580            else{
2581                scrollSlider(slide);
2582            }
2583        }
2584
2585        /**
2586        * Scrolls the slider to the given slide destination for the given section
2587        */
2588        function scrollSlider(slide){
2589            if(slide != null){
2590                landscapeScroll(closest(slide, SLIDES_WRAPPER_SEL), slide);
2591            }
2592        }
2593
2594        /**
2595        * Creates a landscape navigation bar with dots for horizontal sliders.
2596        */
2597        function addSlidesNavigation(section, numSlides){
2598            appendTo(createElementFromHTML('<div class="' + SLIDES_NAV + '"><ul></ul></div>'), section);
2599            var nav = $(SLIDES_NAV_SEL, section)[0];
2600
2601            //top or bottom
2602            addClass(nav, 'fp-' + options.slidesNavPosition);
2603
2604            for(var i=0; i< numSlides; i++){
2605                appendTo(createElementFromHTML('<li><a href="#"><span></span></a></li>'), $('ul', nav)[0] );
2606            }
2607
2608            //centering it
2609            css(nav, {'margin-left': '-' + (nav.innerWidth/2) + 'px'});
2610
2611            addClass($('a', $('li', nav)[0] ), ACTIVE);
2612        }
2613
2614
2615        /**
2616        * Sets the state of the website depending on the active section/slide.
2617        * It changes the URL hash when needed and updates the body class.
2618        */
2619        function setState(slideIndex, slideAnchor, anchorLink, sectionIndex){
2620            var sectionHash = '';
2621
2622            if(options.anchors.length && !options.lockAnchors){
2623
2624                //isn't it the first slide?
2625                if(slideIndex){
2626                    if(anchorLink != null){
2627                        sectionHash = anchorLink;
2628                    }
2629
2630                    //slide without anchor link? We take the index instead.
2631                    if(slideAnchor == null){
2632                        slideAnchor = slideIndex;
2633                    }
2634
2635                    lastScrolledSlide = slideAnchor;
2636                    setUrlHash(sectionHash + '/' + slideAnchor);
2637
2638                //first slide won't have slide anchor, just the section one
2639                }else if(slideIndex != null){
2640                    lastScrolledSlide = slideAnchor;
2641                    setUrlHash(anchorLink);
2642                }
2643
2644                //section without slides
2645                else{
2646                    setUrlHash(anchorLink);
2647                }
2648            }
2649
2650            setBodyClass();
2651        }
2652
2653        /**
2654        * Sets the URL hash.
2655        */
2656        function setUrlHash(url){
2657            if(options.recordHistory){
2658                location.hash = url;
2659            }else{
2660                //Mobile Chrome doesn't work the normal way, so... lets use HTML5 for phones :)
2661                if(isTouchDevice || isTouch){
2662                    window.history.replaceState(undefined, undefined, '#' + url);
2663                }else{
2664                    var baseUrl = window.location.href.split('#')[0];
2665                    window.location.replace( baseUrl + '#' + url );
2666                }
2667            }
2668        }
2669
2670        /**
2671        * Gets the anchor for the given slide / section. Its index will be used if there's none.
2672        */
2673        function getAnchor(element){
2674            if(!element){
2675                return null;
2676            }
2677            var anchor = element.getAttribute('data-anchor');
2678            var elementIndex = index(element);
2679
2680            //Slide without anchor link? We take the index instead.
2681            if(anchor == null){
2682                anchor = elementIndex;
2683            }
2684
2685            return anchor;
2686        }
2687
2688        /**
2689        * Sets a class for the body of the page depending on the active section / slide
2690        */
2691        function setBodyClass(){
2692            var section = $(SECTION_ACTIVE_SEL)[0];
2693            var slide = $(SLIDE_ACTIVE_SEL, section)[0];
2694
2695            var sectionAnchor = getAnchor(section);
2696            var slideAnchor = getAnchor(slide);
2697
2698            var text = String(sectionAnchor);
2699
2700            if(slide){
2701                text = text + '-' + slideAnchor;
2702            }
2703
2704            //changing slash for dash to make it a valid CSS style
2705            text = text.replace('/', '-').replace('#','');
2706
2707            //removing previous anchor classes
2708            var classRe = new RegExp('\\b\\s?' + VIEWING_PREFIX + '-[^\\s]+\\b', "g");
2709            $body.className = $body.className.replace(classRe, '');
2710
2711            //adding the current anchor
2712            addClass($body, VIEWING_PREFIX + '-' + text);
2713        }
2714
2715        /**
2716        * Checks for translate3d support
2717        * @return boolean
2718        * http://stackoverflow.com/questions/5661671/detecting-transform-translate3d-support
2719        */
2720        function support3d() {
2721            var el = document.createElement('p'),
2722                has3d,
2723                transforms = {
2724                    'webkitTransform':'-webkit-transform',
2725                    'OTransform':'-o-transform',
2726                    'msTransform':'-ms-transform',
2727                    'MozTransform':'-moz-transform',
2728                    'transform':'transform'
2729                };
2730
2731            //preventing the style p:empty{display: none;} from returning the wrong result
2732            el.style.display = 'block'
2733
2734            // Add it to the body to get the computed style.
2735            document.body.insertBefore(el, null);
2736
2737            for (var t in transforms) {
2738                if (el.style[t] !== undefined) {
2739                    el.style[t] = 'translate3d(1px,1px,1px)';
2740                    has3d = window.getComputedStyle(el).getPropertyValue(transforms[t]);
2741                }
2742            }
2743
2744            document.body.removeChild(el);
2745
2746            return (has3d !== undefined && has3d.length > 0 && has3d !== 'none');
2747        }
2748
2749        /**
2750        * Removes the auto scrolling action fired by the mouse wheel and trackpad.
2751        * After this function is called, the mousewheel and trackpad movements won't scroll through sections.
2752        */
2753        function removeMouseWheelHandler(){
2754            if (document.addEventListener) {
2755                document.removeEventListener('mousewheel', MouseWheelHandler, false); //IE9, Chrome, Safari, Oper
2756                document.removeEventListener('wheel', MouseWheelHandler, false); //Firefox
2757                document.removeEventListener('MozMousePixelScroll', MouseWheelHandler, false); //old Firefox
2758            } else {
2759                document.detachEvent('onmousewheel', MouseWheelHandler); //IE 6/7/8
2760            }
2761        }
2762
2763        /**
2764        * Adds the auto scrolling action for the mouse wheel and trackpad.
2765        * After this function is called, the mousewheel and trackpad movements will scroll through sections
2766        * https://developer.mozilla.org/en-US/docs/Web/Events/wheel
2767        */
2768        function addMouseWheelHandler(){
2769            var prefix = '';
2770            var _addEventListener;
2771
2772            if (window.addEventListener){
2773                _addEventListener = "addEventListener";
2774            }else{
2775                _addEventListener = "attachEvent";
2776                prefix = 'on';
2777            }
2778
2779             // detect available wheel event
2780            var support = 'onwheel' in document.createElement('div') ? 'wheel' : // Modern browsers support "wheel"
2781                      document.onmousewheel !== undefined ? 'mousewheel' : // Webkit and IE support at least "mousewheel"
2782                      'DOMMouseScroll'; // let's assume that remaining browsers are older Firefox
2783
2784
2785            if(support == 'DOMMouseScroll'){
2786                document[ _addEventListener ](prefix + 'MozMousePixelScroll', MouseWheelHandler, false);
2787            }
2788
2789            //handle MozMousePixelScroll in older Firefox
2790            else{
2791                document[ _addEventListener ](prefix + support, MouseWheelHandler, false);
2792            }
2793        }
2794
2795        /**
2796        * Binding the mousemove when the mouse's middle button is pressed
2797        */
2798        function addMiddleWheelHandler(){
2799            container.addEventListener('mousedown', mouseDownHandler);
2800            container.addEventListener('mouseup', mouseUpHandler);
2801        }
2802
2803        /**
2804        * Unbinding the mousemove when the mouse's middle button is released
2805        */
2806        function removeMiddleWheelHandler(){
2807            container.removeEventListener('mousedown', mouseDownHandler);
2808            container.removeEventListener('mouseup', mouseUpHandler);
2809        }
2810
2811        /**
2812        * Adds the possibility to auto scroll through sections on touch devices.
2813        */
2814        function addTouchHandler(){
2815            if(isTouchDevice || isTouch){
2816                if(options.autoScrolling){
2817                    $body.removeEventListener(events.touchmove, preventBouncing, {passive: false});
2818                    $body.addEventListener(events.touchmove, preventBouncing, {passive: false});
2819                }
2820
2821                $(WRAPPER_SEL)[0].removeEventListener(events.touchstart, touchStartHandler);
2822                $(WRAPPER_SEL)[0].removeEventListener(events.touchmove, touchMoveHandler, {passive: false});
2823
2824                $(WRAPPER_SEL)[0].addEventListener(events.touchstart, touchStartHandler);
2825                $(WRAPPER_SEL)[0].addEventListener(events.touchmove, touchMoveHandler, {passive: false});
2826            }
2827        }
2828
2829        /**
2830        * Removes the auto scrolling for touch devices.
2831        */
2832        function removeTouchHandler(){
2833            if(isTouchDevice || isTouch){
2834                // normalScrollElements requires it off #2691
2835                if(options.autoScrolling){
2836                    $body.removeEventListener(events.touchmove, touchMoveHandler, {passive: false});
2837                    $body.removeEventListener(events.touchmove, preventBouncing, {passive: false});
2838                }
2839
2840                $(WRAPPER_SEL)[0].removeEventListener(events.touchstart, touchStartHandler);
2841                $(WRAPPER_SEL)[0].removeEventListener(events.touchmove, touchMoveHandler, {passive: false});
2842            }
2843        }
2844
2845        /*
2846        * Returns and object with Microsoft pointers (for IE<11 and for IE >= 11)
2847        * http://msdn.microsoft.com/en-us/library/ie/dn304886(v=vs.85).aspx
2848        */
2849        function getMSPointer(){
2850            var pointer;
2851
2852            //IE >= 11 & rest of browsers
2853            if(window.PointerEvent){
2854                pointer = { down: 'pointerdown', move: 'pointermove'};
2855            }
2856
2857            //IE < 11
2858            else{
2859                pointer = { down: 'MSPointerDown', move: 'MSPointerMove'};
2860            }
2861
2862            return pointer;
2863        }
2864
2865        /**
2866        * Gets the pageX and pageY properties depending on the browser.
2867        * https://github.com/alvarotrigo/fullPage.js/issues/194#issuecomment-34069854
2868        */
2869        function getEventsPage(e){
2870            var events = [];
2871
2872            events.y = (typeof e.pageY !== 'undefined' && (e.pageY || e.pageX) ? e.pageY : e.touches[0].pageY);
2873            events.x = (typeof e.pageX !== 'undefined' && (e.pageY || e.pageX) ? e.pageX : e.touches[0].pageX);
2874
2875            //in touch devices with scrollBar:true, e.pageY is detected, but we have to deal with touch events. #1008
2876            if(isTouch && isReallyTouch(e) && options.scrollBar && typeof e.touches !== 'undefined'){
2877                events.y = e.touches[0].pageY;
2878                events.x = e.touches[0].pageX;
2879            }
2880
2881            return events;
2882        }
2883
2884        /**
2885        * Slides silently (with no animation) the active slider to the given slide.
2886        * @param noCallback {bool} true or defined -> no callbacks
2887        */
2888        function silentLandscapeScroll(activeSlide, noCallbacks){
2889            setScrollingSpeed(0, 'internal');
2890
2891            if(typeof noCallbacks !== 'undefined'){
2892                //preventing firing callbacks afterSlideLoad etc.
2893                isResizing = true;
2894            }
2895
2896            landscapeScroll(closest(activeSlide, SLIDES_WRAPPER_SEL), activeSlide);
2897
2898            if(typeof noCallbacks !== 'undefined'){
2899                isResizing = false;
2900            }
2901
2902            setScrollingSpeed(originals.scrollingSpeed, 'internal');
2903        }
2904
2905        /**
2906        * Scrolls silently (with no animation) the page to the given Y position.
2907        */
2908        function silentScroll(top){
2909            // The first section can have a negative value in iOS 10. Not quite sure why: -0.0142822265625
2910            // that's why we round it to 0.
2911            var roundedTop = Math.round(top);
2912
2913            if (options.css3 && options.autoScrolling && !options.scrollBar){
2914                var translate3d = 'translate3d(0px, -' + roundedTop + 'px, 0px)';
2915                transformContainer(translate3d, false);
2916            }
2917            else if(options.autoScrolling && !options.scrollBar){
2918                css(container, {'top': -roundedTop + 'px'});
2919                FP.test.top = -roundedTop + 'px';
2920            }
2921            else{
2922                var scrollSettings = getScrollSettings(roundedTop);
2923                setScrolling(scrollSettings.element, scrollSettings.options);
2924            }
2925        }
2926
2927        /**
2928        * Returns the cross-browser transform string.
2929        */
2930        function getTransforms(translate3d){
2931            return {
2932                '-webkit-transform': translate3d,
2933                '-moz-transform': translate3d,
2934                '-ms-transform':translate3d,
2935                'transform': translate3d
2936            };
2937        }
2938
2939        /**
2940        * Allowing or disallowing the mouse/swipe scroll in a given direction. (not for keyboard)
2941        * @type  m (mouse) or k (keyboard)
2942        */
2943        function setIsScrollAllowed(value, direction, type){
2944            //up, down, left, right
2945            if(direction !== 'all'){
2946                isScrollAllowed[type][direction] = value;
2947            }
2948
2949            //all directions?
2950            else{
2951                Object.keys(isScrollAllowed[type]).forEach(function(key){
2952                    isScrollAllowed[type][key] = value;
2953                });
2954            }
2955        }
2956
2957        /*
2958        * Destroys fullpage.js plugin events and optinally its html markup and styles
2959        */
2960        function destroy(all){
2961            setAutoScrolling(false, 'internal');
2962            setAllowScrolling(false);
2963            setKeyboardScrolling(false);
2964            addClass(container, DESTROYED);
2965
2966            clearTimeout(afterSlideLoadsId);
2967            clearTimeout(afterSectionLoadsId);
2968            clearTimeout(resizeId);
2969            clearTimeout(scrollId);
2970            clearTimeout(scrollId2);
2971
2972
2973            window.removeEventListener('scroll', scrollHandler);
2974            window.removeEventListener('hashchange', hashChangeHandler);
2975            window.removeEventListener('resize', resizeHandler);
2976
2977            document.removeEventListener('keydown', keydownHandler);
2978            document.removeEventListener('keyup', keyUpHandler);
2979
2980            var clickTouchEvents = [sectionBulletHandler, tooltipTextHandler, slideArrowHandler, slideBulletHandler];
2981            ['click', 'touchstart'].forEach(function(eventName){
2982                clickTouchEvents.forEach(function(foo){
2983                    document.removeEventListener(eventName, foo);
2984                });
2985            });
2986
2987            ['mouseenter', 'touchstart', 'mouseleave', 'touchend'].forEach(function(eventName){
2988                document.removeEventListener(eventName, onMouseEnterOrLeave, true); //true is required!
2989            });
2990
2991            clearTimeout(afterSlideLoadsId);
2992            clearTimeout(afterSectionLoadsId);
2993
2994            //lets make a mess!
2995            if(all){
2996                destroyStructure();
2997            }
2998        }
2999
3000        /*
3001        * Removes inline styles added by fullpage.js
3002        */
3003        function destroyStructure(){
3004            //reseting the `top` or `translate` properties to 0
3005            silentScroll(0);
3006
3007            //loading all the lazy load content
3008            $('img[data-src], source[data-src], audio[data-src], iframe[data-src]', container).forEach(function(item){
3009                setSrc(item, 'src');
3010            });
3011
3012            $('img[data-srcset]').forEach(function(item){
3013                setSrc(item, 'srcset');
3014            });
3015
3016            remove($(SECTION_NAV_SEL + ', ' + SLIDES_NAV_SEL +  ', ' + SLIDES_ARROW_SEL));
3017
3018            //removing inline styles
3019            css($(SECTION_SEL), {
3020                'height': '',
3021                'background-color' : '',
3022                'padding': ''
3023            });
3024
3025            css($(SLIDE_SEL), {
3026                'width': ''
3027            });
3028
3029            css(container, {
3030                'height': '',
3031                'position': '',
3032                '-ms-touch-action': '',
3033                'touch-action': ''
3034            });
3035
3036            css($htmlBody, {
3037                'overflow': '',
3038                'height': ''
3039            });
3040
3041            // remove .fp-enabled class
3042            removeClass($('html'), ENABLED);
3043
3044            // remove .fp-responsive class
3045            removeClass($body, RESPONSIVE);
3046
3047            // remove all of the .fp-viewing- classes
3048            $body.className.split(/\s+/).forEach(function (className) {
3049                if (className.indexOf(VIEWING_PREFIX) === 0) {
3050                    removeClass($body, className);
3051                }
3052            });
3053
3054            //removing added classes
3055            $(SECTION_SEL + ', ' + SLIDE_SEL).forEach(function(item){
3056                if(options.scrollOverflowHandler){
3057                    options.scrollOverflowHandler.remove(item);
3058                }
3059                removeClass(item, TABLE + ' ' + ACTIVE + ' ' + COMPLETELY);
3060                var previousStyles = item.getAttribute('data-fp-styles');
3061                if(previousStyles){
3062                    item.setAttribute('style', item.getAttribute('data-fp-styles'));
3063                }
3064            });
3065
3066            //removing the applied transition from the fullpage wrapper
3067            removeAnimation(container);
3068
3069            //Unwrapping content
3070            [TABLE_CELL_SEL, SLIDES_CONTAINER_SEL,SLIDES_WRAPPER_SEL].forEach(function(selector){
3071                $(selector, container).forEach(function(item){
3072                    //unwrap not being use in case there's no child element inside and its just text
3073                    item.outerHTML = item.innerHTML;
3074                });
3075            });
3076
3077            //removing the applied transition from the fullpage wrapper
3078            css(container, {
3079                '-webkit-transition': 'none',
3080                'transition': 'none'
3081            });
3082
3083            //scrolling the page to the top with no animation
3084            $('html')[0].scrollTo(0, 0);
3085            $('body')[0].scrollTo(0, 0);
3086
3087            //removing selectors
3088            var usedSelectors = [SECTION, SLIDE, SLIDES_CONTAINER];
3089            usedSelectors.forEach(function(item){
3090                removeClass($('.' + item), item);
3091            });
3092        }
3093
3094        /*
3095        * Sets the state for a variable with multiple states (original, and temporal)
3096        * Some variables such as `autoScrolling` or `recordHistory` might change automatically its state when using `responsive` or `autoScrolling:false`.
3097        * This function is used to keep track of both states, the original and the temporal one.
3098        * If type is not 'internal', then we assume the user is globally changing the variable.
3099        */
3100        function setVariableState(variable, value, type){
3101            options[variable] = value;
3102            if(type !== 'internal'){
3103                originals[variable] = value;
3104            }
3105        }
3106
3107        /**
3108        * Displays warnings
3109        */
3110        function displayWarnings(){
3111            if(!isLicenseValid){
3112            //    showError('error', 'Fullpage.js version 3 has changed its license to GPLv3 and it requires a `licenseKey` option. Read about it here:');
3113            //    showError('error', 'https://github.com/alvarotrigo/fullPage.js#options.');
3114            }
3115
3116            var extensions = ['fadingEffect', 'continuousHorizontal', 'scrollHorizontally', 'interlockedSlides', 'resetSliders', 'responsiveSlides', 'offsetSections', 'dragAndMove', 'scrollOverflowReset', 'parallax'];
3117            if(hasClass($('html'), ENABLED)){
3118                showError('error', 'Fullpage.js can only be initialized once and you are doing it multiple times!');
3119                return;
3120            }
3121
3122            // Disable mutually exclusive settings
3123            if (options.continuousVertical &&
3124                (options.loopTop || options.loopBottom)) {
3125                options.continuousVertical = false;
3126                showError('warn', 'Option `loopTop/loopBottom` is mutually exclusive with `continuousVertical`; `continuousVertical` disabled');
3127            }
3128
3129            if(options.scrollBar && options.scrollOverflow){
3130                showError('warn', 'Option `scrollBar` is mutually exclusive with `scrollOverflow`. Sections with scrollOverflow might not work well in Firefox');
3131            }
3132
3133            if(options.continuousVertical && (options.scrollBar || !options.autoScrolling)){
3134                options.continuousVertical = false;
3135                showError('warn', 'Scroll bars (`scrollBar:true` or `autoScrolling:false`) are mutually exclusive with `continuousVertical`; `continuousVertical` disabled');
3136            }
3137
3138            if(options.scrollOverflow && options.scrollOverflowHandler == null){
3139                options.scrollOverflow = false;
3140                showError('error', 'The option `scrollOverflow:true` requires the file `scrolloverflow.min.js`. Please include it before fullPage.js.');
3141            }
3142
3143            //using extensions? Wrong file!
3144            extensions.forEach(function(extension){
3145                //is the option set to true?
3146                if(options[extension]){
3147                    showError('warn', 'fullpage.js extensions require jquery.fullpage.extensions.min.js file instead of the usual jquery.fullpage.js. Requested: '+ extension);
3148                }
3149            });
3150
3151            //anchors can not have the same value as any element ID or NAME
3152            options.anchors.forEach(function(name){
3153
3154                //case insensitive selectors (http://stackoverflow.com/a/19465187/1081396)
3155                var nameAttr =  [].slice.call($('[name]')).filter(function(item) {
3156                    return item.getAttribute('name') && item.getAttribute('name').toLowerCase() == name.toLowerCase();
3157                });
3158
3159                var idAttr =  [].slice.call($('[id]')).filter(function(item) {
3160                    return item.getAttribute('id') && item.getAttribute('id').toLowerCase() == name.toLowerCase();
3161                });
3162
3163                if(idAttr.length || nameAttr.length ){
3164                    showError('error', 'data-anchor tags can not have the same value as any `id` element on the site (or `name` element for IE).');
3165                    if(idAttr.length){
3166                        showError('error', '"' + name + '" is is being used by another element `id` property');
3167                    }
3168                    if(nameAttr.length){
3169                        showError('error', '"' + name + '" is is being used by another element `name` property');
3170                    }
3171                }
3172            });
3173        }
3174
3175        /**
3176        * Getting the position of the element to scroll when using jQuery animations
3177        */
3178        function getScrolledPosition(element){
3179            var position;
3180
3181            //is not the window element and is a slide?
3182            if(element.self != window && hasClass(element, SLIDES_WRAPPER)){
3183                position = element.scrollLeft;
3184            }
3185            else if(!options.autoScrolling  || options.scrollBar){
3186                position = getScrollTop();
3187            }
3188            else{
3189                position = element.offsetTop;
3190            }
3191
3192            //gets the top property of the wrapper
3193            return position;
3194        }
3195
3196        /**
3197        * Simulates the animated scrollTop of jQuery. Used when css3:false or scrollBar:true or autoScrolling:false
3198        * http://stackoverflow.com/a/16136789/1081396
3199        */
3200        function scrollTo(element, to, duration, callback) {
3201            var start = getScrolledPosition(element);
3202            var change = to - start;
3203            var currentTime = 0;
3204            var increment = 20;
3205            activeAnimation = true;
3206
3207            var animateScroll = function(){
3208                if(activeAnimation){ //in order to stope it from other function whenever we want
3209                    var val = to;
3210
3211                    currentTime += increment;
3212
3213                    if(duration){
3214                        val = window.fp_easings[options.easing](currentTime, start, change, duration);
3215                    }
3216
3217                    setScrolling(element, val);
3218
3219                    if(currentTime < duration) {
3220                        setTimeout(animateScroll, increment);
3221                    }else if(typeof callback !== 'undefined'){
3222                        callback();
3223                    }
3224                }else if (currentTime < duration){
3225                    callback();
3226                }
3227            };
3228
3229            animateScroll();
3230        }
3231
3232        /**
3233        * Scrolls the page / slider the given number of pixels.
3234        * It will do it one or another way dependiong on the library's config.
3235        */
3236        function setScrolling(element, val){
3237            if(!options.autoScrolling || options.scrollBar || (element.self != window && hasClass(element, SLIDES_WRAPPER))){
3238
3239                //scrolling horizontally through the slides?
3240                if(element.self != window  && hasClass(element, SLIDES_WRAPPER)){
3241                    element.scrollLeft = val;
3242                }
3243                //vertical scroll
3244                else{
3245                    element.scrollTo(0, val);
3246                }
3247            }else{
3248                 element.style.top = val + 'px';
3249            }
3250        }
3251
3252        /**
3253        * Gets the active slide.
3254        */
3255        function getActiveSlide(){
3256            var activeSlide = $(SLIDE_ACTIVE_SEL, $(SECTION_ACTIVE_SEL)[0])[0];
3257            return nullOrSlide(activeSlide);
3258        }
3259
3260        /**
3261        * Gets the active section.
3262        */
3263        function getActiveSection(){
3264            return new Section($(SECTION_ACTIVE_SEL)[0]);
3265        }
3266
3267        /**
3268        * Item. Slide or Section objects share the same properties.
3269        */
3270        function Item(el, selector){
3271            this.anchor = el.getAttribute('data-anchor');
3272            this.item = el;
3273            this.index = index(el, selector);
3274            this.isLast = this.index === $(selector).length -1;
3275            this.isFirst = !this.index;
3276        }
3277
3278        /**
3279        * Section object
3280        */
3281        function Section(el){
3282            Item.call(this, el, SECTION_SEL);
3283        }
3284
3285        /**
3286        * Slide object
3287        */
3288        function Slide(el){
3289            Item.call(this, el, SLIDE_SEL);
3290        }
3291
3292        return FP;
3293    } //end of $.fn.fullpage
3294
3295
3296    //utils
3297    /**
3298    * Shows a message in the console of the given type.
3299    */
3300    function showError(type, text){
3301      //  window.console && window.console[type] && window.console[type]('fullPage: ' + text);
3302    }
3303
3304    /**
3305    * Equivalent or jQuery function $().
3306    */
3307    function $(selector, context){
3308        context = arguments.length > 1 ? context : document;
3309        return context ? context.querySelectorAll(selector) : null;
3310    }
3311
3312    /**
3313    * Extends a given Object properties and its childs.
3314    */
3315    function deepExtend(out) {
3316      out = out || {};
3317
3318      for (var i = 1; i < arguments.length; i++) {
3319        var obj = arguments[i];
3320
3321        if (!obj)
3322          continue;
3323
3324        for (var key in obj) {
3325          if (obj.hasOwnProperty(key)) {
3326            if (typeof obj[key] === 'object' && obj[key] != null)
3327              out[key] = deepExtend(out[key], obj[key]);
3328            else
3329              out[key] = obj[key];
3330          }
3331        }
3332      }
3333
3334      return out;
3335    }
3336
3337    /**
3338    * Checks if the passed element contains the passed class.
3339    */
3340    function hasClass(el, className){
3341        if(el == null){
3342            return false;
3343        }
3344        if (el.classList){
3345            return el.classList.contains(className);
3346        }
3347        return new RegExp('(^| )' + className + '( |$)', 'gi').test(el.className);
3348    }
3349
3350    /**
3351    * Gets the window height. Crossbrowser.
3352    */
3353    function getWindowHeight(){
3354        return  'innerHeight' in window ? window.innerHeight : document.documentElement.offsetHeight;
3355    }
3356
3357    /**
3358    * Set's the CSS properties for the passed item/s.
3359    * @param {NodeList|HTMLElement} items
3360    * @param {Object} props css properties and values.
3361    */
3362    function css(items, props) {
3363        items = getList(items);
3364
3365        var key;
3366        for (key in props) {
3367            if (props.hasOwnProperty(key)) {
3368                if (key !== null) {
3369                    for (var i = 0; i < items.length; i++) {
3370                        var item = items[i];
3371                        item.style[key] = props[key];
3372                    }
3373                }
3374            }
3375        }
3376
3377        return items;
3378    }
3379
3380    /**
3381    * Generic function to get the previous or next element.
3382    */
3383    function until(item, selector, fn){
3384        var sibling = item[fn];
3385        while(sibling && !matches(sibling, selector)){
3386            sibling = sibling[fn];
3387        }
3388
3389        return sibling;
3390    }
3391
3392    /**
3393    * Gets the previous element to the passed element that matches the passed selector.
3394    */
3395    function prevUntil(item, selector){
3396        return until(item, selector, 'previousElementSibling');
3397    }
3398
3399    /**
3400    * Gets the next element to the passed element that matches the passed selector.
3401    */
3402    function nextUntil(item, selector){
3403        return until(item, selector, 'nextElementSibling');
3404    }
3405
3406    /**
3407    * Gets the previous element to the passed element.
3408    */
3409    function prev(item){
3410        return item.previousElementSibling;
3411    }
3412
3413    /**
3414    * Gets the next element to the passed element.
3415    */
3416    function next(item){
3417        return item.nextElementSibling;
3418    }
3419
3420    /**
3421    * Gets the last element from the passed list of elements.
3422    */
3423    function last(item){
3424        return item[item.length-1];
3425    }
3426
3427    /**
3428    * Gets index from the passed element.
3429    * @param {String} selector is optional.
3430    */
3431    function index(item, selector) {
3432        item = isArrayOrList(item) ? item[0] : item;
3433        var children = selector != null? $(selector, item.parentNode) : item.parentNode.childNodes;
3434        var num = 0;
3435        for (var i=0; i<children.length; i++) {
3436             if (children[i] == item) return num;
3437             if (children[i].nodeType==1) num++;
3438        }
3439        return -1;
3440    }
3441
3442    /**
3443    * Gets an iterable element for the passed element/s
3444    */
3445    function getList(item){
3446        return !isArrayOrList(item) ? [item] : item;
3447    }
3448
3449    /**
3450    * Adds the display=none property for the passed element/s
3451    */
3452    function hide(el){
3453        el = getList(el);
3454
3455        for(var i = 0; i<el.length; i++){
3456            el[i].style.display = 'none';
3457        }
3458        return el;
3459    }
3460
3461    /**
3462    * Adds the display=block property for the passed element/s
3463    */
3464    function show(el){
3465        el = getList(el);
3466
3467        for(var i = 0; i<el.length; i++){
3468            el[i].style.display = 'block';
3469        }
3470        return el;
3471    }
3472
3473    /**
3474    * Checks if the passed element is an iterable element or not
3475    */
3476    function isArrayOrList(el){
3477        return Object.prototype.toString.call( el ) === '[object Array]' ||
3478            Object.prototype.toString.call( el ) === '[object NodeList]';
3479    }
3480
3481    /**
3482    * Adds the passed class to the passed element/s
3483    */
3484    function addClass(el, className) {
3485        el = getList(el);
3486
3487        for(var i = 0; i<el.length; i++){
3488            var item = el[i];
3489            if (item.classList){
3490                item.classList.add(className);
3491            }
3492            else{
3493              item.className += ' ' + className;
3494            }
3495        }
3496        return el;
3497    }
3498
3499    /**
3500    * Removes the passed class to the passed element/s
3501    * @param {String} `className` can be multiple classnames separated by whitespace
3502    */
3503    function removeClass(el, className){
3504        el = getList(el);
3505
3506        var classNames = className.split(' ');
3507
3508        for(var a = 0; a<classNames.length; a++){
3509            className = classNames[a];
3510            for(var i = 0; i<el.length; i++){
3511                var item = el[i];
3512                if (item.classList){
3513                    item.classList.remove(className);
3514                }
3515                else{
3516                    item.className = item.className.replace(new RegExp('(^|\\b)' + className.split(' ').join('|') + '(\\b|$)', 'gi'), ' ');
3517                }
3518            }
3519        }
3520        return el;
3521    }
3522
3523    /**
3524    * Appends the given element ot the given parent.
3525    */
3526    function appendTo(el, parent){
3527        parent.appendChild(el);
3528    }
3529
3530    /**
3531    Usage:
3532
3533    var wrapper = document.createElement('div');
3534    wrapper.className = 'fp-slides';
3535    wrap($('.slide'), wrapper);
3536
3537    https://jsfiddle.net/qwzc7oy3/15/ (vanilla)
3538    https://jsfiddle.net/oya6ndka/1/ (jquery equivalent)
3539    */
3540    function wrap(toWrap, wrapper, isWrapAll) {
3541        var newParent;
3542        wrapper = wrapper || document.createElement('div');
3543        for(var i = 0; i < toWrap.length; i++){
3544            var item = toWrap[i];
3545            if(isWrapAll && !i || !isWrapAll){
3546                newParent = wrapper.cloneNode(true);
3547                item.parentNode.insertBefore(newParent, item);
3548            }
3549            newParent.appendChild(item);
3550        }
3551        return toWrap;
3552    }
3553
3554    /**
3555    Usage:
3556    var wrapper = document.createElement('div');
3557    wrapper.className = 'fp-slides';
3558    wrap($('.slide'), wrapper);
3559
3560    https://jsfiddle.net/qwzc7oy3/27/ (vanilla)
3561    https://jsfiddle.net/oya6ndka/4/ (jquery equivalent)
3562    */
3563    function wrapAll(toWrap, wrapper) {
3564        wrap(toWrap, wrapper, true);
3565    }
3566
3567    /**
3568    * Usage:
3569    * wrapInner(document.querySelector('#pepe'), '<div class="test">afdas</div>');
3570    * wrapInner(document.querySelector('#pepe'), element);
3571    *
3572    * https://jsfiddle.net/zexxz0tw/6/
3573    *
3574    * https://stackoverflow.com/a/21817590/1081396
3575    */
3576    function wrapInner(parent, wrapper) {
3577        if (typeof wrapper === "string"){
3578            wrapper = createElementFromHTML(wrapper);
3579        }
3580
3581        parent.appendChild(wrapper);
3582
3583        while(parent.firstChild !== wrapper){
3584            wrapper.appendChild(parent.firstChild);
3585       }
3586    }
3587
3588    /**
3589    * http://stackoverflow.com/questions/22100853/dom-pure-javascript-solution-to-jquery-closest-implementation
3590    * Returns the element or `false` if there's none
3591    */
3592    function closest(el, selector) {
3593        if(el && el.nodeType === 1){
3594            if(matches(el, selector)){
3595                return el;
3596            }
3597            return closest(el.parentNode, selector);
3598        }
3599        return null;
3600    }
3601
3602    /**
3603    * Places one element (rel) after another one or group of them (reference).
3604    * @param {HTMLElement} reference
3605    * @param {HTMLElement|NodeList|String} el
3606    * https://jsfiddle.net/9s97hhzv/1/
3607    */
3608    function after(reference, el) {
3609        insertBefore(reference, reference.nextSibling, el);
3610    }
3611
3612    /**
3613    * Places one element (rel) before another one or group of them (reference).
3614    * @param {HTMLElement} reference
3615    * @param {HTMLElement|NodeList|String} el
3616    * https://jsfiddle.net/9s97hhzv/1/
3617    */
3618    function before(reference, el) {
3619        insertBefore(reference, reference, el);
3620    }
3621
3622    /**
vendor: 6,863 bytes, lines 3623-3865
3623    * Based in https://stackoverflow.com/a/19316024/1081396
3624    * and https://stackoverflow.com/a/4793630/1081396
3625    */
3626    function insertBefore(reference, beforeElement, el){
3627        if(!isArrayOrList(el)){
3628            if(typeof el == 'string'){
3629                el = createElementFromHTML(el);
3630            }
3631            el = [el];
3632        }
3633
3634        for(var i = 0; i<el.length; i++){
3635            reference.parentNode.insertBefore(el[i], beforeElement);
3636        }
3637    }
3638
3639    //http://stackoverflow.com/questions/3464876/javascript-get-window-x-y-position-for-scroll
3640    function getScrollTop(){
3641        var doc = document.documentElement;
3642        return (window.pageYOffset || doc.scrollTop)  - (doc.clientTop || 0);
3643    }
3644
3645    /**
3646    * Gets the siblings of the passed element
3647    */
3648    function siblings(el){
3649        return Array.prototype.filter.call(el.parentNode.children, function(child){
3650          return child !== el;
3651        });
3652    }
3653
3654    //for IE 9 ?
3655    function preventDefault(event){
3656        if(event.preventDefault){
3657            event.preventDefault();
3658        }
3659        else{
3660            event.returnValue = false;
3661        }
3662    }
3663
3664    /**
3665    * Determines whether the passed item is of function type.
3666    */
3667    function isFunction(item) {
3668      if (typeof item === 'function') {
3669        return true;
3670      }
3671      var type = Object.prototype.toString(item);
3672      return type === '[object Function]' || type === '[object GeneratorFunction]';
3673    }
3674
3675    /**
3676    * Trigger custom events
3677    */
3678    function trigger(el, eventName, data){
3679        var event;
3680        data = typeof data === 'undefined' ? {} : data;
3681
3682        // Native
3683        if(typeof window.CustomEvent === "function" ){
3684            event = new CustomEvent(eventName, {detail: data});
3685        }
3686        else{
3687            event = document.createEvent('CustomEvent');
3688            event.initCustomEvent(eventName, true, true, data);
3689        }
3690
3691        el.dispatchEvent(event);
3692    }
3693
3694    /**
3695    * Polyfill of .matches()
3696    */
3697    function matches(el, selector) {
3698        return (el.matches || el.matchesSelector || el.msMatchesSelector || el.mozMatchesSelector || el.webkitMatchesSelector || el.oMatchesSelector).call(el, selector);
3699    }
3700
3701    /**
3702    * Toggles the visibility of the passed element el.
3703    */
3704    function toggle(el, value){
3705        if(typeof value === "boolean"){
3706            for(var i = 0; i<el.length; i++){
3707                el[i].style.display = value ? 'block' : 'none';
3708            }
3709        }
3710        //we don't use it in other way, so no else :)
3711
3712        return el;
3713    }
3714
3715    /**
3716    * Creates a HTMLElement from the passed HTML string.
3717    * https://stackoverflow.com/a/494348/1081396
3718    */
3719    function createElementFromHTML(htmlString) {
3720        var div = document.createElement('div');
3721        div.innerHTML = htmlString.trim();
3722
3723        // Change this to div.childNodes to support multiple top-level nodes
3724        return div.firstChild;
3725    }
3726
3727    /**
3728    * Removes the passed item/s from the DOM.
3729    */
3730    function remove(items){
3731        items = getList(items);
3732        for(var i = 0; i<items.length; i++){
3733            var item = items[i];
3734            if(item && item.parentElement) {
3735                item.parentNode.removeChild(item);
3736            }
3737        }
3738    }
3739
3740    /**
3741    * Filters an array by the passed filter funtion.
3742    */
3743    function filter(el, filterFn){
3744        Array.prototype.filter.call(el, filterFn);
3745    }
3746
3747    //https://jsfiddle.net/w1rktecz/
3748    function untilAll(item, selector, fn){
3749        var sibling = item[fn];
3750        var siblings = [];
3751        while(sibling){
3752            if(matches(sibling, selector) || selector == null) {
3753                siblings.push(sibling);
3754            }
3755            sibling = sibling[fn];
3756        }
3757
3758        return siblings;
3759    }
3760
3761    /**
3762    * Gets all next elements matching the passed selector.
3763    */
3764    function nextAll(item, selector){
3765        return untilAll(item, selector, 'nextElementSibling');
3766    }
3767
3768    /**
3769    * Gets all previous elements matching the passed selector.
3770    */
3771    function prevAll(item, selector){
3772        return untilAll(item, selector, 'previousElementSibling');
3773    }
3774
3775    /**
3776    * Converts an object to an array.
3777    */
3778    function toArray(objectData){
3779        return Object.keys(objectData).map(function(key) {
3780           return objectData[key];
3781        });
3782    }
3783
3784    /**
3785    * forEach polyfill for IE
3786    * https://developer.mozilla.org/en-US/docs/Web/API/NodeList/forEach#Browser_Compatibility
3787    */
3788    if (window.NodeList && !NodeList.prototype.forEach) {
3789        NodeList.prototype.forEach = function (callback, thisArg) {
3790            thisArg = thisArg || window;
3791            for (var i = 0; i < this.length; i++) {
3792                callback.call(thisArg, this[i], i, this);
3793            }
3794        };
3795    }
3796
3797    //utils are public, so we can use it wherever we want
3798    window.fp_utils = {
3799        $: $,
3800        deepExtend: deepExtend,
3801        hasClass: hasClass,
3802        getWindowHeight: getWindowHeight,
3803        css: css,
3804        until: until,
3805        prevUntil: prevUntil,
3806        nextUntil: nextUntil,
3807        prev: prev,
3808        next: next,
3809        last: last,
3810        index: index,
3811        getList: getList,
3812        hide: hide,
3813        show: show,
3814        isArrayOrList: isArrayOrList,
3815        addClass: addClass,
3816        removeClass: removeClass,
3817        appendTo: appendTo,
3818        wrap: wrap,
3819        wrapAll: wrapAll,
3820        wrapInner: wrapInner,
3821        closest: closest,
3822        after: after,
3823        before: before,
3824        insertBefore: insertBefore,
3825        getScrollTop: getScrollTop,
3826        siblings: siblings,
3827        preventDefault: preventDefault,
3828        isFunction: isFunction,
3829        trigger: trigger,
3830        matches: matches,
3831        toggle: toggle,
3832        createElementFromHTML: createElementFromHTML,
3833        remove: remove,
3834        filter: filter,
3835        untilAll: untilAll,
3836        nextAll: nextAll,
3837        prevAll: prevAll
3838    };
3839
3840    return initialise;
3841}));
3842
3843/**
3844 * jQuery adapter for fullPage.js 3.0.0
3845 */
3846if(window.jQuery){
3847    (function ($, fullpage) {
3848        'use strict';
3849
3850        // No jQuery No Go
3851        if (!$ || !fullpage) {
3852            window.fp_utils.showError('error', 'jQuery is required to use the jQuery fullpage adapter!');
3853            return;
3854        }
3855
3856        $.fn.fullpage = function(options) {
3857            var FP = new fullpage('#' + $(this).attr('id'), options);
3858
3859            //Static API
3860            Object.keys(FP).forEach(function (key) {
3861                $.fn.fullpage[key] = FP[key];
3862            });
3863        };
3864    })(jQuery, fullpage);
3865}

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.