spinopel.github.io

Форк
0
/
script.js 
3125 строк · 117.8 Кб
1
/*!
2
 * fullPage 2.9.4
3
 * https://github.com/alvarotrigo/fullPage.js
4
 * @license MIT licensed
5
 *
6
 * Copyright (C) 2015 alvarotrigo.com - A project by Alvaro Trigo
7
 */
8
(function(global, factory) {
9
    'use strict';
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 === "object" && exports) {
15
        module.exports = factory(require('jquery'), global, global.document, global.Math);
16
    } else {
17
        factory(jQuery, global, global.document, global.Math);
18
    }
19
})(typeof window !== 'undefined' ? window : this, function($, window, document, Math, undefined) {
20
    'use strict';
21

22
    // keeping central set of classnames and selectors
23
    var WRAPPER =               'fullpage-wrapper';
24
    var WRAPPER_SEL =           '.' + WRAPPER;
25

26
    // slimscroll
27
    var SCROLLABLE =            'fp-scrollable';
28
    var SCROLLABLE_SEL =        '.' + SCROLLABLE;
29

30
    // util
31
    var RESPONSIVE =            'fp-responsive';
32
    var NO_TRANSITION =         'fp-notransition';
33
    var DESTROYED =             'fp-destroyed';
34
    var ENABLED =               'fp-enabled';
35
    var VIEWING_PREFIX =        'fp-viewing';
36
    var ACTIVE =                'active';
37
    var ACTIVE_SEL =            '.' + ACTIVE;
38
    var COMPLETELY =            'fp-completely';
39
    var COMPLETELY_SEL =        '.' + COMPLETELY;
40

41
    // section
42
    var SECTION_DEFAULT_SEL =   '.section';
43
    var SECTION =               'fp-section';
44
    var SECTION_SEL =           '.' + SECTION;
45
    var SECTION_ACTIVE_SEL =    SECTION_SEL + ACTIVE_SEL;
46
    var SECTION_FIRST_SEL =     SECTION_SEL + ':first';
47
    var SECTION_LAST_SEL =      SECTION_SEL + ':last';
48
    var TABLE_CELL =            'fp-tableCell';
49
    var TABLE_CELL_SEL =        '.' + TABLE_CELL;
50
    var AUTO_HEIGHT =           'fp-auto-height';
51
    var AUTO_HEIGHT_SEL =       '.fp-auto-height';
52
    var NORMAL_SCROLL =         'fp-normal-scroll';
53
    var NORMAL_SCROLL_SEL =     '.fp-normal-scroll';
54

55
    // section nav
56
    var SECTION_NAV =           'fp-nav';
57
    var SECTION_NAV_SEL =       '#' + SECTION_NAV;
58
    var SECTION_NAV_TOOLTIP =   'fp-tooltip';
59
    var SECTION_NAV_TOOLTIP_SEL='.'+SECTION_NAV_TOOLTIP;
60
    var SHOW_ACTIVE_TOOLTIP =   'fp-show-active';
61

62
    // slide
63
    var SLIDE_DEFAULT_SEL =     '.slide';
64
    var SLIDE =                 'fp-slide';
65
    var SLIDE_SEL =             '.' + SLIDE;
66
    var SLIDE_ACTIVE_SEL =      SLIDE_SEL + ACTIVE_SEL;
67
    var SLIDES_WRAPPER =        'fp-slides';
68
    var SLIDES_WRAPPER_SEL =    '.' + SLIDES_WRAPPER;
69
    var SLIDES_CONTAINER =      'fp-slidesContainer';
70
    var SLIDES_CONTAINER_SEL =  '.' + SLIDES_CONTAINER;
71
    var TABLE =                 'fp-table';
72

73
    // slide nav
74
    var SLIDES_NAV =            'fp-slidesNav';
75
    var SLIDES_NAV_SEL =        '.' + SLIDES_NAV;
76
    var SLIDES_NAV_LINK_SEL =   SLIDES_NAV_SEL + ' a';
77
    var SLIDES_ARROW =          'fp-controlArrow';
78
    var SLIDES_ARROW_SEL =      '.' + SLIDES_ARROW;
79
    var SLIDES_PREV =           'fp-prev';
80
    var SLIDES_PREV_SEL =       '.' + SLIDES_PREV;
81
    var SLIDES_ARROW_PREV =     SLIDES_ARROW + ' ' + SLIDES_PREV;
82
    var SLIDES_ARROW_PREV_SEL = SLIDES_ARROW_SEL + SLIDES_PREV_SEL;
83
    var SLIDES_NEXT =           'fp-next';
84
    var SLIDES_NEXT_SEL =       '.' + SLIDES_NEXT;
85
    var SLIDES_ARROW_NEXT =     SLIDES_ARROW + ' ' + SLIDES_NEXT;
86
    var SLIDES_ARROW_NEXT_SEL = SLIDES_ARROW_SEL + SLIDES_NEXT_SEL;
87

88
    var $window = $(window);
89
    var $document = $(document);
90

91
    // Default options for iScroll.js used when using scrollOverflow
92
    var iscrollOptions = {
93
        scrollbars: true,
94
        mouseWheel: true,
95
        hideScrollbars: false,
96
        fadeScrollbars: false,
97
        disableMouse: true,
98
        interactiveScrollbars: true
99
    };
100

101
    $.fn.fullpage = function(options) {
102
        //only once my friend!
103
        if($('html').hasClass(ENABLED)){ displayWarnings(); return; }
104

105
        // common jQuery objects
106
        var $htmlBody = $('html, body');
107
        var $body = $('body');
108

109
        var FP = $.fn.fullpage;
110

111
        // Creating some defaults, extending them with any options that were provided
112
        options = $.extend({
113
            //navigation
114
            menu: false,
115
            anchors:[],
116
            lockAnchors: false,
117
            navigation: false,
118
            navigationPosition: 'right',
119
            navigationTooltips: [],
120
            showActiveTooltip: false,
121
            slidesNavigation: false,
122
            slidesNavPosition: 'bottom',
123
            scrollBar: false,
124
            hybrid: false,
125

126
            //scrolling
127
            css3: true,
128
            scrollingSpeed: 700,
129
            autoScrolling: true,
130
            fitToSection: true,
131
            fitToSectionDelay: 1000,
132
            easing: 'easeInOutCubic',
133
            easingcss3: 'ease',
134
            loopBottom: false,
135
            loopTop: false,
136
            loopHorizontal: true,
137
            continuousVertical: false,
138
            continuousHorizontal: false,
139
            scrollHorizontally: false,
140
            interlockedSlides: false,
141
            dragAndMove: false,
142
            offsetSections: false,
143
            resetSliders: false,
144
            fadingEffect: false,
145
            normalScrollElements: null,
146
            scrollOverflow: false,
147
            scrollOverflowReset: false,
148
            scrollOverflowHandler: iscrollHandler,
149
            scrollOverflowOptions: null,
150
            touchSensitivity: 5,
151
            normalScrollElementTouchThreshold: 5,
152
            bigSectionsDestination: null,
153

154
            //Accessibility
155
            keyboardScrolling: true,
156
            animateAnchor: true,
157
            recordHistory: true,
158

159
            //design
160
            controlArrows: true,
161
            controlArrowColor: '#fff',
162
            verticalCentered: true,
163
            sectionsColor : [],
164
            paddingTop: 0,
165
            paddingBottom: 0,
166
            fixedElements: null,
167
            responsive: 0, //backwards compabitility with responsiveWiddth
168
            responsiveWidth: 0,
169
            responsiveHeight: 0,
170
            responsiveSlides: false,
171
            parallax: false,
172
            parallaxOptions: {
173
                type: 'reveal',
174
                percentage: 62,
175
                property: 'translate'
176
            },
177

178
            //Custom selectors
179
            sectionSelector: SECTION_DEFAULT_SEL,
180
            slideSelector: SLIDE_DEFAULT_SEL,
181

182
            //events
183
            afterLoad: null,
184
            onLeave: null,
185
            afterRender: null,
186
            afterResize: null,
187
            afterReBuild: null,
188
            afterSlideLoad: null,
189
            onSlideLeave: null,
190
            afterResponsive: null,
191

192
            lazyLoading: true
193
        }, options);
194

195
        //flag to avoid very fast sliding for landscape sliders
196
        var slideMoving = false;
197

198
        var isTouchDevice = navigator.userAgent.match(/(iPhone|iPod|iPad|Android|playbook|silk|BlackBerry|BB10|Windows Phone|Tizen|Bada|webOS|IEMobile|Opera Mini)/);
199
        var isTouch = (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0) || (navigator.maxTouchPoints));
200
        var container = $(this);
201
        var windowsHeight = $window.height();
202
        var isResizing = false;
203
        var isWindowFocused = true;
204
        var lastScrolledDestiny;
205
        var lastScrolledSlide;
206
        var canScroll = true;
207
        var scrollings = [];
208
        var controlPressed;
209
        var startingSection;
210
        var isScrollAllowed = {};
211
        isScrollAllowed.m = {  'up':true, 'down':true, 'left':true, 'right':true };
212
        isScrollAllowed.k = $.extend(true,{}, isScrollAllowed.m);
213
        var MSPointer = getMSPointer();
214
        var events = {
215
            touchmove: 'ontouchmove' in window ? 'touchmove' :  MSPointer.move,
216
            touchstart: 'ontouchstart' in window ? 'touchstart' :  MSPointer.down
217
        };
218

219
        //timeouts
220
        var resizeId;
221
        var afterSectionLoadsId;
222
        var afterSlideLoadsId;
223
        var scrollId;
224
        var scrollId2;
225
        var keydownId;
226
        var originals = $.extend(true, {}, options); //deep copy
227

228
        displayWarnings();
229

230
        //fixing bug in iScroll with links: https://github.com/cubiq/iscroll/issues/783
231
        iscrollOptions.click = isTouch; // see #2035
232

233
        //extending iScroll options with the user custom ones
234
        iscrollOptions = $.extend(iscrollOptions, options.scrollOverflowOptions);
235

236
        //easeInOutCubic animation included in the plugin
237
        $.extend($.easing,{ easeInOutCubic: function (x, t, b, c, d) {if ((t/=d/2) < 1) return c/2*t*t*t + b;return c/2*((t-=2)*t*t + 2) + b;}});
238

239
        /**
240
        * Sets the autoScroll option.
241
        * It changes the scroll bar visibility and the history of the site as a result.
242
        */
243
        function setAutoScrolling(value, type){
244
            //removing the transformation
245
            if(!value){
246
                silentScroll(0);
247
            }
248

249
            setVariableState('autoScrolling', value, type);
250

251
            var element = $(SECTION_ACTIVE_SEL);
252

253
            if(options.autoScrolling && !options.scrollBar){
254
                $htmlBody.css({
255
                    'overflow' : 'hidden',
256
                    'height' : '100%'
257
                });
258

259
                setRecordHistory(originals.recordHistory, 'internal');
260

261
                //for IE touch devices
262
                container.css({
263
                    '-ms-touch-action': 'none',
264
                    'touch-action': 'none'
265
                });
266

267
                if(element.length){
268
                    //moving the container up
269
                    silentScroll(element.position().top);
270
                }
271

272
            }else{
273
                $htmlBody.css({
274
                    'overflow' : 'visible',
275
                    'height' : 'initial'
276
                });
277

278
                setRecordHistory(false, 'internal');
279

280
                //for IE touch devices
281
                container.css({
282
                    '-ms-touch-action': '',
283
                    'touch-action': ''
284
                });
285

286
                //scrolling the page to the section with no animation
287
                if (element.length) {
288
                    $htmlBody.scrollTop(element.position().top);
289
                }
290
            }
291
        }
292

293
        /**
294
        * Defines wheter to record the history for each hash change in the URL.
295
        */
296
        function setRecordHistory(value, type){
297
            setVariableState('recordHistory', value, type);
298
        }
299

300
        /**
301
        * Defines the scrolling speed
302
        */
303
        function setScrollingSpeed(value, type){
304
            setVariableState('scrollingSpeed', value, type);
305
        }
306

307
        /**
308
        * Sets fitToSection
309
        */
310
        function setFitToSection(value, type){
311
            setVariableState('fitToSection', value, type);
312
        }
313

314
        /**
315
        * Sets lockAnchors
316
        */
317
        function setLockAnchors(value){
318
            options.lockAnchors = value;
319
        }
320

321
        /**
322
        * Adds or remove the possiblity of scrolling through sections by using the mouse wheel or the trackpad.
323
        */
324
        function setMouseWheelScrolling(value){
325
            if(value){
326
                addMouseWheelHandler();
327
                addMiddleWheelHandler();
328
            }else{
329
                removeMouseWheelHandler();
330
                removeMiddleWheelHandler();
331
            }
332
        }
333

334
        /**
335
        * Adds or remove the possibility of scrolling through sections by using the mouse wheel/trackpad or touch gestures.
336
        * Optionally a second parameter can be used to specify the direction for which the action will be applied.
337
        *
338
        * @param directions string containing the direction or directions separated by comma.
339
        */
340
        function setAllowScrolling(value, directions){
341
            if(typeof directions !== 'undefined'){
342
                directions = directions.replace(/ /g,'').split(',');
343

344
                $.each(directions, function (index, direction){
345
                    setIsScrollAllowed(value, direction, 'm');
346
                });
347
            }
348
            else if(value){
349
                setMouseWheelScrolling(true);
350
                addTouchHandler();
351
            }else{
352
                setMouseWheelScrolling(false);
353
                removeTouchHandler();
354
            }
355
        }
356

357
        /**
358
        * Adds or remove the possibility of scrolling through sections by using the keyboard arrow keys
359
        */
360
        function setKeyboardScrolling(value, directions){
361
            if(typeof directions !== 'undefined'){
362
                directions = directions.replace(/ /g,'').split(',');
363

364
                $.each(directions, function (index, direction){
365
                    setIsScrollAllowed(value, direction, 'k');
366
                });
367
            }else{
368
                options.keyboardScrolling = value;
369
            }
370
        }
371

372
        /**
373
        * Moves the page up one section.
374
        */
375
        function moveSectionUp(){
376
            var prev = $(SECTION_ACTIVE_SEL).prev(SECTION_SEL);
377

378
            //looping to the bottom if there's no more sections above
379
            if (!prev.length && (options.loopTop || options.continuousVertical)) {
380
                prev = $(SECTION_SEL).last();
381
            }
382

383
            if (prev.length) {
384
                scrollPage(prev, null, true);
385
            }
386
        }
387

388
        /**
389
        * Moves the page down one section.
390
        */
391
        function moveSectionDown(){
392
            var next = $(SECTION_ACTIVE_SEL).next(SECTION_SEL);
393

394
            //looping to the top if there's no more sections below
395
            if(!next.length &&
396
                (options.loopBottom || options.continuousVertical)){
397
                next = $(SECTION_SEL).first();
398
            }
399

400
            if(next.length){
401
                scrollPage(next, null, false);
402
            }
403
        }
404

405
        /**
406
        * Moves the page to the given section and slide with no animation.
407
        * Anchors or index positions can be used as params.
408
        */
409
        function silentMoveTo(sectionAnchor, slideAnchor){
410
            setScrollingSpeed (0, 'internal');
411
            moveTo(sectionAnchor, slideAnchor);
412
            setScrollingSpeed (originals.scrollingSpeed, 'internal');
413
        }
414

415
        /**
416
        * Moves the page to the given section and slide.
417
        * Anchors or index positions can be used as params.
418
        */
419
        function moveTo(sectionAnchor, slideAnchor){
420
            var destiny = getSectionByAnchor(sectionAnchor);
421

422
            if (typeof slideAnchor !== 'undefined'){
423
                scrollPageAndSlide(sectionAnchor, slideAnchor);
424
            }else if(destiny.length > 0){
425
                scrollPage(destiny);
426
            }
427
        }
428

429
        /**
430
        * Slides right the slider of the active section.
431
        * Optional `section` param.
432
        */
433
        function moveSlideRight(section){
434
            moveSlide('right', section);
435
        }
436

437
        /**
438
        * Slides left the slider of the active section.
439
        * Optional `section` param.
440
        */
441
        function moveSlideLeft(section){
442
            moveSlide('left', section);
443
        }
444

445
        /**
446
         * When resizing is finished, we adjust the slides sizes and positions
447
         */
448
        function reBuild(resizing){
449
            if(container.hasClass(DESTROYED)){ return; }  //nothing to do if the plugin was destroyed
450

451
            isResizing = true;
452

453
            windowsHeight = $window.height();  //updating global var
454

455
            $(SECTION_SEL).each(function(){
456
                var slidesWrap = $(this).find(SLIDES_WRAPPER_SEL);
457
                var slides = $(this).find(SLIDE_SEL);
458

459
                //adjusting the height of the table-cell for IE and Firefox
460
                if(options.verticalCentered){
461
                    $(this).find(TABLE_CELL_SEL).css('height', getTableHeight($(this)) + 'px');
462
                }
463

464
                $(this).css('height', windowsHeight + 'px');
465

466
                //resizing the scrolling divs
467
                if(options.scrollOverflow){
468
                    if(slides.length){
469
                        slides.each(function(){
470
                            createScrollBar($(this));
471
                        });
472
                    }else{
473
                        createScrollBar($(this));
474
                    }
475
                }
476

477
                //adjusting the position fo the FULL WIDTH slides...
478
                if (slides.length > 1) {
479
                    landscapeScroll(slidesWrap, slidesWrap.find(SLIDE_ACTIVE_SEL));
480
                }
481
            });
482

483
            var activeSection = $(SECTION_ACTIVE_SEL);
484
            var sectionIndex = activeSection.index(SECTION_SEL);
485

486
            //isn't it the first section?
487
            if(sectionIndex){
488
                //adjusting the position for the current section
489
                silentMoveTo(sectionIndex + 1);
490
            }
491

492
            isResizing = false;
493
            $.isFunction( options.afterResize ) && resizing && options.afterResize.call(container);
494
            $.isFunction( options.afterReBuild ) && !resizing && options.afterReBuild.call(container);
495
        }
496

497
        /**
498
        * Turns fullPage.js to normal scrolling mode when the viewport `width` or `height`
499
        * are smaller than the set limit values.
500
        */
501
        function setResponsive(active){
502
            var isResponsive = $body.hasClass(RESPONSIVE);
503

504
            if(active){
505
                if(!isResponsive){
506
                    setAutoScrolling(false, 'internal');
507
                    setFitToSection(false, 'internal');
508
                    $(SECTION_NAV_SEL).hide();
509
                    $body.addClass(RESPONSIVE);
510
                    $.isFunction( options.afterResponsive ) && options.afterResponsive.call( container, active);
511
                }
512
            }
513
            else if(isResponsive){
514
                setAutoScrolling(originals.autoScrolling, 'internal');
515
                setFitToSection(originals.autoScrolling, 'internal');
516
                $(SECTION_NAV_SEL).show();
517
                $body.removeClass(RESPONSIVE);
518
                $.isFunction( options.afterResponsive ) && options.afterResponsive.call( container, active);
519
            }
520
        }
521

522
        if($(this).length){
523
            //public functions
524
            FP.setAutoScrolling = setAutoScrolling;
525
            FP.setRecordHistory = setRecordHistory;
526
            FP.setScrollingSpeed = setScrollingSpeed;
527
            FP.setFitToSection = setFitToSection;
528
            FP.setLockAnchors = setLockAnchors;
529
            FP.setMouseWheelScrolling = setMouseWheelScrolling;
530
            FP.setAllowScrolling = setAllowScrolling;
531
            FP.setKeyboardScrolling = setKeyboardScrolling;
532
            FP.moveSectionUp = moveSectionUp;
533
            FP.moveSectionDown = moveSectionDown;
534
            FP.silentMoveTo = silentMoveTo;
535
            FP.moveTo = moveTo;
536
            FP.moveSlideRight = moveSlideRight;
537
            FP.moveSlideLeft = moveSlideLeft;
538
            FP.fitToSection = fitToSection;
539
            FP.reBuild = reBuild;
540
            FP.setResponsive = setResponsive;
541
            FP.destroy = destroy;
542

543
            init();
544

545
            bindEvents();
546
        }
547

548
        function init(){
549
            //if css3 is not supported, it will use jQuery animations
550
            if(options.css3){
551
                options.css3 = support3d();
552
            }
553

554
            options.scrollBar = options.scrollBar || options.hybrid;
555

556
            setOptionsFromDOM();
557
            prepareDom();
558
            setAllowScrolling(true);
559
            setAutoScrolling(options.autoScrolling, 'internal');
560
            responsive();
561

562
            //setting the class for the body element
563
            setBodyClass();
564

565
            if(document.readyState === 'complete'){
566
                scrollToAnchor();
567
            }
568
            $window.on('load', scrollToAnchor);
569
        }
570

571
        function bindEvents(){
572
            $window
573
                //when scrolling...
574
                .on('scroll', scrollHandler)
575

576
                //detecting any change on the URL to scroll to the given anchor link
577
                //(a way to detect back history button as we play with the hashes on the URL)
578
                .on('hashchange', hashChangeHandler)
579

580
                //when opening a new tab (ctrl + t), `control` won't be pressed when coming back.
581
                .blur(blurHandler)
582

583
                //when resizing the site, we adjust the heights of the sections, slimScroll...
584
                .resize(resizeHandler);
585

586
            $document
587
                //Sliding with arrow keys, both, vertical and horizontal
588
                .keydown(keydownHandler)
589

590
                //to prevent scrolling while zooming
591
                .keyup(keyUpHandler)
592

593
                //Scrolls to the section when clicking the navigation bullet
594
                .on('click touchstart', SECTION_NAV_SEL + ' a', sectionBulletHandler)
595

596
                //Scrolls the slider to the given slide destination for the given section
597
                .on('click touchstart', SLIDES_NAV_LINK_SEL, slideBulletHandler)
598

599
                .on('click', SECTION_NAV_TOOLTIP_SEL, tooltipTextHandler);
600

601
            //Scrolling horizontally when clicking on the slider controls.
602
            $(SECTION_SEL).on('click touchstart', SLIDES_ARROW_SEL, slideArrowHandler);
603

604
            /**
605
            * Applying normalScroll elements.
606
            * Ignoring the scrolls over the specified selectors.
607
            */
608
            if(options.normalScrollElements){
609
                $document.on('mouseenter', options.normalScrollElements, function () {
610
                    setMouseWheelScrolling(false);
611
                });
612

613
                $document.on('mouseleave', options.normalScrollElements, function(){
614
                    setMouseWheelScrolling(true);
615
                });
616
            }
617
        }
618

619
        /**
620
        * Setting options from DOM elements if they are not provided.
621
        */
622
        function setOptionsFromDOM(){
623
            var sections = container.find(options.sectionSelector);
624

625
            //no anchors option? Checking for them in the DOM attributes
626
            if(!options.anchors.length){
627
                options.anchors = sections.filter('[data-anchor]').map(function(){
628
                    return $(this).data('anchor').toString();
629
                }).get();
630
            }
631

632
            //no tooltips option? Checking for them in the DOM attributes
633
            if(!options.navigationTooltips.length){
634
                options.navigationTooltips = sections.filter('[data-tooltip]').map(function(){
635
                    return $(this).data('tooltip').toString();
636
                }).get();
637
            }
638
        }
639

640
        /**
641
        * Works over the DOM structure to set it up for the current fullpage options.
642
        */
643
        function prepareDom(){
644
            container.css({
645
                'height': '100%',
646
                'position': 'relative'
647
            });
648

649
            //adding a class to recognize the container internally in the code
650
            container.addClass(WRAPPER);
651
            $('html').addClass(ENABLED);
652

653
            //due to https://github.com/alvarotrigo/fullPage.js/issues/1502
654
            windowsHeight = $window.height();
655

656
            container.removeClass(DESTROYED); //in case it was destroyed before initializing it again
657

658
            addInternalSelectors();
659

660
             //styling the sections / slides / menu
661
            $(SECTION_SEL).each(function(index){
662
                var section = $(this);
663
                var slides = section.find(SLIDE_SEL);
664
                var numSlides = slides.length;
665

666
                styleSection(section, index);
667
                styleMenu(section, index);
668

669
                // if there's any slide
670
                if (numSlides > 0) {
671
                    styleSlides(section, slides, numSlides);
672
                }else{
673
                    if(options.verticalCentered){
674
                        addTableClass(section);
675
                    }
676
                }
677
            });
678

679
            //fixed elements need to be moved out of the plugin container due to problems with CSS3.
680
            if(options.fixedElements && options.css3){
681
                $(options.fixedElements).appendTo($body);
682
            }
683

684
            //vertical centered of the navigation + active bullet
685
            if(options.navigation){
686
                addVerticalNavigation();
687
            }
688

689
            enableYoutubeAPI();
690

691
            if(options.scrollOverflow){
692
                if(document.readyState === 'complete'){
693
                    createScrollBarHandler();
694
                }
695
                //after DOM and images are loaded
696
                $window.on('load', createScrollBarHandler);
697
            }else{
698
                afterRenderActions();
699
            }
700
        }
701

702
        /**
703
        * Styles the horizontal slides for a section.
704
        */
705
        function styleSlides(section, slides, numSlides){
706
            var sliderWidth = numSlides * 100;
707
            var slideWidth = 100 / numSlides;
708

709
            slides.wrapAll('<div class="' + SLIDES_CONTAINER + '" />');
710
            slides.parent().wrap('<div class="' + SLIDES_WRAPPER + '" />');
711

712
            section.find(SLIDES_CONTAINER_SEL).css('width', sliderWidth + '%');
713

714
            if(numSlides > 1){
715
                if(options.controlArrows){
716
                    createSlideArrows(section);
717
                }
718

719
                if(options.slidesNavigation){
720
                    addSlidesNavigation(section, numSlides);
721
                }
722
            }
723

724
            slides.each(function(index) {
725
                $(this).css('width', slideWidth + '%');
726

727
                if(options.verticalCentered){
728
                    addTableClass($(this));
729
                }
730
            });
731

732
            var startingSlide = section.find(SLIDE_ACTIVE_SEL);
733

734
            //if the slide won't be an starting point, the default will be the first one
735
            //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.
736
            if( startingSlide.length &&  ($(SECTION_ACTIVE_SEL).index(SECTION_SEL) !== 0 || ($(SECTION_ACTIVE_SEL).index(SECTION_SEL) === 0 && startingSlide.index() !== 0))){
737
                silentLandscapeScroll(startingSlide, 'internal');
738
            }else{
739
                slides.eq(0).addClass(ACTIVE);
740
            }
741
        }
742

743
        /**
744
        * Styling vertical sections
745
        */
746
        function styleSection(section, index){
747
            //if no active section is defined, the 1st one will be the default one
748
            if(!index && $(SECTION_ACTIVE_SEL).length === 0) {
749
                section.addClass(ACTIVE);
750
            }
751
            startingSection = $(SECTION_ACTIVE_SEL);
752

753
            section.css('height', windowsHeight + 'px');
754

755
            if(options.paddingTop){
756
                section.css('padding-top', options.paddingTop);
757
            }
758

759
            if(options.paddingBottom){
760
                section.css('padding-bottom', options.paddingBottom);
761
            }
762

763
            if (typeof options.sectionsColor[index] !==  'undefined') {
764
                section.css('background-color', options.sectionsColor[index]);
765
            }
766

767
            if (typeof options.anchors[index] !== 'undefined') {
768
                section.attr('data-anchor', options.anchors[index]);
769
            }
770
        }
771

772
        /**
773
        * Sets the data-anchor attributes to the menu elements and activates the current one.
774
        */
775
        function styleMenu(section, index){
776
            if (typeof options.anchors[index] !== 'undefined') {
777
                //activating the menu / nav element on load
778
                if(section.hasClass(ACTIVE)){
779
                    activateMenuAndNav(options.anchors[index], index);
780
                }
781
            }
782

783
            //moving the menu outside the main container if it is inside (avoid problems with fixed positions when using CSS3 tranforms)
784
            if(options.menu && options.css3 && $(options.menu).closest(WRAPPER_SEL).length){
785
                $(options.menu).appendTo($body);
786
            }
787
        }
788

789
        /**
790
        * Adds internal classes to be able to provide customizable selectors
791
        * keeping the link with the style sheet.
792
        */
793
        function addInternalSelectors(){
794
            container.find(options.sectionSelector).addClass(SECTION);
795
            container.find(options.slideSelector).addClass(SLIDE);
796
        }
797

798
        /**
799
        * Creates the control arrows for the given section
800
        */
801
        function createSlideArrows(section){
802
            section.find(SLIDES_WRAPPER_SEL).after('<div class="' + SLIDES_ARROW_PREV + '"></div><div class="' + SLIDES_ARROW_NEXT + '"></div>');
803

804
            if(options.controlArrowColor!='#fff'){
805
                section.find(SLIDES_ARROW_NEXT_SEL).css('border-color', 'transparent transparent transparent '+options.controlArrowColor);
806
                section.find(SLIDES_ARROW_PREV_SEL).css('border-color', 'transparent '+ options.controlArrowColor + ' transparent transparent');
807
            }
808

809
            if(!options.loopHorizontal){
810
                section.find(SLIDES_ARROW_PREV_SEL).hide();
811
            }
812
        }
813

814
        /**
815
        * Creates a vertical navigation bar.
816
        */
817
        function addVerticalNavigation(){
818
            $body.append('<div id="' + SECTION_NAV + '"><ul></ul></div>');
819
            var nav = $(SECTION_NAV_SEL);
820

821
            nav.addClass(function() {
822
                return options.showActiveTooltip ? SHOW_ACTIVE_TOOLTIP + ' ' + options.navigationPosition : options.navigationPosition;
823
            });
824

825
            for (var i = 0; i < $(SECTION_SEL).length; i++) {
826
                var link = '';
827
                if (options.anchors.length) {
828
                    link = options.anchors[i];
829
                }
830

831
                var li = '<li><a href="#' + link + '"><span></span></a>';
832

833
                // Only add tooltip if needed (defined by user)
834
                var tooltip = options.navigationTooltips[i];
835

836
                if (typeof tooltip !== 'undefined' && tooltip !== '') {
837
                    li += '<div class="' + SECTION_NAV_TOOLTIP + ' ' + options.navigationPosition + '">' + tooltip + '</div>';
838
                }
839

840
                li += '</li>';
841

842
                nav.find('ul').append(li);
843
            }
844

845
            //centering it vertically
846
            $(SECTION_NAV_SEL).css('margin-top', '-' + ($(SECTION_NAV_SEL).height()/2) + 'px');
847

848
            //activating the current active section
849
            $(SECTION_NAV_SEL).find('li').eq($(SECTION_ACTIVE_SEL).index(SECTION_SEL)).find('a').addClass(ACTIVE);
850
        }
851

852
        /**
853
        * Creates the slim scroll scrollbar for the sections and slides inside them.
854
        */
855
        function createScrollBarHandler(){
856
            $(SECTION_SEL).each(function(){
857
                var slides = $(this).find(SLIDE_SEL);
858

859
                if(slides.length){
860
                    slides.each(function(){
861
                        createScrollBar($(this));
862
                    });
863
                }else{
864
                    createScrollBar($(this));
865
                }
866

867
            });
868
            afterRenderActions();
869
        }
870

871
        /*
872
        * Enables the Youtube videos API so we can control their flow if necessary.
873
        */
874
        function enableYoutubeAPI(){
875
            container.find('iframe[src*="youtube.com/embed/"]').each(function(){
876
                addURLParam($(this), 'enablejsapi=1');
877
            });
878
        }
879

880
        /**
881
        * Adds a new parameter and its value to the `src` of a given element
882
        */
883
        function addURLParam(element, newParam){
884
            var originalSrc = element.attr('src');
885
            element.attr('src', originalSrc + getUrlParamSign(originalSrc) + newParam);
886
        }
887

888
        /*
889
        * Returns the prefix sign to use for a new parameter in an existen URL.
890
        *
891
        * @return {String}  ? | &
892
        */
893
        function getUrlParamSign(url){
894
            return ( !/\?/.test( url ) ) ? '?' : '&';
895
        }
896

897
        /**
898
        * Actions and callbacks to fire afterRender
899
        */
900
        function afterRenderActions(){
901
            var section = $(SECTION_ACTIVE_SEL);
902

903
            section.addClass(COMPLETELY);
904

905
            if(options.scrollOverflowHandler.afterRender){
906
                options.scrollOverflowHandler.afterRender(section);
907
            }
908
            lazyLoad(section);
909
            playMedia(section);
910
            options.scrollOverflowHandler.afterLoad();
911
            
912
            if(isDestinyTheStartingSection()){
913
                $.isFunction( options.afterLoad ) && options.afterLoad.call(section, section.data('anchor'), (section.index(SECTION_SEL) + 1));
914
            }
915

916
            $.isFunction( options.afterRender ) && options.afterRender.call(container);
917
        }
918

919
        /**
920
        * Determines if the URL anchor destiny is the starting section (the one using 'active' class before initialization)
921
        */
922
        function isDestinyTheStartingSection(){
923
            var anchors =  window.location.hash.replace('#', '').split('/');
924
            var destinationSection = getSectionByAnchor(decodeURIComponent(anchors[0]));
925
    
926
            return !destinationSection.length || destinationSection.length && destinationSection.index() === startingSection.index();
927
        }
928

929

930
        var isScrolling = false;
931
        var lastScroll = 0;
932

933
        //when scrolling...
934
        function scrollHandler(){
935
            var currentSection;
936

937
            if(!options.autoScrolling || options.scrollBar){
938
                var currentScroll = $window.scrollTop();
939
                var scrollDirection = getScrollDirection(currentScroll);
940
                var visibleSectionIndex = 0;
941
                var screen_mid = currentScroll + ($window.height() / 2.0);
942
                var isAtBottom = $body.height() - $window.height() === currentScroll;
943
                var sections =  document.querySelectorAll(SECTION_SEL);
944

945
                //when using `auto-height` for a small last section it won't be centered in the viewport
946
                if(isAtBottom){
947
                    visibleSectionIndex = sections.length - 1;
948
                }
949
                //is at top? when using `auto-height` for a small first section it won't be centered in the viewport
950
                else if(!currentScroll){
951
                    visibleSectionIndex = 0;
952
                }
953

954
                //taking the section which is showing more content in the viewport
955
                else{
956
                    for (var i = 0; i < sections.length; ++i) {
957
                        var section = sections[i];
958

959
                        // Pick the the last section which passes the middle line of the screen.
960
                        if (section.offsetTop <= screen_mid)
961
                        {
962
                            visibleSectionIndex = i;
963
                        }
964
                    }
965
                }
966

967
                if(isCompletelyInViewPort(scrollDirection)){
968
                    if(!$(SECTION_ACTIVE_SEL).hasClass(COMPLETELY)){
969
                        $(SECTION_ACTIVE_SEL).addClass(COMPLETELY).siblings().removeClass(COMPLETELY);
970
                    }
971
                }
972

973
                //geting the last one, the current one on the screen
974
                currentSection = $(sections).eq(visibleSectionIndex);
975

976
                //setting the visible section as active when manually scrolling
977
                //executing only once the first time we reach the section
978
                if(!currentSection.hasClass(ACTIVE)){
979
                    isScrolling = true;
980
                    var leavingSection = $(SECTION_ACTIVE_SEL);
981
                    var leavingSectionIndex = leavingSection.index(SECTION_SEL) + 1;
982
                    var yMovement = getYmovement(currentSection);
983
                    var anchorLink  = currentSection.data('anchor');
984
                    var sectionIndex = currentSection.index(SECTION_SEL) + 1;
985
                    var activeSlide = currentSection.find(SLIDE_ACTIVE_SEL);
986
                    var slideIndex;
987
                    var slideAnchorLink;
988

989
                    if(activeSlide.length){
990
                        slideAnchorLink = activeSlide.data('anchor');
991
                        slideIndex = activeSlide.index();
992
                    }
993

994
                    if(canScroll){
995
                        currentSection.addClass(ACTIVE).siblings().removeClass(ACTIVE);
996

997
                        $.isFunction( options.onLeave ) && options.onLeave.call( leavingSection, leavingSectionIndex, sectionIndex, yMovement);
998
                        $.isFunction( options.afterLoad ) && options.afterLoad.call( currentSection, anchorLink, sectionIndex);
999

1000
                        stopMedia(leavingSection);
1001
                        lazyLoad(currentSection);
1002
                        playMedia(currentSection);
1003

1004
                        activateMenuAndNav(anchorLink, sectionIndex - 1);
1005

1006
                        if(options.anchors.length){
1007
                            //needed to enter in hashChange event when using the menu with anchor links
1008
                            lastScrolledDestiny = anchorLink;
1009
                        }
1010
                        setState(slideIndex, slideAnchorLink, anchorLink, sectionIndex);
1011
                    }
1012

1013
                    //small timeout in order to avoid entering in hashChange event when scrolling is not finished yet
1014
                    clearTimeout(scrollId);
1015
                    scrollId = setTimeout(function(){
1016
                        isScrolling = false;
1017
                    }, 100);
1018
                }
1019

1020
                if(options.fitToSection){
1021
                    //for the auto adjust of the viewport to fit a whole section
1022
                    clearTimeout(scrollId2);
1023

1024
                    scrollId2 = setTimeout(function(){
1025
                        //checking it again in case it changed during the delay
1026
                        if(options.fitToSection){
1027
                            fitToSection();
1028
                        }
1029
                    }, options.fitToSectionDelay);
1030
                }
1031
            }
1032
        }
1033

1034
        /**
1035
        * Fits the site to the nearest active section
1036
        */
1037
        function fitToSection(){
1038
            //checking fitToSection again in case it was set to false before the timeout delay
1039
            if(canScroll){
1040
                //allows to scroll to an active section and
1041
                //if the section is already active, we prevent firing callbacks
1042
                isResizing = true;
1043

1044
                scrollPage($(SECTION_ACTIVE_SEL));
1045
                isResizing = false;
1046
            }
1047
        }
1048

1049
        /**
1050
        * Determines whether the active section has seen in its whole or not.
1051
        */
1052
        function isCompletelyInViewPort(movement){
1053
            var top = $(SECTION_ACTIVE_SEL).position().top;
1054
            var bottom = top + $window.height();
1055

1056
            if(movement == 'up'){
1057
                return bottom >= ($window.scrollTop() + $window.height());
1058
            }
1059
            return top <= $window.scrollTop();
1060
        }
1061

1062
        /**
1063
        * Gets the directon of the the scrolling fired by the scroll event.
1064
        */
1065
        function getScrollDirection(currentScroll){
1066
            var direction = currentScroll > lastScroll ? 'down' : 'up';
1067

1068
            lastScroll = currentScroll;
1069

1070
            //needed for auto-height sections to determine if we want to scroll to the top or bottom of the destination
1071
            previousDestTop = currentScroll;
1072

1073
            return direction;
1074
        }
1075

1076
        /**
1077
        * Determines the way of scrolling up or down:
1078
        * by 'automatically' scrolling a section or by using the default and normal scrolling.
1079
        */
1080
        function scrolling(type, scrollable){
1081
            if (!isScrollAllowed.m[type]){
1082
                return;
1083
            }
1084
            var check = (type === 'down') ? 'bottom' : 'top';
1085
            var scrollSection = (type === 'down') ? moveSectionDown : moveSectionUp;
1086

1087
            if(scrollable.length > 0 ){
1088
                //is the scrollbar at the start/end of the scroll?
1089
                if(options.scrollOverflowHandler.isScrolled(check, scrollable)){
1090
                    scrollSection();
1091
                }else{
1092
                    return true;
1093
                }
1094
            }else{
1095
                // moved up/down
1096
                scrollSection();
1097
            }
1098
        }
1099

1100
        /*
1101
        * Preventing bouncing in iOS #2285
1102
        */
1103
        function preventBouncing(event){
1104
            var e = event.originalEvent;
1105
            if(!checkParentForNormalScrollElement(event.target) && options.autoScrolling && isReallyTouch(e)){
1106
                //preventing the easing on iOS devices
1107
                event.preventDefault();
1108
            }
1109
        }
1110

1111
        var touchStartY = 0;
1112
        var touchStartX = 0;
1113
        var touchEndY = 0;
1114
        var touchEndX = 0;
1115

1116
        /* Detecting touch events
1117

1118
        * As we are changing the top property of the page on scrolling, we can not use the traditional way to detect it.
1119
        * This way, the touchstart and the touch moves shows an small difference between them which is the
1120
        * used one to determine the direction.
1121
        */
1122
        function touchMoveHandler(event){
1123
            var e = event.originalEvent;
1124
            var activeSection = $(e.target).closest(SECTION_SEL);
1125

1126
            // additional: if one of the normalScrollElements isn't within options.normalScrollElementTouchThreshold hops up the DOM chain
1127
            if (!checkParentForNormalScrollElement(event.target) && isReallyTouch(e) ) {
1128

1129
                if(options.autoScrolling){
1130
                    //preventing the easing on iOS devices
1131
                    event.preventDefault();
1132
                }
1133

1134
                var scrollable = options.scrollOverflowHandler.scrollable(activeSection);
1135
                var touchEvents = getEventsPage(e);
1136

1137
                touchEndY = touchEvents.y;
1138
                touchEndX = touchEvents.x;
1139

1140
                //if movement in the X axys is greater than in the Y and the currect section has slides...
1141
                if (activeSection.find(SLIDES_WRAPPER_SEL).length && Math.abs(touchStartX - touchEndX) > (Math.abs(touchStartY - touchEndY))) {
1142

1143
                    //is the movement greater than the minimum resistance to scroll?
1144
                    if (!slideMoving && Math.abs(touchStartX - touchEndX) > ($window.outerWidth() / 100 * options.touchSensitivity)) {
1145
                        if (touchStartX > touchEndX) {
1146
                            if(isScrollAllowed.m.right){
1147
                                moveSlideRight(activeSection); //next
1148
                            }
1149
                        } else {
1150
                            if(isScrollAllowed.m.left){
1151
                                moveSlideLeft(activeSection); //prev
1152
                            }
1153
                        }
1154
                    }
1155
                }
1156

1157
                //vertical scrolling (only when autoScrolling is enabled)
1158
                else if(options.autoScrolling && canScroll){
1159

1160
                    //is the movement greater than the minimum resistance to scroll?
1161
                    if (Math.abs(touchStartY - touchEndY) > ($window.height() / 100 * options.touchSensitivity)) {
1162
                        if (touchStartY > touchEndY) {
1163
                            scrolling('down', scrollable);
1164
                        } else if (touchEndY > touchStartY) {
1165
                            scrolling('up', scrollable);
1166
                        }
1167
                    }
1168
                }
1169
            }
1170
        }
1171

1172
        /**
1173
         * recursive function to loop up the parent nodes to check if one of them exists in options.normalScrollElements
1174
         * Currently works well for iOS - Android might need some testing
1175
         * @param  {Element} el  target element / jquery selector (in subsequent nodes)
1176
         * @param  {int}     hop current hop compared to options.normalScrollElementTouchThreshold
1177
         * @return {boolean} true if there is a match to options.normalScrollElements
1178
         */
1179
        function checkParentForNormalScrollElement (el, hop) {
1180
            hop = hop || 0;
1181
            var parent = $(el).parent();
1182

1183
            if (hop < options.normalScrollElementTouchThreshold &&
1184
                parent.is(options.normalScrollElements) ) {
1185
                return true;
1186
            } else if (hop == options.normalScrollElementTouchThreshold) {
1187
                return false;
1188
            } else {
1189
                return checkParentForNormalScrollElement(parent, ++hop);
1190
            }
1191
        }
1192

1193
        /**
1194
        * As IE >= 10 fires both touch and mouse events when using a mouse in a touchscreen
1195
        * this way we make sure that is really a touch event what IE is detecting.
1196
        */
1197
        function isReallyTouch(e){
1198
            //if is not IE   ||  IE is detecting `touch` or `pen`
1199
            return typeof e.pointerType === 'undefined' || e.pointerType != 'mouse';
1200
        }
1201

1202
        /**
1203
        * Handler for the touch start event.
1204
        */
1205
        function touchStartHandler(event){
1206
            var e = event.originalEvent;
1207

1208
            //stopping the auto scroll to adjust to a section
1209
            if(options.fitToSection){
1210
                $htmlBody.stop();
1211
            }
1212

1213
            if(isReallyTouch(e)){
1214
                var touchEvents = getEventsPage(e);
1215
                touchStartY = touchEvents.y;
1216
                touchStartX = touchEvents.x;
1217
            }
1218
        }
1219

1220
        /**
1221
        * Gets the average of the last `number` elements of the given array.
1222
        */
1223
        function getAverage(elements, number){
1224
            var sum = 0;
1225

1226
            //taking `number` elements from the end to make the average, if there are not enought, 1
1227
            var lastElements = elements.slice(Math.max(elements.length - number, 1));
1228

1229
            for(var i = 0; i < lastElements.length; i++){
1230
                sum = sum + lastElements[i];
1231
            }
1232

1233
            return Math.ceil(sum/number);
1234
        }
1235

1236
        /**
1237
         * Detecting mousewheel scrolling
1238
         *
1239
         * http://blogs.sitepointstatic.com/examples/tech/mouse-wheel/index.html
1240
         * http://www.sitepoint.com/html5-javascript-mouse-wheel/
1241
         */
1242
        var prevTime = new Date().getTime();
1243

1244
        function MouseWheelHandler(e) {
1245
            var curTime = new Date().getTime();
1246
            var isNormalScroll = $(COMPLETELY_SEL).hasClass(NORMAL_SCROLL);
1247

1248
            //autoscrolling and not zooming?
1249
            if(options.autoScrolling && !controlPressed && !isNormalScroll){
1250
                // cross-browser wheel delta
1251
                e = e || window.event;
1252
                var value = e.wheelDelta || -e.deltaY || -e.detail;
1253
                var delta = Math.max(-1, Math.min(1, value));
1254

1255
                var horizontalDetection = typeof e.wheelDeltaX !== 'undefined' || typeof e.deltaX !== 'undefined';
1256
                var isScrollingVertically = (Math.abs(e.wheelDeltaX) < Math.abs(e.wheelDelta)) || (Math.abs(e.deltaX ) < Math.abs(e.deltaY) || !horizontalDetection);
1257

1258
                //Limiting the array to 150 (lets not waste memory!)
1259
                if(scrollings.length > 149){
1260
                    scrollings.shift();
1261
                }
1262

1263
                //keeping record of the previous scrollings
1264
                scrollings.push(Math.abs(value));
1265

1266
                //preventing to scroll the site on mouse wheel when scrollbar is present
1267
                if(options.scrollBar){
1268
                    e.preventDefault ? e.preventDefault() : e.returnValue = false;
1269
                }
1270

1271
                var activeSection = $(SECTION_ACTIVE_SEL);
1272
                var scrollable = options.scrollOverflowHandler.scrollable(activeSection);
1273

1274
                //time difference between the last scroll and the current one
1275
                var timeDiff = curTime-prevTime;
1276
                prevTime = curTime;
1277

1278
                //haven't they scrolled in a while?
1279
                //(enough to be consider a different scrolling action to scroll another section)
1280
                if(timeDiff > 200){
1281
                    //emptying the array, we dont care about old scrollings for our averages
1282
                    scrollings = [];
1283
                }
1284

1285
                if(canScroll){
1286
                    var averageEnd = getAverage(scrollings, 10);
1287
                    var averageMiddle = getAverage(scrollings, 70);
1288
                    var isAccelerating = averageEnd >= averageMiddle;
1289

1290
                    //to avoid double swipes...
1291
                    if(isAccelerating && isScrollingVertically){
1292
                        //scrolling down?
1293
                        if (delta < 0) {
1294
                            scrolling('down', scrollable);
1295

1296
                        //scrolling up?
1297
                        }else {
1298
                            scrolling('up', scrollable);
1299
                        }
1300
                    }
1301
                }
1302

1303
                return false;
1304
            }
1305

1306
            if(options.fitToSection){
1307
                //stopping the auto scroll to adjust to a section
1308
                $htmlBody.stop();
1309
            }
1310
        }
1311

1312
        /**
1313
        * Slides a slider to the given direction.
1314
        * Optional `section` param.
1315
        */
1316
        function moveSlide(direction, section){
1317
            var activeSection = typeof section === 'undefined' ? $(SECTION_ACTIVE_SEL) : section;
1318
            var slides = activeSection.find(SLIDES_WRAPPER_SEL);
1319
            var numSlides = slides.find(SLIDE_SEL).length;
1320

1321
            // more than one slide needed and nothing should be sliding
1322
            if (!slides.length || slideMoving || numSlides < 2) {
1323
                return;
1324
            }
1325

1326
            var currentSlide = slides.find(SLIDE_ACTIVE_SEL);
1327
            var destiny = null;
1328

1329
            if(direction === 'left'){
1330
                destiny = currentSlide.prev(SLIDE_SEL);
1331
            }else{
1332
                destiny = currentSlide.next(SLIDE_SEL);
1333
            }
1334

1335
            //isn't there a next slide in the secuence?
1336
            if(!destiny.length){
1337
                //respect loopHorizontal settin
1338
                if (!options.loopHorizontal) return;
1339

1340
                if(direction === 'left'){
1341
                    destiny = currentSlide.siblings(':last');
1342
                }else{
1343
                    destiny = currentSlide.siblings(':first');
1344
                }
1345
            }
1346

1347
            slideMoving = true;
1348

1349
            landscapeScroll(slides, destiny, direction);
1350
        }
1351

1352
        /**
1353
        * Maintains the active slides in the viewport
1354
        * (Because the `scroll` animation might get lost with some actions, such as when using continuousVertical)
1355
        */
1356
        function keepSlidesPosition(){
1357
            $(SLIDE_ACTIVE_SEL).each(function(){
1358
                silentLandscapeScroll($(this), 'internal');
1359
            });
1360
        }
1361

1362
        var previousDestTop = 0;
1363
        /**
1364
        * Returns the destination Y position based on the scrolling direction and
1365
        * the height of the section.
1366
        */
1367
        function getDestinationPosition(element){
1368
            var elemPosition = element.position();
1369

1370
            //top of the desination will be at the top of the viewport
1371
            var position = elemPosition.top;
1372
            var isScrollingDown =  elemPosition.top > previousDestTop;
1373
            var sectionBottom = position - windowsHeight + element.outerHeight();
1374
            var bigSectionsDestination = options.bigSectionsDestination;
1375

1376
            //is the destination element bigger than the viewport?
1377
            if(element.outerHeight() > windowsHeight){
1378
                //scrolling up?
1379
                if(!isScrollingDown && !bigSectionsDestination || bigSectionsDestination === 'bottom' ){
1380
                    position = sectionBottom;
1381
                }
1382
            }
1383

1384
            //sections equal or smaller than the viewport height && scrolling down? ||  is resizing and its in the last section
1385
            else if(isScrollingDown || (isResizing && element.is(':last-child')) ){
1386
                //The bottom of the destination will be at the bottom of the viewport
1387
                position = sectionBottom;
1388
            }
1389

1390
            /*
1391
            Keeping record of the last scrolled position to determine the scrolling direction.
1392
            No conventional methods can be used as the scroll bar might not be present
1393
            AND the section might not be active if it is auto-height and didnt reach the middle
1394
            of the viewport.
1395
            */
1396
            previousDestTop = position;
1397
            return position;
1398
        }
1399

1400
        /**
1401
        * Scrolls the site to the given element and scrolls to the slide if a callback is given.
1402
        */
1403
        function scrollPage(element, callback, isMovementUp){
1404
            if(typeof element === 'undefined'){ return; } //there's no element to scroll, leaving the function
1405

1406
            var dtop = getDestinationPosition(element);
1407
            var slideAnchorLink;
1408
            var slideIndex;
1409

1410
            //local variables
1411
            var v = {
1412
                element: element,
1413
                callback: callback,
1414
                isMovementUp: isMovementUp,
1415
                dtop: dtop,
1416
                yMovement: getYmovement(element),
1417
                anchorLink: element.data('anchor'),
1418
                sectionIndex: element.index(SECTION_SEL),
1419
                activeSlide: element.find(SLIDE_ACTIVE_SEL),
1420
                activeSection: $(SECTION_ACTIVE_SEL),
1421
                leavingSection: $(SECTION_ACTIVE_SEL).index(SECTION_SEL) + 1,
1422

1423
                //caching the value of isResizing at the momment the function is called
1424
                //because it will be checked later inside a setTimeout and the value might change
1425
                localIsResizing: isResizing
1426
            };
1427

1428
            //quiting when destination scroll is the same as the current one
1429
            if((v.activeSection.is(element) && !isResizing) || (options.scrollBar && $window.scrollTop() === v.dtop && !element.hasClass(AUTO_HEIGHT) )){ return; }
1430

1431
            if(v.activeSlide.length){
1432
                slideAnchorLink = v.activeSlide.data('anchor');
1433
                slideIndex = v.activeSlide.index();
1434
            }
1435

1436
            // If continuousVertical && we need to wrap around
1437
            if (options.autoScrolling && options.continuousVertical && typeof (v.isMovementUp) !== "undefined" &&
1438
                ((!v.isMovementUp && v.yMovement == 'up') || // Intending to scroll down but about to go up or
1439
                (v.isMovementUp && v.yMovement == 'down'))) { // intending to scroll up but about to go down
1440

1441
                v = createInfiniteSections(v);
1442
            }
1443

1444
            //callback (onLeave) if the site is not just resizing and readjusting the slides
1445
            if($.isFunction(options.onLeave) && !v.localIsResizing){
1446
                if(options.onLeave.call(v.activeSection, v.leavingSection, (v.sectionIndex + 1), v.yMovement) === false){
1447
                    return;
1448
                }
1449
            }
1450

1451
            //pausing media of the leaving section (if we are not just resizing, as destinatino will be the same one)
1452
            if(!v.localIsResizing){
1453
                stopMedia(v.activeSection);
1454
            }
1455

1456
            options.scrollOverflowHandler.beforeLeave();
1457
            element.addClass(ACTIVE).siblings().removeClass(ACTIVE);
1458
            lazyLoad(element);
1459
            options.scrollOverflowHandler.onLeave();
1460

1461

1462
            //preventing from activating the MouseWheelHandler event
1463
            //more than once if the page is scrolling
1464
            canScroll = false;
1465

1466
            setState(slideIndex, slideAnchorLink, v.anchorLink, v.sectionIndex);
1467

1468
            performMovement(v);
1469

1470
            //flag to avoid callingn `scrollPage()` twice in case of using anchor links
1471
            lastScrolledDestiny = v.anchorLink;
1472

1473
            //avoid firing it twice (as it does also on scroll)
1474
            activateMenuAndNav(v.anchorLink, v.sectionIndex);
1475
        }
1476

1477
        /**
1478
        * Performs the vertical movement (by CSS3 or by jQuery)
1479
        */
1480
        function performMovement(v){
1481
            // using CSS3 translate functionality
1482
            if (options.css3 && options.autoScrolling && !options.scrollBar) {
1483

1484
                // The first section can have a negative value in iOS 10. Not quite sure why: -0.0142822265625
1485
                // that's why we round it to 0.
1486
                var translate3d = 'translate3d(0px, -' + Math.round(v.dtop) + 'px, 0px)';
1487
                transformContainer(translate3d, true);
1488

1489
                //even when the scrollingSpeed is 0 there's a little delay, which might cause the
1490
                //scrollingSpeed to change in case of using silentMoveTo();
1491
                if(options.scrollingSpeed){
1492
                    clearTimeout(afterSectionLoadsId);
1493
                    afterSectionLoadsId = setTimeout(function () {
1494
                        afterSectionLoads(v);
1495
                    }, options.scrollingSpeed);
1496
                }else{
1497
                    afterSectionLoads(v);
1498
                }
1499
            }
1500

1501
            // using jQuery animate
1502
            else{
1503
                var scrollSettings = getScrollSettings(v);
1504

1505
                $(scrollSettings.element).animate(
1506
                    scrollSettings.options,
1507
                options.scrollingSpeed, options.easing).promise().done(function () { //only one single callback in case of animating  `html, body`
1508
                    if(options.scrollBar){
1509

1510
                        /* Hack!
1511
                        The timeout prevents setting the most dominant section in the viewport as "active" when the user
1512
                        scrolled to a smaller section by using the mousewheel (auto scrolling) rather than draging the scroll bar.
1513

1514
                        When using scrollBar:true It seems like the scroll events still getting propagated even after the scrolling animation has finished.
1515
                        */
1516
                        setTimeout(function(){
1517
                            afterSectionLoads(v);
1518
                        },30);
1519
                    }else{
1520
                        afterSectionLoads(v);
1521
                    }
1522
                });
1523
            }
1524
        }
1525

1526
        /**
1527
        * Gets the scrolling settings depending on the plugin autoScrolling option
1528
        */
1529
        function getScrollSettings(v){
1530
            var scroll = {};
1531

1532
            if(options.autoScrolling && !options.scrollBar){
1533
                scroll.options = { 'top': -v.dtop};
1534
                scroll.element = WRAPPER_SEL;
1535
            }else{
1536
                scroll.options = { 'scrollTop': v.dtop};
1537
                scroll.element = 'html, body';
1538
            }
1539

1540
            return scroll;
1541
        }
1542

1543
        /**
1544
        * Adds sections before or after the current one to create the infinite effect.
1545
        */
1546
        function createInfiniteSections(v){
1547
            // Scrolling down
1548
            if (!v.isMovementUp) {
1549
                // Move all previous sections to after the active section
1550
                $(SECTION_ACTIVE_SEL).after(v.activeSection.prevAll(SECTION_SEL).get().reverse());
1551
            }
1552
            else { // Scrolling up
1553
                // Move all next sections to before the active section
1554
                $(SECTION_ACTIVE_SEL).before(v.activeSection.nextAll(SECTION_SEL));
1555
            }
1556

1557
            // Maintain the displayed position (now that we changed the element order)
1558
            silentScroll($(SECTION_ACTIVE_SEL).position().top);
1559

1560
            // Maintain the active slides visible in the viewport
1561
            keepSlidesPosition();
1562

1563
            // save for later the elements that still need to be reordered
1564
            v.wrapAroundElements = v.activeSection;
1565

1566
            // Recalculate animation variables
1567
            v.dtop = v.element.position().top;
1568
            v.yMovement = getYmovement(v.element);
1569

1570
            return v;
1571
        }
1572

1573
        /**
1574
        * Fix section order after continuousVertical changes have been animated
1575
        */
1576
        function continuousVerticalFixSectionOrder (v) {
1577
            // If continuousVertical is in effect (and autoScrolling would also be in effect then),
1578
            // finish moving the elements around so the direct navigation will function more simply
1579
            if (!v.wrapAroundElements || !v.wrapAroundElements.length) {
1580
                return;
1581
            }
1582

1583
            if (v.isMovementUp) {
1584
                $(SECTION_FIRST_SEL).before(v.wrapAroundElements);
1585
            }
1586
            else {
1587
                $(SECTION_LAST_SEL).after(v.wrapAroundElements);
1588
            }
1589

1590
            silentScroll($(SECTION_ACTIVE_SEL).position().top);
1591

1592
            // Maintain the active slides visible in the viewport
1593
            keepSlidesPosition();
1594
        }
1595

1596

1597
        /**
1598
        * Actions to do once the section is loaded.
1599
        */
1600
        function afterSectionLoads (v){
1601
            continuousVerticalFixSectionOrder(v);
1602

1603
            //callback (afterLoad) if the site is not just resizing and readjusting the slides
1604
            $.isFunction(options.afterLoad) && !v.localIsResizing && options.afterLoad.call(v.element, v.anchorLink, (v.sectionIndex + 1));
1605
            options.scrollOverflowHandler.afterLoad();
1606

1607
            if(!v.localIsResizing){
1608
                playMedia(v.element);
1609
            }
1610

1611
            v.element.addClass(COMPLETELY).siblings().removeClass(COMPLETELY);
1612

1613
            canScroll = true;
1614

1615
            $.isFunction(v.callback) && v.callback.call(this);
1616
        }
1617

1618
        /**
1619
        * Sets the value for the given attribute from the `data-` attribute with the same suffix
1620
        * ie: data-srcset ==> srcset  |  data-src ==> src
1621
        */
1622
        function setSrc(element, attribute){
1623
            element
1624
                .attr(attribute, element.data(attribute))
1625
                .removeAttr('data-' + attribute);
1626
        }
1627

1628
        /**
1629
        * Lazy loads image, video and audio elements.
1630
        */
1631
        function lazyLoad(destiny){
1632
            if (!options.lazyLoading){
1633
                return;
1634
            }
1635

1636
            var panel = getSlideOrSection(destiny);
1637
            var element;
1638
            
1639
            panel.find('img[data-src], img[data-srcset], source[data-src], audio[data-src], iframe[data-src]').each(function(){
1640
                element = $(this);
1641

1642
                $.each(['src', 'srcset'], function(index, type){
1643
                    var attribute = element.attr('data-' + type);
1644
                    if(typeof attribute !== 'undefined' && attribute){
1645
                        setSrc(element, type);
1646
                    }
1647
                });
1648

1649
                if(element.is('source')){
1650
                    element.closest('video').get(0).load();
1651
                }
1652
            });
1653
        }
1654

1655
        /**
1656
        * Plays video and audio elements.
1657
        */
1658
        function playMedia(destiny){
1659
            var panel = getSlideOrSection(destiny);
1660

1661
            //playing HTML5 media elements
1662
            panel.find('video, audio').each(function(){
1663
                var element = $(this).get(0);
1664

1665
                if( element.hasAttribute('data-autoplay') && typeof element.play === 'function' ) {
1666
                    element.play();
1667
                }
1668
            });
1669

1670
            //youtube videos
1671
            panel.find('iframe[src*="youtube.com/embed/"]').each(function(){
1672
                var element = $(this).get(0);
1673

1674
                if ( element.hasAttribute('data-autoplay') ){
1675
                    playYoutube(element);
1676
                }
1677

1678
                //in case the URL was not loaded yet. On page load we need time for the new URL (with the API string) to load.
1679
                element.onload = function() {
1680
                    if ( element.hasAttribute('data-autoplay') ){
1681
                        playYoutube(element);
1682
                    }
1683
                };
1684
            });
1685
        }
1686

1687
        /**
1688
        * Plays a youtube video
1689
        */
1690
        function playYoutube(element){
1691
            element.contentWindow.postMessage('{"event":"command","func":"playVideo","args":""}', '*');
1692
        }
1693

1694
        /**
1695
        * Stops video and audio elements.
1696
        */
1697
        function stopMedia(destiny){
1698
            var panel = getSlideOrSection(destiny);
1699

1700
            //stopping HTML5 media elements
1701
            panel.find('video, audio').each(function(){
1702
                var element = $(this).get(0);
1703

1704
                if( !element.hasAttribute('data-keepplaying') && typeof element.pause === 'function' ) {
1705
                    element.pause();
1706
                }
1707
            });
1708

1709
            //youtube videos
1710
            panel.find('iframe[src*="youtube.com/embed/"]').each(function(){
1711
                var element = $(this).get(0);
1712

1713
                if( /youtube\.com\/embed\//.test($(this).attr('src')) && !element.hasAttribute('data-keepplaying')){
1714
                    $(this).get(0).contentWindow.postMessage('{"event":"command","func":"pauseVideo","args":""}','*');
1715
                }
1716
            });
1717
        }
1718

1719
        /**
1720
        * Gets the active slide (or section) for the given section
1721
        */
1722
        function getSlideOrSection(destiny){
1723
            var slide = destiny.find(SLIDE_ACTIVE_SEL);
1724
            if( slide.length ) {
1725
                destiny = $(slide);
1726
            }
1727

1728
            return destiny;
1729
        }
1730

1731
        /**
1732
        * Scrolls to the anchor in the URL when loading the site
1733
        */
1734
        function scrollToAnchor(){
1735
            //getting the anchor link in the URL and deleting the `#`
1736
            var value =  window.location.hash.replace('#', '').split('/');
1737
            var sectionAnchor = decodeURIComponent(value[0]);
1738
            var slideAnchor = decodeURIComponent(value[1]);
1739

1740
            if(sectionAnchor){  //if theres any #
1741
                if(options.animateAnchor){
1742
                    scrollPageAndSlide(sectionAnchor, slideAnchor);
1743
                }else{
1744
                    silentMoveTo(sectionAnchor, slideAnchor);
1745
                }
1746
            }
1747
        }
1748

1749
        /**
1750
        * Detecting any change on the URL to scroll to the given anchor link
1751
        * (a way to detect back history button as we play with the hashes on the URL)
1752
        */
1753
        function hashChangeHandler(){
1754
            if(!isScrolling && !options.lockAnchors){
1755
                var value =  window.location.hash.replace('#', '').split('/');
1756
                var sectionAnchor = decodeURIComponent(value[0]);
1757
                var slideAnchor = decodeURIComponent(value[1]);
1758

1759
                    //when moving to a slide in the first section for the first time (first time to add an anchor to the URL)
1760
                    var isFirstSlideMove =  (typeof lastScrolledDestiny === 'undefined');
1761
                    var isFirstScrollMove = (typeof lastScrolledDestiny === 'undefined' && typeof slideAnchor === 'undefined' && !slideMoving);
1762

1763

1764
                if(sectionAnchor.length){
1765
                    /*in order to call scrollpage() only once for each destination at a time
1766
                    It is called twice for each scroll otherwise, as in case of using anchorlinks `hashChange`
1767
                    event is fired on every scroll too.*/
1768
                    if ((sectionAnchor && sectionAnchor !== lastScrolledDestiny) && !isFirstSlideMove || isFirstScrollMove || (!slideMoving && lastScrolledSlide != slideAnchor ))  {
1769
                        scrollPageAndSlide(sectionAnchor, slideAnchor);
1770
                    }
1771
                }
1772
            }
1773
        }
1774

1775
        //Sliding with arrow keys, both, vertical and horizontal
1776
        function keydownHandler(e) {
1777

1778
            clearTimeout(keydownId);
1779

1780
            var activeElement = $(':focus');
1781

1782
            if(!activeElement.is('textarea') && !activeElement.is('input') && !activeElement.is('select') &&
1783
                activeElement.attr('contentEditable') !== "true" && activeElement.attr('contentEditable') !== '' &&
1784
                options.keyboardScrolling && options.autoScrolling){
1785
                var keyCode = e.which;
1786

1787
                //preventing the scroll with arrow keys & spacebar & Page Up & Down keys
1788
                var keyControls = [40, 38, 32, 33, 34];
1789
                if($.inArray(keyCode, keyControls) > -1){
1790
                    e.preventDefault();
1791
                }
1792

1793
                controlPressed = e.ctrlKey;
1794

1795
                keydownId = setTimeout(function(){
1796
                    onkeydown(e);
1797
                },150);
1798
            }
1799
        }
1800

1801
        function tooltipTextHandler(){
1802
            $(this).prev().trigger('click');
1803
        }
1804

1805
        //to prevent scrolling while zooming
1806
        function keyUpHandler(e){
1807
            if(isWindowFocused){ //the keyup gets fired on new tab ctrl + t in Firefox
1808
                controlPressed = e.ctrlKey;
1809
            }
1810
        }
1811

1812
        //binding the mousemove when the mouse's middle button is released
1813
        function mouseDownHandler(e){
1814
            //middle button
1815
            if (e.which == 2){
1816
                oldPageY = e.pageY;
1817
                container.on('mousemove', mouseMoveHandler);
1818
            }
1819
        }
1820

1821
        //unbinding the mousemove when the mouse's middle button is released
1822
        function mouseUpHandler(e){
1823
            //middle button
1824
            if (e.which == 2){
1825
                container.off('mousemove');
1826
            }
1827
        }
1828

1829
        //Scrolling horizontally when clicking on the slider controls.
1830
        function slideArrowHandler(){
1831
            var section = $(this).closest(SECTION_SEL);
1832

1833
            if ($(this).hasClass(SLIDES_PREV)) {
1834
                if(isScrollAllowed.m.left){
1835
                    moveSlideLeft(section);
1836
                }
1837
            } else {
1838
                if(isScrollAllowed.m.right){
1839
                    moveSlideRight(section);
1840
                }
1841
            }
1842
        }
1843

1844
        //when opening a new tab (ctrl + t), `control` won't be pressed when coming back.
1845
        function blurHandler(){
1846
            isWindowFocused = false;
1847
            controlPressed = false;
1848
        }
1849

1850
        //Scrolls to the section when clicking the navigation bullet
1851
        function sectionBulletHandler(e){
1852
            e.preventDefault();
1853
            var index = $(this).parent().index();
1854
            scrollPage($(SECTION_SEL).eq(index));
1855
        }
1856

1857
        //Scrolls the slider to the given slide destination for the given section
1858
        function slideBulletHandler(e){
1859
            e.preventDefault();
1860
            var slides = $(this).closest(SECTION_SEL).find(SLIDES_WRAPPER_SEL);
1861
            var destiny = slides.find(SLIDE_SEL).eq($(this).closest('li').index());
1862

1863
            landscapeScroll(slides, destiny);
1864
        }
1865

1866
        /**
1867
        * Keydown event
1868
        */
1869
        function onkeydown(e){
1870
            var shiftPressed = e.shiftKey;
1871

1872
            //do nothing if we can not scroll or we are not using horizotnal key arrows.
1873
            if(!canScroll && [37,39].indexOf(e.which) < 0){
1874
                return;
1875
            }
1876

1877
            switch (e.which) {
1878
                //up
1879
                case 38:
1880
                case 33:
1881
                    if(isScrollAllowed.k.up){
1882
                        moveSectionUp();
1883
                    }
1884
                    break;
1885

1886
                //down
1887
                case 32: //spacebar
1888
                    if(shiftPressed && isScrollAllowed.k.up){
1889
                        moveSectionUp();
1890
                        break;
1891
                    }
1892
                /* falls through */
1893
                case 40:
1894
                case 34:
1895
                    if(isScrollAllowed.k.down){
1896
                        moveSectionDown();
1897
                    }
1898
                    break;
1899

1900
                //Home
1901
                case 36:
1902
                    if(isScrollAllowed.k.up){
1903
                        moveTo(1);
1904
                    }
1905
                    break;
1906

1907
                //End
1908
                case 35:
1909
                     if(isScrollAllowed.k.down){
1910
                        moveTo( $(SECTION_SEL).length );
1911
                    }
1912
                    break;
1913

1914
                //left
1915
                case 37:
1916
                    if(isScrollAllowed.k.left){
1917
                        moveSlideLeft();
1918
                    }
1919
                    break;
1920

1921
                //right
1922
                case 39:
1923
                    if(isScrollAllowed.k.right){
1924
                        moveSlideRight();
1925
                    }
1926
                    break;
1927

1928
                default:
1929
                    return; // exit this handler for other keys
1930
            }
1931
        }
1932

1933
        /**
1934
        * Detecting the direction of the mouse movement.
1935
        * Used only for the middle button of the mouse.
1936
        */
1937
        var oldPageY = 0;
1938
        function mouseMoveHandler(e){
1939
            if(canScroll){
1940
                // moving up
1941
                if (e.pageY < oldPageY && isScrollAllowed.m.up){
1942
                    moveSectionUp();
1943
                }
1944

1945
                // moving down
1946
                else if(e.pageY > oldPageY && isScrollAllowed.m.down){
1947
                    moveSectionDown();
1948
                }
1949
            }
1950
            oldPageY = e.pageY;
1951
        }
1952

1953
        /**
1954
        * Scrolls horizontal sliders.
1955
        */
1956
        function landscapeScroll(slides, destiny, direction){
1957
            var section = slides.closest(SECTION_SEL);
1958
            var v = {
1959
                slides: slides,
1960
                destiny: destiny,
1961
                direction: direction,
1962
                destinyPos: destiny.position(),
1963
                slideIndex: destiny.index(),
1964
                section: section,
1965
                sectionIndex: section.index(SECTION_SEL),
1966
                anchorLink: section.data('anchor'),
1967
                slidesNav: section.find(SLIDES_NAV_SEL),
1968
                slideAnchor:  getAnchor(destiny),
1969
                prevSlide: section.find(SLIDE_ACTIVE_SEL),
1970
                prevSlideIndex: section.find(SLIDE_ACTIVE_SEL).index(),
1971

1972
                //caching the value of isResizing at the momment the function is called
1973
                //because it will be checked later inside a setTimeout and the value might change
1974
                localIsResizing: isResizing
1975
            };
1976
            v.xMovement = getXmovement(v.prevSlideIndex, v.slideIndex);
1977

1978
            //important!! Only do it when not resizing
1979
            if(!v.localIsResizing){
1980
                //preventing from scrolling to the next/prev section when using scrollHorizontally
1981
                canScroll = false;
1982
            }
1983

1984
            if(options.onSlideLeave){
1985

1986
                //if the site is not just resizing and readjusting the slides
1987
                if(!v.localIsResizing && v.xMovement!=='none'){
1988
                    if($.isFunction( options.onSlideLeave )){
1989
                        if(options.onSlideLeave.call( v.prevSlide, v.anchorLink, (v.sectionIndex + 1), v.prevSlideIndex, v.xMovement, v.slideIndex ) === false){
1990
                            slideMoving = false;
1991
                            return;
1992
                        }
1993
                    }
1994
                }
1995
            }
1996

1997
            destiny.addClass(ACTIVE).siblings().removeClass(ACTIVE);
1998

1999
            if(!v.localIsResizing){
2000
                stopMedia(v.prevSlide);
2001
                lazyLoad(destiny);
2002
            }
2003

2004
            if(!options.loopHorizontal && options.controlArrows){
2005
                //hidding it for the fist slide, showing for the rest
2006
                section.find(SLIDES_ARROW_PREV_SEL).toggle(v.slideIndex!==0);
2007

2008
                //hidding it for the last slide, showing for the rest
2009
                section.find(SLIDES_ARROW_NEXT_SEL).toggle(!destiny.is(':last-child'));
2010
            }
2011

2012
            //only changing the URL if the slides are in the current section (not for resize re-adjusting)
2013
            if(section.hasClass(ACTIVE) && !v.localIsResizing){
2014
                setState(v.slideIndex, v.slideAnchor, v.anchorLink, v.sectionIndex);
2015
            }
2016

2017
            performHorizontalMove(slides, v, true);
2018
        }
2019

2020

2021
        function afterSlideLoads(v){
2022
            activeSlidesNavigation(v.slidesNav, v.slideIndex);
2023

2024
            //if the site is not just resizing and readjusting the slides
2025
            if(!v.localIsResizing){
2026
                $.isFunction( options.afterSlideLoad ) && options.afterSlideLoad.call( v.destiny, v.anchorLink, (v.sectionIndex + 1), v.slideAnchor, v.slideIndex);
2027

2028
                //needs to be inside the condition to prevent problems with continuousVertical and scrollHorizontally
2029
                //and to prevent double scroll right after a windows resize
2030
                canScroll = true;
2031

2032
                playMedia(v.destiny);
2033
            }
2034

2035
            //letting them slide again
2036
            slideMoving = false;
2037
        }
2038

2039
        /**
2040
        * Performs the horizontal movement. (CSS3 or jQuery)
2041
        *
2042
        * @param fireCallback {Bool} - determines whether or not to fire the callback
2043
        */
2044
        function performHorizontalMove(slides, v, fireCallback){
2045
            var destinyPos = v.destinyPos;
2046

2047
            if(options.css3){
2048
                var translate3d = 'translate3d(-' + Math.round(destinyPos.left) + 'px, 0px, 0px)';
2049

2050
                addAnimation(slides.find(SLIDES_CONTAINER_SEL)).css(getTransforms(translate3d));
2051

2052
                afterSlideLoadsId = setTimeout(function(){
2053
                    fireCallback && afterSlideLoads(v);
2054
                }, options.scrollingSpeed, options.easing);
2055
            }else{
2056
                slides.animate({
2057
                    scrollLeft : Math.round(destinyPos.left)
2058
                }, options.scrollingSpeed, options.easing, function() {
2059

2060
                    fireCallback && afterSlideLoads(v);
2061
                });
2062
            }
2063
        }
2064

2065
        /**
2066
        * Sets the state for the horizontal bullet navigations.
2067
        */
2068
        function activeSlidesNavigation(slidesNav, slideIndex){
2069
            slidesNav.find(ACTIVE_SEL).removeClass(ACTIVE);
2070
            slidesNav.find('li').eq(slideIndex).find('a').addClass(ACTIVE);
2071
        }
2072

2073
        var previousHeight = windowsHeight;
2074

2075
        //when resizing the site, we adjust the heights of the sections, slimScroll...
2076
        function resizeHandler(){
2077
            //checking if it needs to get responsive
2078
            responsive();
2079

2080
            // rebuild immediately on touch devices
2081
            if (isTouchDevice) {
2082
                var activeElement = $(document.activeElement);
2083

2084
                //if the keyboard is NOT visible
2085
                if (!activeElement.is('textarea') && !activeElement.is('input') && !activeElement.is('select')) {
2086
                    var currentHeight = $window.height();
2087

2088
                    //making sure the change in the viewport size is enough to force a rebuild. (20 % of the window to avoid problems when hidding scroll bars)
2089
                    if( Math.abs(currentHeight - previousHeight) > (20 * Math.max(previousHeight, currentHeight) / 100) ){
2090
                        reBuild(true);
2091
                        previousHeight = currentHeight;
2092
                    }
2093
                }
2094
            }else{
2095
                //in order to call the functions only when the resize is finished
2096
                //http://stackoverflow.com/questions/4298612/jquery-how-to-call-resize-event-only-once-its-finished-resizing
2097
                clearTimeout(resizeId);
2098

2099
                resizeId = setTimeout(function(){
2100
                    reBuild(true);
2101
                }, 350);
2102
            }
2103
        }
2104

2105
        /**
2106
        * Checks if the site needs to get responsive and disables autoScrolling if so.
2107
        * A class `fp-responsive` is added to the plugin's container in case the user wants to use it for his own responsive CSS.
2108
        */
2109
        function responsive(){
2110
            var widthLimit = options.responsive || options.responsiveWidth; //backwards compatiblity
2111
            var heightLimit = options.responsiveHeight;
2112

2113
            //only calculating what we need. Remember its called on the resize event.
2114
            var isBreakingPointWidth = widthLimit && $window.outerWidth() < widthLimit;
2115
            var isBreakingPointHeight = heightLimit && $window.height() < heightLimit;
2116

2117
            if(widthLimit && heightLimit){
2118
                setResponsive(isBreakingPointWidth || isBreakingPointHeight);
2119
            }
2120
            else if(widthLimit){
2121
                setResponsive(isBreakingPointWidth);
2122
            }
2123
            else if(heightLimit){
2124
                setResponsive(isBreakingPointHeight);
2125
            }
2126
        }
2127

2128
        /**
2129
        * Adds transition animations for the given element
2130
        */
2131
        function addAnimation(element){
2132
            var transition = 'all ' + options.scrollingSpeed + 'ms ' + options.easingcss3;
2133

2134
            element.removeClass(NO_TRANSITION);
2135
            return element.css({
2136
                '-webkit-transition': transition,
2137
                'transition': transition
2138
            });
2139
        }
2140

2141
        /**
2142
        * Remove transition animations for the given element
2143
        */
2144
        function removeAnimation(element){
2145
            return element.addClass(NO_TRANSITION);
2146
        }
2147

2148
        /**
2149
        * Activating the vertical navigation bullets according to the given slide name.
2150
        */
2151
        function activateNavDots(name, sectionIndex){
2152
            if(options.navigation){
2153
                $(SECTION_NAV_SEL).find(ACTIVE_SEL).removeClass(ACTIVE);
2154
                if(name){
2155
                    $(SECTION_NAV_SEL).find('a[href="#' + name + '"]').addClass(ACTIVE);
2156
                }else{
2157
                    $(SECTION_NAV_SEL).find('li').eq(sectionIndex).find('a').addClass(ACTIVE);
2158
                }
2159
            }
2160
        }
2161

2162
        /**
2163
        * Activating the website main menu elements according to the given slide name.
2164
        */
2165
        function activateMenuElement(name){
2166
            if(options.menu){
2167
                $(options.menu).find(ACTIVE_SEL).removeClass(ACTIVE);
2168
                $(options.menu).find('[data-menuanchor="'+name+'"]').addClass(ACTIVE);
2169
            }
2170
        }
2171

2172
        /**
2173
        * Sets to active the current menu and vertical nav items.
2174
        */
2175
        function activateMenuAndNav(anchor, index){
2176
            activateMenuElement(anchor);
2177
            activateNavDots(anchor, index);
2178
        }
2179

2180
        /**
2181
        * Retuns `up` or `down` depending on the scrolling movement to reach its destination
2182
        * from the current section.
2183
        */
2184
        function getYmovement(destiny){
2185
            var fromIndex = $(SECTION_ACTIVE_SEL).index(SECTION_SEL);
2186
            var toIndex = destiny.index(SECTION_SEL);
2187
            if( fromIndex == toIndex){
2188
                return 'none';
2189
            }
2190
            if(fromIndex > toIndex){
2191
                return 'up';
2192
            }
2193
            return 'down';
2194
        }
2195

2196
        /**
2197
        * Retuns `right` or `left` depending on the scrolling movement to reach its destination
2198
        * from the current slide.
2199
        */
2200
        function getXmovement(fromIndex, toIndex){
2201
            if( fromIndex == toIndex){
2202
                return 'none';
2203
            }
2204
            if(fromIndex > toIndex){
2205
                return 'left';
2206
            }
2207
            return 'right';
2208
        }
2209

2210
        /**
2211
        * Checks if the element needs scrollbar and if the user wants to apply it.
2212
        * If so it creates it.
2213
        *
2214
        * @param {Object} element   jQuery object of the section or slide
2215
        */
2216
        function createScrollBar(element){
2217
            //User doesn't want scrollbar here? Sayonara baby!
2218
            if(element.hasClass('fp-noscroll')) return;
2219

2220
            //needed to make `scrollHeight` work under Opera 12
2221
            element.css('overflow', 'hidden');
2222

2223
            var scrollOverflowHandler = options.scrollOverflowHandler;
2224
            var wrap = scrollOverflowHandler.wrapContent();
2225
            //in case element is a slide
2226
            var section = element.closest(SECTION_SEL);
2227
            var scrollable = scrollOverflowHandler.scrollable(element);
2228
            var contentHeight;
2229

2230
            //if there was scroll, the contentHeight will be the one in the scrollable section
2231
            if(scrollable.length){
2232
                contentHeight = scrollOverflowHandler.scrollHeight(element);
2233
            }else{
2234
                contentHeight = element.get(0).scrollHeight;
2235
                if(options.verticalCentered){
2236
                    contentHeight = element.find(TABLE_CELL_SEL).get(0).scrollHeight;
2237
                }
2238
            }
2239

2240
            var scrollHeight = windowsHeight - parseInt(section.css('padding-bottom')) - parseInt(section.css('padding-top'));
2241

2242
            //needs scroll?
2243
            if ( contentHeight > scrollHeight) {
2244
                //did we already have an scrollbar ? Updating it
2245
                if(scrollable.length){
2246
                    scrollOverflowHandler.update(element, scrollHeight);
2247
                }
2248
                //creating the scrolling
2249
                else{
2250
                    if(options.verticalCentered){
2251
                        element.find(TABLE_CELL_SEL).wrapInner(wrap);
2252
                    }else{
2253
                        element.wrapInner(wrap);
2254
                    }
2255
                    scrollOverflowHandler.create(element, scrollHeight);
2256
                }
2257
            }
2258
            //removing the scrolling when it is not necessary anymore
2259
            else{
2260
                scrollOverflowHandler.remove(element);
2261
            }
2262

2263
            //undo
2264
            element.css('overflow', '');
2265
        }
2266

2267
        function addTableClass(element){
2268
            //In case we are styling for the 2nd time as in with reponsiveSlides
2269
            if(!element.hasClass(TABLE)){
2270
                element.addClass(TABLE).wrapInner('<div class="' + TABLE_CELL + '" style="height:' + getTableHeight(element) + 'px;" />');
2271
            }
2272
        }
2273

2274
        function getTableHeight(element){
2275
            var sectionHeight = windowsHeight;
2276

2277
            if(options.paddingTop || options.paddingBottom){
2278
                var section = element;
2279
                if(!section.hasClass(SECTION)){
2280
                    section = element.closest(SECTION_SEL);
2281
                }
2282

2283
                var paddings = parseInt(section.css('padding-top')) + parseInt(section.css('padding-bottom'));
2284
                sectionHeight = (windowsHeight - paddings);
2285
            }
2286

2287
            return sectionHeight;
2288
        }
2289

2290
        /**
2291
        * Adds a css3 transform property to the container class with or without animation depending on the animated param.
2292
        */
2293
        function transformContainer(translate3d, animated){
2294
            if(animated){
2295
                addAnimation(container);
2296
            }else{
2297
                removeAnimation(container);
2298
            }
2299

2300
            container.css(getTransforms(translate3d));
2301

2302
            //syncronously removing the class after the animation has been applied.
2303
            setTimeout(function(){
2304
                container.removeClass(NO_TRANSITION);
2305
            },10);
2306
        }
2307

2308
        /**
2309
        * Gets a section by its anchor / index
2310
        */
2311
        function getSectionByAnchor(sectionAnchor){
2312
            if(!sectionAnchor) return [];
2313

2314
            var section = container.find(SECTION_SEL + '[data-anchor="'+sectionAnchor+'"]');
2315
            if(!section.length){
2316
                section = $(SECTION_SEL).eq( sectionAnchor -1);
2317
            }
2318

2319
            return section;
2320
        }
2321

2322
        /**
2323
        * Gets a slide inside a given section by its anchor / index
2324
        */
2325
        function getSlideByAnchor(slideAnchor, section){
2326
            var slides = section.find(SLIDES_WRAPPER_SEL);
2327
            var slide =  slides.find(SLIDE_SEL + '[data-anchor="'+slideAnchor+'"]');
2328

2329
            if(!slide.length){
2330
                slide = slides.find(SLIDE_SEL).eq(slideAnchor);
2331
            }
2332

2333
            return slide;
2334
        }
2335

2336
        /**
2337
        * Scrolls to the given section and slide anchors
2338
        */
2339
        function scrollPageAndSlide(destiny, slide){
2340
            var section = getSectionByAnchor(destiny);
2341

2342
            //do nothing if there's no section with the given anchor name
2343
            if(!section.length) return;
2344

2345
            //default slide
2346
            if (typeof slide === 'undefined') {
2347
                slide = 0;
2348
            }
2349

2350
            //we need to scroll to the section and then to the slide
2351
            if (destiny !== lastScrolledDestiny && !section.hasClass(ACTIVE)){
2352
                scrollPage(section, function(){
2353
                    scrollSlider(section, slide);
2354
                });
2355
            }
2356
            //if we were already in the section
2357
            else{
2358
                scrollSlider(section, slide);
2359
            }
2360
        }
2361

2362
        /**
2363
        * Scrolls the slider to the given slide destination for the given section
2364
        */
2365
        function scrollSlider(section, slideAnchor){
2366
            if(typeof slideAnchor !== 'undefined'){
2367
                var slides = section.find(SLIDES_WRAPPER_SEL);
2368
                var destiny =  getSlideByAnchor(slideAnchor, section);
2369

2370
                if(destiny.length){
2371
                    landscapeScroll(slides, destiny);
2372
                }
2373
            }
2374
        }
2375

2376
        /**
2377
        * Creates a landscape navigation bar with dots for horizontal sliders.
2378
        */
2379
        function addSlidesNavigation(section, numSlides){
2380
            section.append('<div class="' + SLIDES_NAV + '"><ul></ul></div>');
2381
            var nav = section.find(SLIDES_NAV_SEL);
2382

2383
            //top or bottom
2384
            nav.addClass(options.slidesNavPosition);
2385

2386
            for(var i=0; i< numSlides; i++){
2387
                nav.find('ul').append('<li><a href="#"><span></span></a></li>');
2388
            }
2389

2390
            //centering it
2391
            nav.css('margin-left', '-' + (nav.width()/2) + 'px');
2392

2393
            nav.find('li').first().find('a').addClass(ACTIVE);
2394
        }
2395

2396

2397
        /**
2398
        * Sets the state of the website depending on the active section/slide.
2399
        * It changes the URL hash when needed and updates the body class.
2400
        */
2401
        function setState(slideIndex, slideAnchor, anchorLink, sectionIndex){
2402
            var sectionHash = '';
2403

2404
            if(options.anchors.length && !options.lockAnchors){
2405

2406
                //isn't it the first slide?
2407
                if(slideIndex){
2408
                    if(typeof anchorLink !== 'undefined'){
2409
                        sectionHash = anchorLink;
2410
                    }
2411

2412
                    //slide without anchor link? We take the index instead.
2413
                    if(typeof slideAnchor === 'undefined'){
2414
                        slideAnchor = slideIndex;
2415
                    }
2416

2417
                    lastScrolledSlide = slideAnchor;
2418
                    setUrlHash(sectionHash + '/' + slideAnchor);
2419

2420
                //first slide won't have slide anchor, just the section one
2421
                }else if(typeof slideIndex !== 'undefined'){
2422
                    lastScrolledSlide = slideAnchor;
2423
                    setUrlHash(anchorLink);
2424
                }
2425

2426
                //section without slides
2427
                else{
2428
                    setUrlHash(anchorLink);
2429
                }
2430
            }
2431

2432
            setBodyClass();
2433
        }
2434

2435
        /**
2436
        * Sets the URL hash.
2437
        */
2438
        function setUrlHash(url){
2439
            if(options.recordHistory){
2440
                location.hash = url;
2441
            }else{
2442
                //Mobile Chrome doesn't work the normal way, so... lets use HTML5 for phones :)
2443
                if(isTouchDevice || isTouch){
2444
                    window.history.replaceState(undefined, undefined, '#' + url);
2445
                }else{
2446
                    var baseUrl = window.location.href.split('#')[0];
2447
                    window.location.replace( baseUrl + '#' + url );
2448
                }
2449
            }
2450
        }
2451

2452
        /**
2453
        * Gets the anchor for the given slide / section. Its index will be used if there's none.
2454
        */
2455
        function getAnchor(element){
2456
            var anchor = element.data('anchor');
2457
            var index = element.index();
2458

2459
            //Slide without anchor link? We take the index instead.
2460
            if(typeof anchor === 'undefined'){
2461
                anchor = index;
2462
            }
2463

2464
            return anchor;
2465
        }
2466

2467
        /**
2468
        * Sets a class for the body of the page depending on the active section / slide
2469
        */
2470
        function setBodyClass(){
2471
            var section = $(SECTION_ACTIVE_SEL);
2472
            var slide = section.find(SLIDE_ACTIVE_SEL);
2473

2474
            var sectionAnchor = getAnchor(section);
2475
            var slideAnchor = getAnchor(slide);
2476

2477
            var text = String(sectionAnchor);
2478

2479
            if(slide.length){
2480
                text = text + '-' + slideAnchor;
2481
            }
2482

2483
            //changing slash for dash to make it a valid CSS style
2484
            text = text.replace('/', '-').replace('#','');
2485

2486
            //removing previous anchor classes
2487
            var classRe = new RegExp('\\b\\s?' + VIEWING_PREFIX + '-[^\\s]+\\b', "g");
2488
            $body[0].className = $body[0].className.replace(classRe, '');
2489

2490
            //adding the current anchor
2491
            $body.addClass(VIEWING_PREFIX + '-' + text);
2492
        }
2493

2494
        /**
2495
        * Checks for translate3d support
2496
        * @return boolean
2497
        * http://stackoverflow.com/questions/5661671/detecting-transform-translate3d-support
2498
        */
2499
        function support3d() {
2500
            var el = document.createElement('p'),
2501
                has3d,
2502
                transforms = {
2503
                    'webkitTransform':'-webkit-transform',
2504
                    'OTransform':'-o-transform',
2505
                    'msTransform':'-ms-transform',
2506
                    'MozTransform':'-moz-transform',
2507
                    'transform':'transform'
2508
                };
2509

2510
            // Add it to the body to get the computed style.
2511
            document.body.insertBefore(el, null);
2512

2513
            for (var t in transforms) {
2514
                if (el.style[t] !== undefined) {
2515
                    el.style[t] = 'translate3d(1px,1px,1px)';
2516
                    has3d = window.getComputedStyle(el).getPropertyValue(transforms[t]);
2517
                }
2518
            }
2519

2520
            document.body.removeChild(el);
2521

2522
            return (has3d !== undefined && has3d.length > 0 && has3d !== 'none');
2523
        }
2524

2525
        /**
2526
        * Removes the auto scrolling action fired by the mouse wheel and trackpad.
2527
        * After this function is called, the mousewheel and trackpad movements won't scroll through sections.
2528
        */
2529
        function removeMouseWheelHandler(){
2530
            if (document.addEventListener) {
2531
                document.removeEventListener('mousewheel', MouseWheelHandler, false); //IE9, Chrome, Safari, Oper
2532
                document.removeEventListener('wheel', MouseWheelHandler, false); //Firefox
2533
                document.removeEventListener('MozMousePixelScroll', MouseWheelHandler, false); //old Firefox
2534
            } else {
2535
                document.detachEvent('onmousewheel', MouseWheelHandler); //IE 6/7/8
2536
            }
2537
        }
2538

2539
        /**
2540
        * Adds the auto scrolling action for the mouse wheel and trackpad.
2541
        * After this function is called, the mousewheel and trackpad movements will scroll through sections
2542
        * https://developer.mozilla.org/en-US/docs/Web/Events/wheel
2543
        */
2544
        function addMouseWheelHandler(){
2545
            var prefix = '';
2546
            var _addEventListener;
2547

2548
            if (window.addEventListener){
2549
                _addEventListener = "addEventListener";
2550
            }else{
2551
                _addEventListener = "attachEvent";
2552
                prefix = 'on';
2553
            }
2554

2555
             // detect available wheel event
2556
            var support = 'onwheel' in document.createElement('div') ? 'wheel' : // Modern browsers support "wheel"
2557
                      document.onmousewheel !== undefined ? 'mousewheel' : // Webkit and IE support at least "mousewheel"
2558
                      'DOMMouseScroll'; // let's assume that remaining browsers are older Firefox
2559

2560

2561
            if(support == 'DOMMouseScroll'){
2562
                document[ _addEventListener ](prefix + 'MozMousePixelScroll', MouseWheelHandler, false);
2563
            }
2564

2565
            //handle MozMousePixelScroll in older Firefox
2566
            else{
2567
                document[ _addEventListener ](prefix + support, MouseWheelHandler, false);
2568
            }
2569
        }
2570

2571
        /**
2572
        * Binding the mousemove when the mouse's middle button is pressed
2573
        */
2574
        function addMiddleWheelHandler(){
2575
            container
2576
                .on('mousedown', mouseDownHandler)
2577
                .on('mouseup', mouseUpHandler);
2578
        }
2579

2580
        /**
2581
        * Unbinding the mousemove when the mouse's middle button is released
2582
        */
2583
        function removeMiddleWheelHandler(){
2584
            container
2585
                .off('mousedown', mouseDownHandler)
2586
                .off('mouseup', mouseUpHandler);
2587
        }
2588

2589
        /**
2590
        * Adds the possibility to auto scroll through sections on touch devices.
2591
        */
2592
        function addTouchHandler(){
2593
            if(isTouchDevice || isTouch){
2594
                if(options.autoScrolling){
2595
                    $body.off(events.touchmove).on(events.touchmove, preventBouncing);
2596
                }
2597

2598
                $(WRAPPER_SEL)
2599
                    .off(events.touchstart).on(events.touchstart, touchStartHandler)
2600
                    .off(events.touchmove).on(events.touchmove, touchMoveHandler);
2601
            }
2602
        }
2603

2604
        /**
2605
        * Removes the auto scrolling for touch devices.
2606
        */
2607
        function removeTouchHandler(){
2608
            if(isTouchDevice || isTouch){
2609
                $(WRAPPER_SEL)
2610
                    .off(events.touchstart)
2611
                    .off(events.touchmove);
2612
            }
2613
        }
2614

2615
        /*
2616
        * Returns and object with Microsoft pointers (for IE<11 and for IE >= 11)
2617
        * http://msdn.microsoft.com/en-us/library/ie/dn304886(v=vs.85).aspx
2618
        */
2619
        function getMSPointer(){
2620
            var pointer;
2621

2622
            //IE >= 11 & rest of browsers
2623
            if(window.PointerEvent){
2624
                pointer = { down: 'pointerdown', move: 'pointermove'};
2625
            }
2626

2627
            //IE < 11
2628
            else{
2629
                pointer = { down: 'MSPointerDown', move: 'MSPointerMove'};
2630
            }
2631

2632
            return pointer;
2633
        }
2634

2635
        /**
2636
        * Gets the pageX and pageY properties depending on the browser.
2637
        * https://github.com/alvarotrigo/fullPage.js/issues/194#issuecomment-34069854
2638
        */
2639
        function getEventsPage(e){
2640
            var events = [];
2641

2642
            events.y = (typeof e.pageY !== 'undefined' && (e.pageY || e.pageX) ? e.pageY : e.touches[0].pageY);
2643
            events.x = (typeof e.pageX !== 'undefined' && (e.pageY || e.pageX) ? e.pageX : e.touches[0].pageX);
2644

2645
            //in touch devices with scrollBar:true, e.pageY is detected, but we have to deal with touch events. #1008
2646
            if(isTouch && isReallyTouch(e) && options.scrollBar){
2647
                events.y = e.touches[0].pageY;
2648
                events.x = e.touches[0].pageX;
2649
            }
2650

2651
            return events;
2652
        }
2653

2654
        /**
2655
        * Slides silently (with no animation) the active slider to the given slide.
2656
        * @param noCallback {bool} true or defined -> no callbacks
2657
        */
2658
        function silentLandscapeScroll(activeSlide, noCallbacks){
2659
            setScrollingSpeed (0, 'internal');
2660

2661
            if(typeof noCallbacks !== 'undefined'){
2662
                //preventing firing callbacks afterSlideLoad etc.
2663
                isResizing = true;
2664
            }
2665

2666
            landscapeScroll(activeSlide.closest(SLIDES_WRAPPER_SEL), activeSlide);
2667

2668
            if(typeof noCallbacks !== 'undefined'){
2669
                isResizing = false;
2670
            }
2671

2672
            setScrollingSpeed(originals.scrollingSpeed, 'internal');
2673
        }
2674

2675
        /**
2676
        * Scrolls silently (with no animation) the page to the given Y position.
2677
        */
2678
        function silentScroll(top){
2679
            // The first section can have a negative value in iOS 10. Not quite sure why: -0.0142822265625
2680
            // that's why we round it to 0.
2681
            var roundedTop = Math.round(top);
2682

2683
            if (options.css3 && options.autoScrolling && !options.scrollBar){
2684
                var translate3d = 'translate3d(0px, -' + roundedTop + 'px, 0px)';
2685
                transformContainer(translate3d, false);
2686
            }
2687
            else if(options.autoScrolling && !options.scrollBar){
2688
                container.css('top', -roundedTop);
2689
            }
2690
            else{
2691
                $htmlBody.scrollTop(roundedTop);
2692
            }
2693
        }
2694

2695
        /**
2696
        * Returns the cross-browser transform string.
2697
        */
2698
        function getTransforms(translate3d){
2699
            return {
2700
                '-webkit-transform': translate3d,
2701
                '-moz-transform': translate3d,
2702
                '-ms-transform':translate3d,
2703
                'transform': translate3d
2704
            };
2705
        }
2706

2707
        /**
2708
        * Allowing or disallowing the mouse/swipe scroll in a given direction. (not for keyboard)
2709
        * @type  m (mouse) or k (keyboard)
2710
        */
2711
        function setIsScrollAllowed(value, direction, type){
2712
            switch (direction){
2713
                case 'up': isScrollAllowed[type].up = value; break;
2714
                case 'down': isScrollAllowed[type].down = value; break;
2715
                case 'left': isScrollAllowed[type].left = value; break;
2716
                case 'right': isScrollAllowed[type].right = value; break;
2717
                case 'all':
2718
                    if(type == 'm'){
2719
                        setAllowScrolling(value);
2720
                    }else{
2721
                        setKeyboardScrolling(value);
2722
                    }
2723
            }
2724
        }
2725

2726
        /*
2727
        * Destroys fullpage.js plugin events and optinally its html markup and styles
2728
        */
2729
        function destroy(all){
2730
            setAutoScrolling(false, 'internal');
2731
            setAllowScrolling(false);
2732
            setKeyboardScrolling(false);
2733
            container.addClass(DESTROYED);
2734

2735
            clearTimeout(afterSlideLoadsId);
2736
            clearTimeout(afterSectionLoadsId);
2737
            clearTimeout(resizeId);
2738
            clearTimeout(scrollId);
2739
            clearTimeout(scrollId2);
2740

2741
            $window
2742
                .off('scroll', scrollHandler)
2743
                .off('hashchange', hashChangeHandler)
2744
                .off('resize', resizeHandler);
2745

2746
            $document
2747
                .off('click touchstart', SECTION_NAV_SEL + ' a')
2748
                .off('mouseenter', SECTION_NAV_SEL + ' li')
2749
                .off('mouseleave', SECTION_NAV_SEL + ' li')
2750
                .off('click touchstart', SLIDES_NAV_LINK_SEL)
2751
                .off('mouseover', options.normalScrollElements)
2752
                .off('mouseout', options.normalScrollElements);
2753

2754
            $(SECTION_SEL)
2755
                .off('click touchstart', SLIDES_ARROW_SEL);
2756

2757
            clearTimeout(afterSlideLoadsId);
2758
            clearTimeout(afterSectionLoadsId);
2759

2760
            //lets make a mess!
2761
            if(all){
2762
                destroyStructure();
2763
            }
2764
        }
2765

2766
        /*
2767
        * Removes inline styles added by fullpage.js
2768
        */
2769
        function destroyStructure(){
2770
            //reseting the `top` or `translate` properties to 0
2771
            silentScroll(0);
2772

2773
            //loading all the lazy load content
2774
            container.find('img[data-src], source[data-src], audio[data-src], iframe[data-src]').each(function(){
2775
                setSrc($(this), 'src');
2776
            });
2777

2778
            container.find('img[data-srcset]').each(function(){
2779
                setSrc($(this), 'srcset');
2780
            });
2781

2782
            $(SECTION_NAV_SEL + ', ' + SLIDES_NAV_SEL +  ', ' + SLIDES_ARROW_SEL).remove();
2783

2784
            //removing inline styles
2785
            $(SECTION_SEL).css( {
2786
                'height': '',
2787
                'background-color' : '',
2788
                'padding': ''
2789
            });
2790

2791
            $(SLIDE_SEL).css( {
2792
                'width': ''
2793
            });
2794

2795
            container.css({
2796
                'height': '',
2797
                'position': '',
2798
                '-ms-touch-action': '',
2799
                'touch-action': ''
2800
            });
2801

2802
            $htmlBody.css({
2803
                'overflow': '',
2804
                'height': ''
2805
            });
2806

2807
            // remove .fp-enabled class
2808
            $('html').removeClass(ENABLED);
2809

2810
            // remove .fp-responsive class
2811
            $body.removeClass(RESPONSIVE);
2812

2813
            // remove all of the .fp-viewing- classes
2814
            $.each($body.get(0).className.split(/\s+/), function (index, className) {
2815
                if (className.indexOf(VIEWING_PREFIX) === 0) {
2816
                    $body.removeClass(className);
2817
                }
2818
            });
2819

2820
            //removing added classes
2821
            $(SECTION_SEL + ', ' + SLIDE_SEL).each(function(){
2822
                options.scrollOverflowHandler.remove($(this));
2823
                $(this).removeClass(TABLE + ' ' + ACTIVE);
2824
            });
2825

2826
            removeAnimation(container);
2827

2828
            //Unwrapping content
2829
            container.find(TABLE_CELL_SEL + ', ' + SLIDES_CONTAINER_SEL + ', ' + SLIDES_WRAPPER_SEL).each(function(){
2830
                //unwrap not being use in case there's no child element inside and its just text
2831
                $(this).replaceWith(this.childNodes);
2832
            });
2833

2834
            //removing the applied transition from the fullpage wrapper
2835
            container.css({
2836
                '-webkit-transition': 'none',
2837
                'transition': 'none'
2838
            });
2839

2840
            //scrolling the page to the top with no animation
2841
            $htmlBody.scrollTop(0);
2842

2843
            //removing selectors
2844
            var usedSelectors = [SECTION, SLIDE, SLIDES_CONTAINER];
2845
            $.each(usedSelectors, function(index, value){
2846
                $('.' + value).removeClass(value);
2847
            });
2848
        }
2849

2850
        /*
2851
        * Sets the state for a variable with multiple states (original, and temporal)
2852
        * Some variables such as `autoScrolling` or `recordHistory` might change automatically its state when using `responsive` or `autoScrolling:false`.
2853
        * This function is used to keep track of both states, the original and the temporal one.
2854
        * If type is not 'internal', then we assume the user is globally changing the variable.
2855
        */
2856
        function setVariableState(variable, value, type){
2857
            options[variable] = value;
2858
            if(type !== 'internal'){
2859
                originals[variable] = value;
2860
            }
2861
        }
2862

2863
        /**
2864
        * Displays warnings
2865
        */
2866
        function displayWarnings(){
2867
            var extensions = ['fadingEffect', 'continuousHorizontal', 'scrollHorizontally', 'interlockedSlides', 'resetSliders', 'responsiveSlides', 'offsetSections', 'dragAndMove', 'scrollOverflowReset', 'parallax'];
2868
            if($('html').hasClass(ENABLED)){
2869
                showError('error', 'Fullpage.js can only be initialized once and you are doing it multiple times!');
2870
                return;
2871
            }
2872

2873
            // Disable mutually exclusive settings
2874
            if (options.continuousVertical &&
2875
                (options.loopTop || options.loopBottom)) {
2876
                options.continuousVertical = false;
2877
                showError('warn', 'Option `loopTop/loopBottom` is mutually exclusive with `continuousVertical`; `continuousVertical` disabled');
2878
            }
2879

2880
            if(options.scrollBar && options.scrollOverflow){
2881
                showError('warn', 'Option `scrollBar` is mutually exclusive with `scrollOverflow`. Sections with scrollOverflow might not work well in Firefox');
2882
            }
2883

2884
            if(options.continuousVertical && (options.scrollBar || !options.autoScrolling)){
2885
                options.continuousVertical = false;
2886
                showError('warn', 'Scroll bars (`scrollBar:true` or `autoScrolling:false`) are mutually exclusive with `continuousVertical`; `continuousVertical` disabled');
2887
            }
2888

2889
            //using extensions? Wrong file!
2890
            $.each(extensions, function(index, extension){
2891
                //is the option set to true?
2892
                if(options[extension]){
2893
                    showError('warn', 'fullpage.js extensions require jquery.fullpage.extensions.min.js file instead of the usual jquery.fullpage.js. Requested: '+ extension);
2894
                }
2895
            });
2896

2897
            //anchors can not have the same value as any element ID or NAME
2898
            $.each(options.anchors, function(index, name){
2899

2900
                //case insensitive selectors (http://stackoverflow.com/a/19465187/1081396)
2901
                var nameAttr = $document.find('[name]').filter(function() {
2902
                    return $(this).attr('name') && $(this).attr('name').toLowerCase() == name.toLowerCase();
2903
                });
2904

2905
                var idAttr = $document.find('[id]').filter(function() {
2906
                    return $(this).attr('id') && $(this).attr('id').toLowerCase() == name.toLowerCase();
2907
                });
2908

2909
                if(idAttr.length || nameAttr.length ){
2910
                    showError('error', 'data-anchor tags can not have the same value as any `id` element on the site (or `name` element for IE).');
2911
                    idAttr.length && showError('error', '"' + name + '" is is being used by another element `id` property');
2912
                    nameAttr.length && showError('error', '"' + name + '" is is being used by another element `name` property');
2913
                }
2914
            });
2915
        }
2916

2917
        /**
2918
        * Shows a message in the console of the given type.
2919
        */
2920
        function showError(type, text){
2921
            console && console[type] && console[type]('fullPage: ' + text);
2922
        }
2923

2924
    }; //end of $.fn.fullpage
2925

2926
    if(typeof IScroll !== 'undefined'){
2927
        /*
2928
        * Turns iScroll `mousewheel` option off dynamically
2929
        * https://github.com/cubiq/iscroll/issues/1036
2930
        */
2931
        IScroll.prototype.wheelOn = function () {
2932
            this.wrapper.addEventListener('wheel', this);
2933
            this.wrapper.addEventListener('mousewheel', this);
2934
            this.wrapper.addEventListener('DOMMouseScroll', this);
2935
        };
2936

2937
        /*
2938
        * Turns iScroll `mousewheel` option on dynamically
2939
        * https://github.com/cubiq/iscroll/issues/1036
2940
        */
2941
        IScroll.prototype.wheelOff = function () {
2942
            this.wrapper.removeEventListener('wheel', this);
2943
            this.wrapper.removeEventListener('mousewheel', this);
2944
            this.wrapper.removeEventListener('DOMMouseScroll', this);
2945
        };
2946
    }
2947

2948
    /**
2949
     * An object to handle overflow scrolling.
2950
     * This uses jquery.slimScroll to accomplish overflow scrolling.
2951
     * It is possible to pass in an alternate scrollOverflowHandler
2952
     * to the fullpage.js option that implements the same functions
2953
     * as this handler.
2954
     *
2955
     * @type {Object}
2956
     */
2957
    var iscrollHandler = {
2958
        refreshId: null,
2959
        iScrollInstances: [],
2960

2961
        // Enables or disables the mouse wheel for the active section or all slides in it
2962
        toggleWheel: function(value){
2963
            var scrollable = $(SECTION_ACTIVE_SEL).find(SCROLLABLE_SEL);
2964
            scrollable.each(function(){
2965
                var iScrollInstance = $(this).data('iscrollInstance');
2966
                if(typeof iScrollInstance !== 'undefined' && iScrollInstance){
2967
                    if(value){
2968
                        iScrollInstance.wheelOn();
2969
                    }
2970
                    else{
2971
                        iScrollInstance.wheelOff();
2972
                    }
2973
                }
2974
            });
2975
        },
2976

2977
        /**
2978
        * Turns off iScroll for the destination section.
2979
        * When scrolling very fast on some trackpads (and Apple laptops) the inertial scrolling would
2980
        * scroll the destination section/slide before the sections animations ends.
2981
        */
2982
        onLeave: function(){
2983
            iscrollHandler.toggleWheel(false);
2984
        },
2985

2986
        // Turns off iScroll for the leaving section
2987
        beforeLeave: function(){
2988
            iscrollHandler.onLeave()
2989
        },
2990

2991
        // Turns on iScroll on section load
2992
        afterLoad: function(){
2993
            iscrollHandler.toggleWheel(true);
2994
        },
2995

2996
        /**
2997
         * Called when overflow scrolling is needed for a section.
2998
         *
2999
         * @param  {Object} element      jQuery object containing current section
3000
         * @param  {Number} scrollHeight Current window height in pixels
3001
         */
3002
        create: function(element, scrollHeight) {
3003
            var scrollable = element.find(SCROLLABLE_SEL);
3004

3005
            scrollable.height(scrollHeight);
3006
            scrollable.each(function() {
3007
                var $this = $(this);
3008
                var iScrollInstance = $this.data('iscrollInstance');
3009
                if (iScrollInstance) {
3010
                    $.each(iscrollHandler.iScrollInstances, function(){
3011
                        $(this).destroy();
3012
                    });
3013
                }
3014

3015
                iScrollInstance = new IScroll($this.get(0), iscrollOptions);
3016
                iscrollHandler.iScrollInstances.push(iScrollInstance);
3017

3018
                //off by default until the section gets active
3019
                iScrollInstance.wheelOff();
3020

3021
                $this.data('iscrollInstance', iScrollInstance);
3022
            });
3023
        },
3024

3025
        /**
3026
         * Return a boolean depending on whether the scrollable element is a
3027
         * the end or at the start of the scrolling depending on the given type.
3028
         *
3029
         * @param  {String}  type       Either 'top' or 'bottom'
3030
         * @param  {Object}  scrollable jQuery object for the scrollable element
3031
         * @return {Boolean}
3032
         */
3033
        isScrolled: function(type, scrollable) {
3034
            var scroller = scrollable.data('iscrollInstance');
3035

3036
            //no scroller?
3037
            if (!scroller) {
3038
                return true;
3039
            }
3040

3041
            if (type === 'top') {
3042
                return scroller.y >= 0 && !scrollable.scrollTop();
3043
            } else if (type === 'bottom') {
3044
                return (0 - scroller.y) + scrollable.scrollTop() + 1 + scrollable.innerHeight() >= scrollable[0].scrollHeight;
3045
            }
3046
        },
3047

3048
        /**
3049
         * Returns the scrollable element for the given section.
3050
         * If there are landscape slides, will only return a scrollable element
3051
         * if it is in the active slide.
3052
         *
3053
         * @param  {Object}  activeSection jQuery object containing current section
3054
         * @return {Boolean}
3055
         */
3056
        scrollable: function(activeSection){
3057
            // if there are landscape slides, we check if the scrolling bar is in the current one or not
3058
            if (activeSection.find(SLIDES_WRAPPER_SEL).length) {
3059
                return activeSection.find(SLIDE_ACTIVE_SEL).find(SCROLLABLE_SEL);
3060
            }
3061
            return activeSection.find(SCROLLABLE_SEL);
3062
        },
3063

3064
        /**
3065
         * Returns the scroll height of the wrapped content.
3066
         * If this is larger than the window height minus section padding,
3067
         * overflow scrolling is needed.
3068
         *
3069
         * @param  {Object} element jQuery object containing current section
3070
         * @return {Number}
3071
         */
3072
        scrollHeight: function(element) {
3073
            return element.find(SCROLLABLE_SEL).children().first().get(0).scrollHeight;
3074
        },
3075

3076
        /**
3077
         * Called when overflow scrolling is no longer needed for a section.
3078
         *
3079
         * @param  {Object} element      jQuery object containing current section
3080
         */
3081
        remove: function(element) {
3082
            var scrollable = element.find(SCROLLABLE_SEL);
3083
            if (scrollable.length) {
3084
                var iScrollInstance = scrollable.data('iscrollInstance');
3085
                iScrollInstance.destroy();
3086

3087
                scrollable.data('iscrollInstance', null);
3088
            }
3089
            element.find(SCROLLABLE_SEL).children().first().children().first().unwrap().unwrap();
3090
        },
3091

3092
        /**
3093
         * Called when overflow scrolling has already been setup but the
3094
         * window height has potentially changed.
3095
         *
3096
         * @param  {Object} element      jQuery object containing current section
3097
         * @param  {Number} scrollHeight Current window height in pixels
3098
         */
3099
        update: function(element, scrollHeight) {
3100
            //using a timeout in order to execute the refresh function only once when `update` is called multiple times in a
3101
            //short period of time.
3102
            //it also comes on handy because iScroll requires the use of timeout when using `refresh`.
3103
            clearTimeout(iscrollHandler.refreshId);
3104
            iscrollHandler.refreshId = setTimeout(function(){
3105
                $.each(iscrollHandler.iScrollInstances, function(){
3106
                    $(this).get(0).refresh();
3107
                });
3108
            }, 150);
3109

3110
            //updating the wrappers height
3111
            element.find(SCROLLABLE_SEL).css('height', scrollHeight + 'px').parent().css('height', scrollHeight + 'px');
3112
        },
3113

3114
        /**
3115
         * Called to get any additional elements needed to wrap the section
3116
         * content in order to facilitate overflow scrolling.
3117
         *
3118
         * @return {String|Object} Can be a string containing HTML,
3119
         *                         a DOM element, or jQuery object.
3120
         */
3121
        wrapContent: function() {
3122
            return '<div class="' + SCROLLABLE + '"><div class="fp-scroller"></div></div>';
3123
        }
3124
    };
3125
});

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.