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