UNPKG

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