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