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