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