PageSourceSearch

https://www.gwangbok.kr/js/fullpage/jquery.fullPage.js

js gwangbok.kr collected 2026-10-09 22:41:15 UTC 101,206 bytes, 2,664 lines download raw bytes

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

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.