1/*! 2 * fullPage 2.8.2 3 * https://github.com/alvarotrigo/fullPage.js 4 * @license MIT licensed 5 * 6 * Copyright (C) 2015 alvarotrigo.com - A project by Alvaro Trigo 7 */ 8(function(global, factory) { 9 'use strict'; 10 if (typeof define === 'function' && define.amd) { 11 define(['jquery'], function($) { 12 return factory($, global, global.document, global.Math); 13 }); 14 } else if (typeof exports !== 'undefined') { 15 module.exports = factory(require('jquery'), global, global.document, global.Math); 16 } else { 17 factory(jQuery, global, global.document, global.Math); 18 } 19})(typeof window !== 'undefined' ? window : this, function($, window, document, Math, undefined) { 20 'use strict'; 21 22 // keeping central set of classnames and selectors 23 var WRAPPER = 'fullpage-wrapper'; 24 var WRAPPER_SEL = '.' + WRAPPER; 25 26 // slimscroll 27 var SCROLLABLE = 'fp-scrollable'; 28 var SCROLLABLE_SEL = '.' + SCROLLABLE; 29 30 // util 31 var RESPONSIVE = 'fp-responsive'; 32 var NO_TRANSITION = 'fp-notransition'; 33 var DESTROYED = 'fp-destroyed'; 34 var ENABLED = 'fp-enabled'; 35 var VIEWING_PREFIX = 'fp-viewing'; 36 var ACTIVE = 'active'; 37 var ACTIVE_SEL = '.' + ACTIVE; 38 var COMPLETELY = 'fp-completely'; 39 var COMPLETELY_SEL = '.' + COMPLETELY; 40 41 // section 42 var SECTION_DEFAULT_SEL = '.section'; 43 var SECTION = 'fp-section'; 44 var SECTION_SEL = '.' + SECTION; 45 var SECTION_ACTIVE_SEL = SECTION_SEL + ACTIVE_SEL; 46 var SECTION_FIRST_SEL = SECTION_SEL + ':first'; 47 var SECTION_LAST_SEL = SECTION_SEL + ':last'; 48 var TABLE_CELL = 'fp-tableCell'; 49 var TABLE_CELL_SEL = '.' + TABLE_CELL; 50 var AUTO_HEIGHT = 'fp-auto-height'; 51 var AUTO_HEIGHT_SEL = '.fp-auto-height'; 52 var NORMAL_SCROLL = 'fp-normal-scroll'; 53 var NORMAL_SCROLL_SEL = '.fp-normal-scroll'; 54 55 // section nav 56 var SECTION_NAV = 'fp-nav'; 57 var SECTION_NAV_SEL = '#' + SECTION_NAV; 58 var SECTION_NAV_TOOLTIP = 'fp-tooltip'; 59 var SECTION_NAV_TOOLTIP_SEL='.'+SECTION_NAV_TOOLTIP; 60 var SHOW_ACTIVE_TOOLTIP = 'fp-show-active'; 61 62 // slide 63 var SLIDE_DEFAULT_SEL = '.slide'; 64 var SLIDE = 'fp-slide'; 65 var SLIDE_SEL = '.' + SLIDE; 66 var SLIDE_ACTIVE_SEL = SLIDE_SEL + ACTIVE_SEL; 67 var SLIDES_WRAPPER = 'fp-slides'; 68 var SLIDES_WRAPPER_SEL = '.' + SLIDES_WRAPPER; 69 var SLIDES_CONTAINER = 'fp-slidesContainer'; 70 var SLIDES_CONTAINER_SEL = '.' + SLIDES_CONTAINER; 71 var TABLE = 'fp-table'; 72 73 // slide nav 74 var SLIDES_NAV = 'fp-slidesNav'; 75 var SLIDES_NAV_SEL = '.' + SLIDES_NAV; 76 var SLIDES_NAV_LINK_SEL = SLIDES_NAV_SEL + ' a'; 77 var SLIDES_ARROW = 'fp-controlArrow'; 78 var SLIDES_ARROW_SEL = '.' + SLIDES_ARROW; 79 var SLIDES_PREV = 'fp-prev'; 80 var SLIDES_PREV_SEL = '.' + SLIDES_PREV; 81 var SLIDES_ARROW_PREV = SLIDES_ARROW + ' ' + SLIDES_PREV; 82 var SLIDES_ARROW_PREV_SEL = SLIDES_ARROW_SEL + SLIDES_PREV_SEL; 83 var SLIDES_NEXT = 'fp-next'; 84 var SLIDES_NEXT_SEL = '.' + SLIDES_NEXT; 85 var SLIDES_ARROW_NEXT = SLIDES_ARROW + ' ' + SLIDES_NEXT; 86 var SLIDES_ARROW_NEXT_SEL = SLIDES_ARROW_SEL + SLIDES_NEXT_SEL; 87 88 var $window = $(window); 89 var $document = $(document); 90 91 // Default options for iScroll.js used when using scrollOverflow 92 var iscrollOptions = { 93 scrollbars: true, 94 mouseWheel: true, 95 hideScrollbars: false, 96 fadeScrollbars: false, 97 disableMouse: true 98 }; 99 100 $.fn.fullpage = function(options) { 101 //only once my friend! 102 if($('html').hasClass(ENABLED)){ displayWarnings(); return; } 103 104 // common jQuery objects 105 var $htmlBody = $('html, body'); 106 var $body = $('body'); 107 108 var FP = $.fn.fullpage; 109 110 // Create some defaults, extending them with any options that were provided 111 options = $.extend({ 112 //navigation 113 menu: false, 114 anchors:[], 115 lockAnchors: false, 116 navigation: false, 117 navigationPosition: 'right', 118 navigationTooltips: [], 119 showActiveTooltip: false, 120 slidesNavigation: false, 121 slidesNavPosition: 'bottom', 122 scrollBar: false, 123 hybrid: false, 124 125 //scrolling 126 css3: true, 127 scrollingSpeed: 700, 128 autoScrolling: true, 129 fitToSection: true, 130 fitToSectionDelay: 1000, 131 easing: 'easeInOutCubic', 132 easingcss3: 'ease', 133 loopBottom: false, 134 loopTop: false, 135 loopHorizontal: true, 136 continuousVertical: false, 137 normalScrollElements: null, 138 scrollOverflow: false, 139 scrollOverflowHandler: iscrollHandler, 140 scrollOverflowOptions: null, 141 touchSensitivity: 5, 142 normalScrollElementTouchThreshold: 5, 143 bigSectionsDestination: null, 144 145 //Accessibility 146 keyboardScrolling: true, 147 animateAnchor: true, 148 recordHistory: true, 149 150 //design 151 controlArrows: true, 152 controlArrowColor: '#fff', 153 verticalCentered: true, 154 sectionsColor : [], 155 paddingTop: 0, 156 paddingBottom: 0, 157 fixedElements: null, 158 responsive: 0, //backwards compabitility with responsiveWiddth 159 responsiveWidth: 0, 160 responsiveHeight: 0, 161 162 //Custom selectors 163 sectionSelector: SECTION_DEFAULT_SEL, 164 slideSelector: SLIDE_DEFAULT_SEL, 165 166 167 //events 168 afterLoad: null, 169 onLeave: null, 170 afterRender: null, 171 afterResize: null, 172 afterReBuild: null, 173 afterSlideLoad: null, 174 onSlideLeave: null 175 }, options); 176 177 //flag to avoid very fast sliding for landscape sliders 178 var slideMoving = false;
179 180 var isTouchDevice = navigator.userAgent.match(/(iPhone|iPod|iPad|Android|playbook|silk|BlackBerry|BB10|Windows Phone|Tizen|Bada|webOS|IEMobile|Opera Mini)/); 181 var isTouch = (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0) || (navigator.maxTouchPoints)); 182 var container = $(this); 183 var windowsHeight = $window.height(); 184 var isResizing = false; 185 var isWindowFocused = true; 186 var lastScrolledDestiny; 187 var lastScrolledSlide; 188 var canScroll = true; 189 var scrollings = []; 190 var controlPressed; 191 var isScrollAllowed = {}; 192 isScrollAllowed.m = { 'up':true, 'down':true, 'left':true, 'right':true }; 193 isScrollAllowed.k = $.extend(true,{}, isScrollAllowed.m); 194 195 //timeouts 196 var resizeId; 197 var afterSectionLoadsId; 198 var afterSlideLoadsId; 199 var scrollId; 200 var scrollId2; 201 var keydownId; 202 var originals = $.extend(true, {}, options); //deep copy 203 204 displayWarnings(); 205 206 //fixing bug in iScroll with links: https://github.com/cubiq/iscroll/issues/783 207 iscrollOptions.click = isTouch; // see #2035 208 209 //extending iScroll options with the user custom ones 210 iscrollOptions = $.extend(iscrollOptions, options.scrollOverflowOptions); 211 212 //easeInOutCubic animation included in the plugin 213 $.extend($.easing,{ easeInOutCubic: function (x, t, b, c, d) {if ((t/=d/2) < 1) return c/2*t*t*t + b;return c/2*((t-=2)*t*t + 2) + b;}}); 214 215 /** 216 * Sets the autoScroll option. 217 * It changes the scroll bar visibility and the history of the site as a result. 218 */ 219 FP.setAutoScrolling = function(value, type){ 220 setVariableState('autoScrolling', value, type); 221 222 var element = $(SECTION_ACTIVE_SEL); 223 224 if(options.autoScrolling && !options.scrollBar){ 225 $htmlBody.css({ 226 'overflow' : 'hidden', 227 'height' : '100%' 228 }); 229 230 FP.setRecordHistory(originals.recordHistory, 'internal'); 231 232 //for IE touch devices 233 container.css({ 234 '-ms-touch-action': 'none', 235 'touch-action': 'none' 236 }); 237 238 if(element.length){ 239 //moving the container up 240 silentScroll(element.position().top); 241 } 242 243 }else{ 244 $htmlBody.css({ 245 'overflow' : 'visible', 246 'height' : 'initial' 247 }); 248 249 FP.setRecordHistory(false, 'internal'); 250 251 //for IE touch devices 252 container.css({ 253 '-ms-touch-action': '', 254 'touch-action': '' 255 }); 256 257 silentScroll(0); 258 259 //scrolling the page to the section with no animation 260 if (element.length) { 261 $htmlBody.scrollTop(element.position().top); 262 } 263 } 264 }; 265 266 /** 267 * Defines wheter to record the history for each hash change in the URL. 268 */ 269 FP.setRecordHistory = function(value, type){ 270 setVariableState('recordHistory', value, type); 271 }; 272 273 /** 274 * Defines the scrolling speed 275 */ 276 FP.setScrollingSpeed = function(value, type){ 277 setVariableState('scrollingSpeed', value, type); 278 }; 279 280 /** 281 * Sets fitToSection 282 */ 283 FP.setFitToSection = function(value, type){ 284 setVariableState('fitToSection', value, type); 285 }; 286 287 /** 288 * Sets lockAnchors 289 */ 290 FP.setLockAnchors = function(value){ 291 options.lockAnchors = value; 292 }; 293 294 /** 295 * Adds or remove the possiblity of scrolling through sections by using the mouse wheel or the trackpad. 296 */ 297 FP.setMouseWheelScrolling = function (value){ 298 if(value){ 299 addMouseWheelHandler(); 300 addMiddleWheelHandler(); 301 }else{ 302 removeMouseWheelHandler(); 303 removeMiddleWheelHandler(); 304 } 305 }; 306 307 /** 308 * Adds or remove the possiblity of scrolling through sections by using the mouse wheel/trackpad or touch gestures. 309 * Optionally a second parameter can be used to specify the direction for which the action will be applied. 310 * 311 * @param directions string containing the direction or directions separated by comma. 312 */ 313 FP.setAllowScrolling = function (value, directions){ 314 if(typeof directions !== 'undefined'){ 315 directions = directions.replace(/ /g,'').split(','); 316 317 $.each(directions, function (index, direction){ 318 setIsScrollAllowed(value, direction, 'm'); 319 }); 320 } 321 else if(value){ 322 FP.setMouseWheelScrolling(true); 323 addTouchHandler(); 324 }else{ 325 FP.setMouseWheelScrolling(false); 326 removeTouchHandler(); 327 } 328 }; 329 330 /** 331 * Adds or remove the possiblity of scrolling through sections by using the keyboard arrow keys 332 */ 333 FP.setKeyboardScrolling = function (value, directions){ 334 if(typeof directions !== 'undefined'){ 335 directions = directions.replace(/ /g,'').split(','); 336 337 $.each(directions, function (index, direction){ 338 setIsScrollAllowed(value, direction, 'k'); 339 }); 340 }else{ 341 options.keyboardScrolling = value; 342 } 343 }; 344 345 /** 346 * Moves the page up one section. 347 */ 348 FP.moveSectionUp = function(){ 349 var prev = $(SECTION_ACTIVE_SEL).prev(SECTION_SEL); 350 351 //looping to the bottom if there's no more sections above 352 if (!prev.length && (options.loopTop || options.continuousVertical)) {
353 prev = $(SECTION_SEL).last(); 354 } 355 356 if (prev.length) { 357 scrollPage(prev, null, true); 358 } 359 }; 360 361 /** 362 * Moves the page down one section. 363 */ 364 FP.moveSectionDown = function (){ 365 var next = $(SECTION_ACTIVE_SEL).next(SECTION_SEL); 366 367 //looping to the top if there's no more sections below 368 if(!next.length && 369 (options.loopBottom || options.continuousVertical)){ 370 next = $(SECTION_SEL).first(); 371 } 372 373 if(next.length){ 374 scrollPage(next, null, false); 375 } 376 }; 377 378 /** 379 * Moves the page to the given section and slide with no animation. 380 * Anchors or index positions can be used as params. 381 */ 382 FP.silentMoveTo = function(sectionAnchor, slideAnchor){ 383 FP.setScrollingSpeed (0, 'internal'); 384 FP.moveTo(sectionAnchor, slideAnchor); 385 FP.setScrollingSpeed (originals.scrollingSpeed, 'internal'); 386 }; 387 388 /** 389 * Moves the page to the given section and slide. 390 * Anchors or index positions can be used as params. 391 */ 392 FP.moveTo = function (sectionAnchor, slideAnchor){ 393 var destiny = getSectionByAnchor(sectionAnchor); 394 395 if (typeof slideAnchor !== 'undefined'){ 396 scrollPageAndSlide(sectionAnchor, slideAnchor); 397 }else if(destiny.length > 0){ 398 scrollPage(destiny); 399 } 400 }; 401 402 /** 403 * Slides right the slider of the active section. 404 * Optional `section` param. 405 */ 406 FP.moveSlideRight = function(section){ 407 moveSlide('next', section); 408 }; 409 410 /** 411 * Slides left the slider of the active section. 412 * Optional `section` param. 413 */ 414 FP.moveSlideLeft = function(section){ 415 moveSlide('prev', section); 416 }; 417 418 /** 419 * When resizing is finished, we adjust the slides sizes and positions 420 */ 421 FP.reBuild = function(resizing){ 422 if(container.hasClass(DESTROYED)){ return; } //nothing to do if the plugin was destroyed 423 424 isResizing = true; 425 426 windowsHeight = $window.height(); //updating global var 427 428 $(SECTION_SEL).each(function(){ 429 var slidesWrap = $(this).find(SLIDES_WRAPPER_SEL); 430 var slides = $(this).find(SLIDE_SEL); 431 432 //adjusting the height of the table-cell for IE and Firefox 433 if(options.verticalCentered){ 434 $(this).find(TABLE_CELL_SEL).css('height', getTableHeight($(this)) + 'px'); 435 } 436 437 $(this).css('height', windowsHeight + 'px'); 438 439 //resizing the scrolling divs 440 if(options.scrollOverflow){ 441 if(slides.length){ 442 slides.each(function(){ 443 createSlimScrolling($(this)); 444 }); 445 }else{ 446 createSlimScrolling($(this)); 447 } 448 } 449 450 //adjusting the position fo the FULL WIDTH slides... 451 if (slides.length > 1) { 452 landscapeScroll(slidesWrap, slidesWrap.find(SLIDE_ACTIVE_SEL)); 453 } 454 }); 455 456 var activeSection = $(SECTION_ACTIVE_SEL); 457 var sectionIndex = activeSection.index(SECTION_SEL); 458 459 //isn't it the first section? 460 if(sectionIndex){ 461 //adjusting the position for the current section 462 FP.silentMoveTo(sectionIndex + 1); 463 } 464 465 isResizing = false; 466 $.isFunction( options.afterResize ) && resizing && options.afterResize.call(container); 467 $.isFunction( options.afterReBuild ) && !resizing && options.afterReBuild.call(container); 468 }; 469 470 /** 471 * Turns fullPage.js to normal scrolling mode when the viewport `width` or `height` 472 * are smaller than the set limit values. 473 */ 474 FP.setResponsive = function (active){ 475 var isResponsive = $body.hasClass(RESPONSIVE); 476 477 if(active){ 478 if(!isResponsive){ 479 FP.setAutoScrolling(false, 'internal'); 480 FP.setFitToSection(false, 'internal'); 481 $(SECTION_NAV_SEL).hide(); 482 $body.addClass(RESPONSIVE); 483 } 484 } 485 else if(isResponsive){ 486 FP.setAutoScrolling(originals.autoScrolling, 'internal'); 487 FP.setFitToSection(originals.autoScrolling, 'internal'); 488 $(SECTION_NAV_SEL).show(); 489 $body.removeClass(RESPONSIVE); 490 } 491 }; 492 493 if($(this).length){ 494 init(); 495 bindEvents(); 496 } 497
498 function init(){ 499 //if css3 is not supported, it will use jQuery animations 500 if(options.css3){ 501 options.css3 = support3d(); 502 } 503 504 options.scrollBar = options.scrollBar || options.hybrid; 505 506 507 setOptionsFromDOM(); 508 509 prepareDom(); 510 FP.setAllowScrolling(true); 511 512 FP.setAutoScrolling(options.autoScrolling, 'internal'); 513 514 //the starting point is a slide? 515 var activeSlide = $(SECTION_ACTIVE_SEL).find(SLIDE_ACTIVE_SEL); 516 517 //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. 518 if( activeSlide.length && ($(SECTION_ACTIVE_SEL).index(SECTION_SEL) !== 0 || ($(SECTION_ACTIVE_SEL).index(SECTION_SEL) === 0 && activeSlide.index() !== 0))){ 519 silentLandscapeScroll(activeSlide); 520 } 521 522 responsive(); 523 524 //setting the class for the body element 525 setBodyClass(); 526 527 if(document.readyState === 'complete'){ 528 scrollToAnchor(); 529 } 530 $window.on('load', scrollToAnchor); 531 } 532 533 function bindEvents(){ 534 $window 535 //when scrolling... 536 .on('scroll', scrollHandler) 537 538 //detecting any change on the URL to scroll to the given anchor link 539 //(a way to detect back history button as we play with the hashes on the URL) 540 .on('hashchange', hashChangeHandler) 541 542 //when opening a new tab (ctrl + t), `control` won't be pressed when comming back. 543 .blur(blurHandler) 544 545 //when resizing the site, we adjust the heights of the sections, slimScroll... 546 .resize(resizeHandler); 547 548 $document 549 //Sliding with arrow keys, both, vertical and horizontal 550 .keydown(keydownHandler) 551 552 //to prevent scrolling while zooming 553 .keyup(keyUpHandler) 554 555 //Scrolls to the section when clicking the navigation bullet 556 .on('click touchstart', SECTION_NAV_SEL + ' a', sectionBulletHandler) 557 558 //Scrolls the slider to the given slide destination for the given section 559 .on('click touchstart', SLIDES_NAV_LINK_SEL, slideBulletHandler) 560 561 .on('click', SECTION_NAV_TOOLTIP_SEL, tooltipTextHandler); 562 563 //Scrolling horizontally when clicking on the slider controls. 564 $(SECTION_SEL).on('click touchstart', SLIDES_ARROW_SEL, slideArrowHandler); 565 566 /** 567 * Applying normalScroll elements. 568 * Ignoring the scrolls over the specified selectors. 569 */ 570 if(options.normalScrollElements){ 571 $document.on('mouseenter', options.normalScrollElements, function () { 572 FP.setMouseWheelScrolling(false); 573 }); 574 575 $document.on('mouseleave', options.normalScrollElements, function(){ 576 FP.setMouseWheelScrolling(true); 577 }); 578 } 579 } 580 581 /** 582 * Setting options from DOM elements if they are not provided. 583 */ 584 function setOptionsFromDOM(){ 585 var sections = container.find(options.sectionSelector); 586 587 //no anchors option? Checking for them in the DOM attributes 588 if(!options.anchors.length){ 589 options.anchors = sections.filter('[data-anchor]').map(function(){ 590 return $(this).data('anchor').toString(); 591 }).get(); 592 } 593 594 //no tooltipos option? Checking for them in the DOM attributes 595 if(!options.navigationTooltips.length){ 596 options.navigationTooltips = sections.filter('[data-tooltip]').map(function(){ 597 return $(this).data('tooltip').toString(); 598 }).get(); 599 } 600 } 601 602 /** 603 * Works over the DOM structure to set it up for the current fullpage optionss. 604 */ 605 function prepareDom(){ 606 container.css({ 607 'height': '100%', 608 'position': 'relative' 609 }); 610 611 //adding a class to recognize the container internally in the code 612 container.addClass(WRAPPER); 613 $('html').addClass(ENABLED); 614 615 //due to https://github.com/alvarotrigo/fullPage.js/issues/1502 616 windowsHeight = $window.height(); 617 618 container.removeClass(DESTROYED); //in case it was destroyed before initilizing it again 619 620 addInternalSelectors(); 621 622 //styling the sections / slides / menu 623 $(SECTION_SEL).each(function(index){ 624 var section = $(this); 625 var slides = section.find(SLIDE_SEL); 626 var numSlides = slides.length; 627 628 styleSection(section, index); 629 styleMenu(section, index); 630 631 // if there's any slide 632 if (numSlides > 0) { 633 styleSlides(section, slides, numSlides); 634 }else{ 635 if(options.verticalCentered){ 636 addTableClass(section); 637 } 638 } 639 }); 640 641 //fixed elements need to be moved out of the plugin container due to problems with CSS3. 642 if(options.fixedElements && options.css3){ 643 $(options.fixedElements).appendTo($body); 644 } 645 646 //vertical centered of the navigation + active bullet 647 if(options.navigation){ 648 addVerticalNavigation(); 649 } 650 651 enableYoutubeAPI(); 652 enableVidemoAPI(); 653 654 if(options.scrollOverflow){ 655 if(document.readyState === 'complete'){ 656 createSlimScrollingHandler(); 657 } 658 //after DOM and images are loaded 659 $window.on('load', createSlimScrollingHandler); 660 }else{ 661 afterRenderActions(); 662 } 663 } 664 665 /** 666 * Styles the horizontal slides for a section. 667 */ 668 function styleSlides(section, slides, numSlides){ 669 var sliderWidth = numSlides * 100; 670 var slideWidth = 100 / numSlides; 671 672 slides.wrapAll('<div class="' + SLIDES_CONTAINER + '" />'); 673 slides.parent().wrap('<div class="' + SLIDES_WRAPPER + '" />'); 674 675 section.find(SLIDES_CONTAINER_SEL).css('width', sliderWidth + '%'); 676 677 if(numSlides > 1){ 678 if(options.controlArrows){ 679 createSlideArrows(section); 680 } 681 682 if(options.slidesNavigation){ 683 addSlidesNavigation(section, numSlides); 684 } 685 } 686 687 slides.each(function(index) { 688 $(this).css('width', slideWidth + '%'); 689 690 if(options.verticalCentered){ 691 addTableClass($(this)); 692 } 693 }); 694 695 var startingSlide = section.find(SLIDE_ACTIVE_SEL); 696 697 //if the slide won't be an starting point, the default will be the first one 698 //the active section isn't the first one? Is not the first slide of the first section? Then we load that section/sl
698ide by default. 699 if( startingSlide.length && ($(SECTION_ACTIVE_SEL).index(SECTION_SEL) !== 0 || ($(SECTION_ACTIVE_SEL).index(SECTION_SEL) === 0 && startingSlide.index() !== 0))){ 700 silentLandscapeScroll(startingSlide); 701 }else{ 702 slides.eq(0).addClass(ACTIVE); 703 } 704 } 705 706 /** 707 * Styling vertical sections 708 */ 709 function styleSection(section, index){ 710 //if no active section is defined, the 1st one will be the default one 711 if(!index && $(SECTION_ACTIVE_SEL).length === 0) { 712 section.addClass(ACTIVE); 713 } 714 715 section.css('height', windowsHeight + 'px'); 716 717 if(options.paddingTop){ 718 section.css('padding-top', options.paddingTop); 719 } 720 721 if(options.paddingBottom){ 722 section.css('padding-bottom', options.paddingBottom); 723 } 724 725 if (typeof options.sectionsColor[index] !== 'undefined') { 726 section.css('background-color', options.sectionsColor[index]); 727 } 728 729 if (typeof options.anchors[index] !== 'undefined') { 730 section.attr('data-anchor', options.anchors[index]); 731 } 732 } 733 734 /** 735 * Sets the data-anchor attributes to the menu elements and activates the current one. 736 */ 737 function styleMenu(section, index){ 738 if (typeof options.anchors[index] !== 'undefined') { 739 //activating the menu / nav element on load 740 if(section.hasClass(ACTIVE)){ 741 activateMenuAndNav(options.anchors[index], index); 742 } 743 } 744 745 //moving the menu outside the main container if it is inside (avoid problems with fixed positions when using CSS3 tranforms) 746 if(options.menu && options.css3 && $(options.menu).closest(WRAPPER_SEL).length){ 747 $(options.menu).appendTo($body); 748 } 749 } 750 751 /** 752 * Adds internal classes to be able to provide customizable selectors 753 * keeping the link with the style sheet. 754 */ 755 function addInternalSelectors(){ 756 //adding internal class names to void problem with common ones 757 container.find(options.sectionSelector).each(function(){ 758 $(this).addClass(SECTION); 759 }); 760 container.find(options.slideSelector).each(function(){ 761 $(this).addClass(SLIDE); 762 }); 763 } 764 765 /** 766 * Creates the control arrows for the given section 767 */ 768 function createSlideArrows(section){ 769 section.find(SLIDES_WRAPPER_SEL).after('<div class="' + SLIDES_ARROW_PREV + '"></div><div class="' + SLIDES_ARROW_NEXT + '"></div>'); 770 771 if(options.controlArrowColor!='#fff'){ 772 section.find(SLIDES_ARROW_NEXT_SEL).css('border-color', 'transparent transparent transparent '+options.controlArrowColor); 773 section.find(SLIDES_ARROW_PREV_SEL).css('border-color', 'transparent '+ options.controlArrowColor + ' transparent transparent'); 774 } 775 776 if(!options.loopHorizontal){ 777 section.find(SLIDES_ARROW_PREV_SEL).hide(); 778 } 779 } 780 781 /** 782 * Creates a vertical navigation bar. 783 */ 784 function addVerticalNavigation(){ 785 $body.append('<div id="' + SECTION_NAV + '"><ul></ul></div>'); 786 var nav = $(SECTION_NAV_SEL); 787 788 nav.addClass(function() { 789 return options.showActiveTooltip ? SHOW_ACTIVE_TOOLTIP + ' ' + options.navigationPosition : options.navigationPosition; 790 }); 791 792 for (var i = 0; i < $(SECTION_SEL).length; i++) { 793 var link = ''; 794 if (options.anchors.length) { 795 link = options.anchors[i]; 796 } 797 798 var li = '<li><a href="#' + link + '"><span></span></a>'; 799 800 // Only add tooltip if needed (defined by user) 801 var tooltip = options.navigationTooltips[i]; 802 803 if (typeof tooltip !== 'undefined' && tooltip !== '') { 804 li += '<div class="' + SECTION_NAV_TOOLTIP + ' ' + options.navigationPosition + '">' + tooltip + '</div>'; 805 } 806 807 li += '</li>'; 808 809 nav.find('ul').append(li); 810 } 811 812 //centering it vertically 813 $(SECTION_NAV_SEL).css('margin-top', '-' + ($(SECTION_NAV_SEL).height()/2) + 'px'); 814 815 //activating the current active section 816 $(SECTION_NAV_SEL).find('li').eq($(SECTION_ACTIVE_SEL).index(SECTION_SEL)).find('a').addClass(ACTIVE); 817 } 818 819 /** 820 * Creates the slim scroll scrollbar for the sections and slides inside them. 821 */ 822 function createSlimScrollingHandler(){ 823 $(SECTION_SEL).each(function(){ 824 var slides = $(this).find(SLIDE_SEL); 825 826 if(slides.length){ 827 slides.each(function(){ 828 createSlimScrolling($(this)); 829 }); 830 }else{ 831 createSlimScrolling($(this)); 832 } 833 834 }); 835 afterRenderActions(); 836 } 837 838 /*
839 * Enables the Youtube videos API so we can control their flow if necessary. 840 */ 841 function enableYoutubeAPI(){ 842 container.find('iframe[src*="youtube.com/embed/"]').each(function(){ 843 var sign = getUrlParamSign($(this).attr('src')); 844 $(this).attr('src', $(this).attr('src') + sign + 'enablejsapi=1'); 845 }); 846 } 847 848 /* 849 * Enables the Vimeo videos API so we can control their flow if necessary. 850 */ 851 function enableVidemoAPI(){ 852 container.find('iframe[src*="player.vimeo.com/"]').each(function(){ 853 var sign = getUrlParamSign($(this).attr('src')); 854 $(this).attr('src', $(this).attr('src') + sign + 'api=1'); 855 }); 856 } 857 858 /* 859 * Returns the prefix sign to use for a new parameter in an existen URL. 860 * 861 * @return {String} ? | & 862 */ 863 function getUrlParamSign(url){ 864 return ( !/\?/.test( url ) ) ? '?' : '&'; 865 } 866 867 /** 868 * Actions and callbacks to fire afterRender 869 */ 870 function afterRenderActions(){ 871 var section = $(SECTION_ACTIVE_SEL); 872 873 section.addClass(COMPLETELY); 874 875 if(options.scrollOverflowHandler.afterRender){ 876 options.scrollOverflowHandler.afterRender(section); 877 } 878 lazyLoad(section); 879 playMedia(section); 880 881 $.isFunction( options.afterLoad ) && options.afterLoad.call(section, section.data('anchor'), (section.index(SECTION_SEL) + 1)); 882 $.isFunction( options.afterRender ) && options.afterRender.call(container); 883 } 884 885 886 var isScrolling = false; 887 var lastScroll = 0; 888 889 //when scrolling... 890 function scrollHandler(){ 891 var currentSection; 892 893 if(!options.autoScrolling || options.scrollBar){ 894 var currentScroll = $window.scrollTop(); 895 var scrollDirection = getScrollDirection(currentScroll); 896 var visibleSectionIndex = 0; 897 var screen_mid = currentScroll + ($window.height() / 2.0); 898 var isAtBottom = $body.height() - $window.height() === currentScroll; 899 var sections = document.querySelectorAll(SECTION_SEL); 900 901 //when using `auto-height` for a small last section it won't take most of the viewport 902 if(isAtBottom){ 903 visibleSectionIndex = sections.length - 1; 904 } 905 906 //taking the section which is showing more content in the viewport 907 else{ 908 for (var i = 0; i < sections.length; ++i) { 909 var section = sections[i]; 910 911 // Pick the the last section which passes the middle line of the screen. 912 if (section.offsetTop <= screen_mid) 913 { 914 visibleSectionIndex = i; 915 } 916 } 917 } 918 919 if(isCompletelyInViewPort(scrollDirection)){ 920 if(!$(SECTION_ACTIVE_SEL).hasClass(COMPLETELY)){ 921 $(SECTION_ACTIVE_SEL).addClass(COMPLETELY).siblings().removeClass(COMPLETELY); 922 } 923 } 924 925 //geting the last one, the current one on the screen 926 currentSection = $(sections).eq(visibleSectionIndex); 927 928 //setting the visible section as active when manually scrolling 929 //executing only once the first time we reach the section 930 if(!currentSection.hasClass(ACTIVE)){ 931 isScrolling = true; 932 var leavingSection = $(SECTION_ACTIVE_SEL); 933 var leavingSectionIndex = leavingSection.index(SECTION_SEL) + 1; 934 var yMovement = getYmovement(currentSection); 935 var anchorLink = currentSection.data('anchor'); 936 var sectionIndex = currentSection.index(SECTION_SEL) + 1; 937 var activeSlide = currentSection.find(SLIDE_ACTIVE_SEL); 938 939 if(activeSlide.length){ 940 var slideAnchorLink = activeSlide.data('anchor'); 941 var slideIndex = activeSlide.index(); 942 } 943 944 if(canScroll){ 945 currentSection.addClass(ACTIVE).siblings().removeClass(ACTIVE); 946 947 $.isFunction( options.onLeave ) && options.onLeave.call( leavingSection, leavingSectionIndex, sectionIndex, yMovement); 948 $.isFunction( options.afterLoad ) && options.afterLoad.call( currentSection, anchorLink, sectionIndex); 949 950 stopMedia(leavingSection); 951 lazyLoad(currentSection); 952 playMedia(currentSection); 953 954 activateMenuAndNav(anchorLink, sectionIndex - 1); 955 956 if(options.anchors.length){ 957 //needed to enter in hashChange event when using the menu with anchor links 958 lastScrolledDestiny = anchorLink; 959 960 setState(slideIndex, slideAnchorLink, anchorLink, sectionIndex); 961 } 962 } 963 964 //small timeout in order to avoid entering in hashChange event when scrolling is not finished yet 965 clearTimeout(scrollId); 966 scrollId = setTimeout(function(){ 967 isScrolling = false;
968 }, 100); 969 } 970 971 if(options.fitToSection){ 972 //for the auto adjust of the viewport to fit a whole section 973 clearTimeout(scrollId2); 974 975 scrollId2 = setTimeout(function(){ 976 //checking fitToSection again in case it was set to false before the timeout delay 977 if(canScroll && options.fitToSection){ 978 //allows to scroll to an active section and 979 //if the section is already active, we prevent firing callbacks 980 if($(SECTION_ACTIVE_SEL).is(currentSection)){ 981 isResizing = true; 982 } 983 scrollPage($(SECTION_ACTIVE_SEL)); 984 985 isResizing = false; 986 } 987 }, options.fitToSectionDelay); 988 } 989 } 990 } 991 992 /** 993 * Determines whether the active section has seen in its whole or not. 994 */ 995 function isCompletelyInViewPort(movement){ 996 var top = $(SECTION_ACTIVE_SEL).position().top; 997 var bottom = top + $window.height(); 998 999 if(movement == 'up'){ 1000 return bottom >= ($window.scrollTop() + $window.height()); 1001 } 1002 return top <= $window.scrollTop(); 1003 } 1004 1005 /** 1006 * Gets the directon of the the scrolling fired by the scroll event. 1007 */ 1008 function getScrollDirection(currentScroll){ 1009 var direction = currentScroll > lastScroll ? 'down' : 'up'; 1010 1011 lastScroll = currentScroll; 1012 1013 //needed for auto-height sections to determine if we want to scroll to the top or bottom of the destination 1014 previousDestTop = currentScroll; 1015 1016 return direction; 1017 } 1018 1019 /** 1020 * Determines the way of scrolling up or down: 1021 * by 'automatically' scrolling a section or by using the default and normal scrolling. 1022 */ 1023 function scrolling(type, scrollable){ 1024 if (!isScrollAllowed.m[type]){ 1025 return; 1026 } 1027 var check, scrollSection; 1028 1029 if(type == 'down'){ 1030 check = 'bottom'; 1031 scrollSection = FP.moveSectionDown; 1032 }else{ 1033 check = 'top'; 1034 scrollSection = FP.moveSectionUp; 1035 } 1036 1037 if(scrollable.length > 0 ){ 1038 //is the scrollbar at the start/end of the scroll? 1039 if(options.scrollOverflowHandler.isScrolled(check, scrollable)){ 1040 scrollSection(); 1041 }else{ 1042 return true; 1043 } 1044 }else{ 1045 // moved up/down 1046 scrollSection(); 1047 } 1048 } 1049 1050 1051 var touchStartY = 0; 1052 var touchStartX = 0; 1053 var touchEndY = 0; 1054 var touchEndX = 0; 1055 1056 /* Detecting touch events 1057 1058 * As we are changing the top property of the page on scrolling, we can not use the traditional way to detect it. 1059 * This way, the touchstart and the touch moves shows an small difference between them which is the 1060 * used one to determine the direction. 1061 */ 1062 function touchMoveHandler(event){ 1063 var e = event.originalEvent; 1064 1065 // additional: if one of the normalScrollElements isn't within options.normalScrollElementTouchThreshold hops up the DOM chain 1066 if (!checkParentForNormalScrollElement(event.target) && isReallyTouch(e) ) { 1067 1068 if(options.autoScrolling){ 1069 //preventing the easing on iOS devices 1070 event.preventDefault(); 1071 } 1072 1073 var activeSection = $(SECTION_ACTIVE_SEL); 1074 var scrollable = options.scrollOverflowHandler.scrollable(activeSection); 1075 1076 if (canScroll && !slideMoving) { //if theres any # 1077 var touchEvents = getEventsPage(e); 1078 1079 touchEndY = touchEvents.y; 1080 touchEndX = touchEvents.x; 1081 1082 //if movement in the X axys is greater than in the Y and the currect section has slides... 1083 if (activeSection.find(SLIDES_WRAPPER_SEL).length && Math.abs(touchStartX - touchEndX) > (Math.abs(touchStartY - touchEndY))) { 1084 1085 //is the movement greater than the minimum resistance to scroll? 1086 if (Math.abs(touchStartX - touchEndX) > ($window.outerWidth() / 100 * options.touchSensitivity)) { 1087 if (touchStartX > touchEndX) { 1088 if(isScrollAllowed.m.right){ 1089 FP.moveSlideRight(); //next 1090 } 1091 } else { 1092 if(isScrollAllowed.m.left){ 1093 FP.moveSlideLeft(); //prev 1094 } 1095 } 1096 } 1097 } 1098 1099 //vertical scrolling (only when autoScrolling is enabled) 1100 else if(options.autoScrolling){ 1101 1102 //is the movement greater than the minimum resistance to scroll? 1103 if (Math.abs(touchStartY - touchEndY) > ($window.height() / 100 * options.touchSensitivity)) { 1104 if (touchStartY > touchEndY) { 1105 scrolling('down', scrollable); 1106 } else if (touchEndY > touchStartY) { 1107 scrolling('up', scrollable); 1108 } 1109 } 1110 } 1111 } 1112 } 1113 1114 } 1115 1116 /** 1117 * recursive function to loop up the parent nodes to check if one of them exists in options.normalScrollElements 1118 * Currently works well for iOS - Android might need some testing 1119 * @param {Element} el target element / jquery selector (in subsequent nodes) 1120 * @param {int} hop current hop compared to options.normalScrollElementTouchThreshold 1121 * @return {boolean} true if there is a match to options.normalScrollElements 1122 */ 1123 function checkParentForNormalScrollElement (el, hop) { 1124 hop = hop || 0; 1125 var parent = $(el).parent(); 1126 1127 if (hop < options.normalScrollElementTouchThreshold && 1128 parent.is(options.normalScrollElements) ) { 1129 return true; 1130 } else if (hop == options.normalScrollElementTouchThreshold) { 1131 return false;
1132 } else { 1133 return checkParentForNormalScrollElement(parent, ++hop); 1134 } 1135 } 1136 1137 /** 1138 * As IE >= 10 fires both touch and mouse events when using a mouse in a touchscreen 1139 * this way we make sure that is really a touch event what IE is detecting. 1140 */ 1141 function isReallyTouch(e){ 1142 //if is not IE || IE is detecting `touch` or `pen` 1143 return typeof e.pointerType === 'undefined' || e.pointerType != 'mouse'; 1144 } 1145 1146 /** 1147 * Handler for the touch start event. 1148 */ 1149 function touchStartHandler(event){ 1150 var e = event.originalEvent; 1151 1152 //stopping the auto scroll to adjust to a section 1153 if(options.fitToSection){ 1154 $htmlBody.stop(); 1155 } 1156 1157 if(isReallyTouch(e)){ 1158 var touchEvents = getEventsPage(e); 1159 touchStartY = touchEvents.y; 1160 touchStartX = touchEvents.x; 1161 } 1162 } 1163 1164 /** 1165 * Gets the average of the last `number` elements of the given array. 1166 */ 1167 function getAverage(elements, number){ 1168 var sum = 0; 1169 1170 //taking `number` elements from the end to make the average, if there are not enought, 1 1171 var lastElements = elements.slice(Math.max(elements.length - number, 1)); 1172 1173 for(var i = 0; i < lastElements.length; i++){ 1174 sum = sum + lastElements[i]; 1175 } 1176 1177 return Math.ceil(sum/number); 1178 } 1179 1180 /** 1181 * Detecting mousewheel scrolling 1182 * 1183 * http://blogs.sitepointstatic.com/examples/tech/mouse-wheel/index.html 1184 * http://www.sitepoint.com/html5-javascript-mouse-wheel/ 1185 */ 1186 var prevTime = new Date().getTime(); 1187 1188 function MouseWheelHandler(e) { 1189 //passive event handler 1190 var supportsPassive = false; 1191 try { 1192 var opts = Object.defineProperty({}, 'passive', { 1193 get: function() { 1194 supportsPassive = true; 1195 } 1196 }); 1197 window.addEventListener("test", null, opts); 1198 } catch (e) {} 1199 1200 supportsPassive ? { 1201 passive: true 1202 } : false; 1203 if (supportsPassive) { 1204 e.preventDefault(); 1205 passive: true; 1206 } 1207 var curTime = new Date().getTime(); 1208 var isNormalScroll = $(COMPLETELY_SEL).hasClass(NORMAL_SCROLL); 1209 1210 //autoscrolling and not zooming? 1211 if(options.autoScrolling && !controlPressed && !isNormalScroll){ 1212 // cross-browser wheel delta 1213 e = e || window.event; 1214 var value = e.wheelDelta || -e.deltaY || -e.detail; 1215 var delta = Math.max(-1, Math.min(1, value)); 1216 1217 var horizontalDetection = typeof e.wheelDeltaX !== 'undefined' || typeof e.deltaX !== 'undefined'; 1218 var isScrollingVertically = (Math.abs(e.wheelDeltaX) < Math.abs(e.wheelDelta)) || (Math.abs(e.deltaX ) < Math.abs(e.deltaY) || !horizontalDetection); 1219 1220 //Limiting the array to 150 (lets not waste memory!) 1221 if(scrollings.length > 149){ 1222 scrollings.shift(); 1223 } 1224 1225 //keeping record of the previous scrollings 1226 scrollings.push(Math.abs(value)); 1227 1228 //preventing to scroll the site on mouse wheel when scrollbar is present 1229 if(options.scrollBar){ 1230 e.preventDefault ? e.preventDefault() : e.returnValue = false; 1231 } 1232 1233 var activeSection = $(SECTION_ACTIVE_SEL); 1234 var scrollable = options.scrollOverflowHandler.scrollable(activeSection); 1235 1236 //time difference between the last scroll and the current one 1237 var timeDiff = curTime-prevTime; 1238 prevTime = curTime; 1239 1240 //haven't they scrolled in a while? 1241 //(enough to be consider a different scrolling action to scroll another section) 1242 if(timeDiff > 200){ 1243 //emptying the array, we dont care about old scrollings for our averages 1244 scrollings = []; 1245 } 1246 1247 if(canScroll){ 1248 var averageEnd = getAverage(scrollings, 10); 1249 var averageMiddle = getAverage(scrollings, 70); 1250 var isAccelerating = averageEnd >= averageMiddle; 1251 1252 //to avoid double swipes... 1253 if(isAccelerating && isScrollingVertically){ 1254 //scrolling down? 1255 if (delta < 0) { 1256 scrolling('down', scrollable); 1257 1258 //scrolling up? 1259 }else { 1260 scrolling('up', scrollable); 1261 } 1262 } 1263 } 1264 1265 return false;
1266 } 1267 1268 if(options.fitToSection){ 1269 //stopping the auto scroll to adjust to a section 1270 $htmlBody.stop(); 1271 } 1272 } 1273 1274 /** 1275 * Slides a slider to the given direction. 1276 * Optional `section` param. 1277 */ 1278 function moveSlide(direction, section){ 1279 var activeSection = typeof section === 'undefined' ? $(SECTION_ACTIVE_SEL) : section; 1280 var slides = activeSection.find(SLIDES_WRAPPER_SEL); 1281 var numSlides = slides.find(SLIDE_SEL).length; 1282 1283 // more than one slide needed and nothing should be sliding 1284 if (!slides.length || slideMoving || numSlides < 2) { 1285 return; 1286 } 1287 1288 var currentSlide = slides.find(SLIDE_ACTIVE_SEL); 1289 var destiny = null; 1290 1291 if(direction === 'prev'){ 1292 destiny = currentSlide.prev(SLIDE_SEL); 1293 }else{ 1294 destiny = currentSlide.next(SLIDE_SEL); 1295 } 1296 1297 //isn't there a next slide in the secuence? 1298 if(!destiny.length){ 1299 //respect loopHorizontal settin 1300 if (!options.loopHorizontal) return; 1301 1302 if(direction === 'prev'){ 1303 destiny = currentSlide.siblings(':last'); 1304 }else{ 1305 destiny = currentSlide.siblings(':first'); 1306 } 1307 } 1308 1309 slideMoving = true; 1310 1311 landscapeScroll(slides, destiny); 1312 } 1313 1314 /** 1315 * Maintains the active slides in the viewport 1316 * (Because he `scroll` animation might get lost with some actions, such as when using continuousVertical) 1317 */ 1318 function keepSlidesPosition(){ 1319 $(SLIDE_ACTIVE_SEL).each(function(){ 1320 silentLandscapeScroll($(this), 'internal'); 1321 }); 1322 } 1323 1324 var previousDestTop = 0; 1325 /** 1326 * Returns the destination Y position based on the scrolling direction and 1327 * the height of the section. 1328 */ 1329 function getDestinationPosition(element){ 1330 var elemPosition = element.position(); 1331 1332 //top of the desination will be at the top of the viewport 1333 var position = elemPosition.top; 1334 var isScrollingDown = elemPosition.top > previousDestTop; 1335 var sectionBottom = position - windowsHeight + element.outerHeight(); 1336 var bigSectionsDestination = options.bigSectionsDestination; 1337 1338 //is the destination element bigger than the viewport? 1339 if(element.outerHeight() > windowsHeight){ 1340 //scrolling up? 1341 if(!isScrollingDown && !bigSectionsDestination || bigSectionsDestination === 'bottom' ){ 1342 position = sectionBottom; 1343 } 1344 } 1345 1346 //sections equal or smaller than the viewport height && scrolling down? || is resizing and its in the last section 1347 else if(isScrollingDown || (isResizing && element.is(':last-child')) ){ 1348 //The bottom of the destination will be at the bottom of the viewport 1349 position = sectionBottom; 1350 } 1351 1352 /* 1353 Keeping record of the last scrolled position to determine the scrolling direction. 1354 No conventional methods can be used as the scroll bar might not be present 1355 AND the section might not be active if it is auto-height and didnt reach the middle 1356 of the viewport. 1357 */ 1358 previousDestTop = position; 1359 return position; 1360 } 1361 1362 /** 1363 * Scrolls the site to the given element and scrolls to the slide if a callback is given. 1364 */ 1365 function scrollPage(element, callback, isMovementUp){ 1366 if(typeof element === 'undefined'){ return; } //there's no element to scroll, leaving the function 1367 if(typeof element.attr('class') === 'undefined'){ return; } //there's no element to scroll, leaving the function 1368 1369 var dtop = getDestinationPosition(element); 1370 1371 //local variables 1372 var v = { 1373 element: element, 1374 callback: callback, 1375 isMovementUp: isMovementUp, 1376 dtop: dtop, 1377 yMovement: getYmovement(element), 1378 anchorLink: element.data('anchor'), 1379 sectionIndex: element.index(SECTION_SEL), 1380 activeSlide: element.find(SLIDE_ACTIVE_SEL), 1381 activeSection: $(SECTION_ACTIVE_SEL), 1382 leavingSection: $(SECTION_ACTIVE_SEL).index(SECTION_SEL) + 1, 1383 1384 //caching the value of isResizing at the momment the function is called 1385 //because it will be checked later inside a setTimeout and the value might change 1386 localIsResizing: isResizing 1387 }; 1388 1389 //quiting when destination scroll is the same as the current one 1390 if((v.activeSection.is(element) && !isResizing) || (options.scrollBar && $window.scrollTop() === v.dtop && !element.hasClass(AUTO_HEIGHT) )){ return; } 1391 1392 if(v.activeSlide.length){ 1393 var slideAnchorLink = v.activeSlide.data('anchor'); 1394 var slideIndex = v.activeSlide.index(); 1395 } 1396 1397 // If continuousVertical && we need to wrap around 1398 if (options.autoScrolling && options.continuousVertical && typeof (v.isMovementUp) !== "undefined" && 1399 ((!v.isMovementUp && v.yMovement == 'up') || // Intending to scroll down but about to go up or 1400 (v.isMovementUp && v.yMovement == 'down'))) { // intending to scroll up but about to go down 1401 1402 v = createInfiniteSections(v); 1403 } 1404 1405 //callback (onLeave) if the site is not just resizing and readjusting the slides 1406 if($.isFunction(options.onLeave) && !v.localIsResizing){ 1407 if(options.onLeave.call(v.activeSection, v.leavingSection, (v.sectionIndex + 1), v.yMovement) === false){ 1408 return; 1409 } 1410 } 1411 1412 stopMedia(v.activeSection); 1413 1414 element.addClass(ACTIVE).siblings().removeClass(ACTIVE); 1415 lazyLoad(element); 1416 options.scrollOverflowHandler.onLeave(); 1417 1418 1419 //preventing from activating the MouseWheelHandler event 1420 //more than once if the page is scrolling 1421 canScroll = false;
1422 1423 setState(slideIndex, slideAnchorLink, v.anchorLink, v.sectionIndex); 1424 1425 performMovement(v); 1426 1427 //flag to avoid callingn `scrollPage()` twice in case of using anchor links 1428 lastScrolledDestiny = v.anchorLink; 1429 1430 //avoid firing it twice (as it does also on scroll) 1431 activateMenuAndNav(v.anchorLink, v.sectionIndex); 1432 } 1433 1434 /** 1435 * Performs the movement (by CSS3 or by jQuery) 1436 */ 1437 function performMovement(v){ 1438 // using CSS3 translate functionality 1439 if (options.css3 && options.autoScrolling && !options.scrollBar) { 1440 var translate3d = 'translate3d(0px, -' + v.dtop + 'px, 0px)'; 1441 transformContainer(translate3d, true); 1442 1443 //even when the scrollingSpeed is 0 there's a little delay, which might cause the 1444 //scrollingSpeed to change in case of using silentMoveTo(); 1445 if(options.scrollingSpeed){ 1446 afterSectionLoadsId = setTimeout(function () { 1447 afterSectionLoads(v); 1448 }, options.scrollingSpeed); 1449 }else{ 1450 afterSectionLoads(v); 1451 } 1452 } 1453 1454 // using jQuery animate 1455 else{ 1456 var scrollSettings = getScrollSettings(v); 1457 1458 $(scrollSettings.element).animate( 1459 scrollSettings.options, 1460 options.scrollingSpeed, options.easing).promise().done(function () { //only one single callback in case of animating `html, body` 1461 if(options.scrollBar){ 1462 1463 /* Hack! 1464 The timeout prevents setting the most dominant section in the viewport as "active" when the user 1465 scrolled to a smaller section by using the mousewheel (auto scrolling) rather than draging the scroll bar. 1466 1467 When using scrollBar:true It seems like the scroll events still getting propagated even after the scrolling animation has finished. 1468 */ 1469 setTimeout(function(){ 1470 afterSectionLoads(v); 1471 },30); 1472 }else{ 1473 afterSectionLoads(v); 1474 } 1475 }); 1476 } 1477 } 1478 1479 /** 1480 * Gets the scrolling settings depending on the plugin autoScrolling option 1481 */ 1482 function getScrollSettings(v){ 1483 var scroll = {}; 1484 1485 if(options.autoScrolling && !options.scrollBar){ 1486 scroll.options = { 'top': -v.dtop}; 1487 scroll.element = WRAPPER_SEL; 1488 }else{ 1489 scroll.options = { 'scrollTop': v.dtop}; 1490 scroll.element = 'html, body'; 1491 } 1492 1493 return scroll; 1494 } 1495 1496 /** 1497 * Adds sections before or after the current one to create the infinite effect. 1498 */ 1499 function createInfiniteSections(v){ 1500 // Scrolling down 1501 if (!v.isMovementUp) { 1502 // Move all previous sections to after the active section 1503 $(SECTION_ACTIVE_SEL).after(v.activeSection.prevAll(SECTION_SEL).get().reverse()); 1504 } 1505 else { // Scrolling up 1506 // Move all next sections to before the active section 1507 $(SECTION_ACTIVE_SEL).before(v.activeSection.nextAll(SECTION_SEL)); 1508 } 1509 1510 // Maintain the displayed position (now that we changed the element order) 1511 silentScroll($(SECTION_ACTIVE_SEL).position().top); 1512 1513 // Maintain the active slides visible in the viewport 1514 keepSlidesPosition(); 1515 1516 // save for later the elements that still need to be reordered 1517 v.wrapAroundElements = v.activeSection; 1518 1519 // Recalculate animation variables 1520 v.dtop = v.element.position().top; 1521 v.yMovement = getYmovement(v.element); 1522 1523 return v; 1524 } 1525 1526 /** 1527 * Fix section order after continuousVertical changes have been animated 1528 */ 1529 function continuousVerticalFixSectionOrder (v) {
1530 // If continuousVertical is in effect (and autoScrolling would also be in effect then), 1531 // finish moving the elements around so the direct navigation will function more simply 1532 if (!v.wrapAroundElements || !v.wrapAroundElements.length) { 1533 return; 1534 } 1535 1536 if (v.isMovementUp) { 1537 $(SECTION_FIRST_SEL).before(v.wrapAroundElements); 1538 } 1539 else { 1540 $(SECTION_LAST_SEL).after(v.wrapAroundElements); 1541 } 1542 1543 silentScroll($(SECTION_ACTIVE_SEL).position().top); 1544 1545 // Maintain the active slides visible in the viewport 1546 keepSlidesPosition(); 1547 } 1548 1549 1550 /** 1551 * Actions to do once the section is loaded. 1552 */ 1553 function afterSectionLoads (v){ 1554 continuousVerticalFixSectionOrder(v); 1555 1556 //callback (afterLoad) if the site is not just resizing and readjusting the slides 1557 $.isFunction(options.afterLoad) && !v.localIsResizing && options.afterLoad.call(v.element, v.anchorLink, (v.sectionIndex + 1)); 1558 options.scrollOverflowHandler.afterLoad(); 1559 1560 playMedia(v.element); 1561 v.element.addClass(COMPLETELY).siblings().removeClass(COMPLETELY); 1562 1563 canScroll = true; 1564 1565 $.isFunction(v.callback) && v.callback.call(this); 1566 } 1567 1568 /** 1569 * Lazy loads image, video and audio elements. 1570 */ 1571 function lazyLoad(destiny){ 1572 var destiny = getSlideOrSection(destiny); 1573 1574 destiny.find('img[data-src], source[data-src], audio[data-src], iframe[data-src]').each(function(){ 1575 $(this).attr('src', $(this).data('src')); 1576 $(this).removeAttr('data-src'); 1577 1578 if($(this).is('source')){ 1579 $(this).closest('video').get(0).load(); 1580 } 1581 }); 1582 } 1583 1584 /** 1585 * Plays video and audio elements. 1586 */ 1587 function playMedia(destiny){ 1588 var destiny = getSlideOrSection(destiny); 1589 1590 //playing HTML5 media elements 1591 destiny.find('video, audio').each(function(){ 1592 var element = $(this).get(0); 1593 1594 if( element.hasAttribute('data-autoplay') && typeof element.play === 'function' ) { 1595 element.play(); 1596 } 1597 }); 1598 1599 //youtube videos 1600 destiny.find('iframe[src*="youtube.com/embed/"]').each(function(){ 1601 var element = $(this).get(0); 1602 1603 if( /youtube\.com\/embed\//.test($(this).attr('src')) && element.hasAttribute('data-autoplay')){ 1604 element.contentWindow.postMessage('{"event":"command","func":"playVideo","args":""}', '*'); 1605 } 1606 }); 1607 } 1608 1609 /** 1610 * Stops video and audio elements. 1611 */ 1612 function stopMedia(destiny){ 1613 var destiny = getSlideOrSection(destiny); 1614 1615 //stopping HTML5 media elements 1616 destiny.find('video, audio').each(function(){ 1617 var element = $(this).get(0); 1618 1619 if( !element.hasAttribute('data-keepplaying') && typeof element.pause === 'function' ) { 1620 element.pause(); 1621 } 1622 }); 1623 1624 //youtube videos 1625 destiny.find('iframe[src*="youtube.com/embed/"]').each(function(){ 1626 var element = $(this).get(0); 1627 1628 if( /youtube\.com\/embed\//.test($(this).attr('src')) && !element.hasAttribute('data-keepplaying')){ 1629 $(this).get(0).contentWindow.postMessage('{"event":"command","func":"pauseVideo","args":""}','*'); 1630 } 1631 }); 1632 } 1633 1634 /** 1635 * Gets the active slide (or section) for the given section 1636 */ 1637 function getSlideOrSection(destiny){ 1638 var slide = destiny.find(SLIDE_ACTIVE_SEL); 1639 if( slide.length ) { 1640 destiny = $(slide); 1641 } 1642 1643 return destiny; 1644 } 1645 1646 /** 1647 * Scrolls to the anchor in the URL when loading the site 1648 */ 1649 function scrollToAnchor(){
1650 //getting the anchor link in the URL and deleting the `#` 1651 var value = window.location.hash.replace('#', '').split('/'); 1652 var section = decodeURIComponent(value[0]); 1653 var slide = decodeURIComponent(value[1]); 1654 1655 if(section){ //if theres any # 1656 if(options.animateAnchor){ 1657 scrollPageAndSlide(section, slide); 1658 }else{ 1659 FP.silentMoveTo(section, slide); 1660 } 1661 } 1662 } 1663 1664 /** 1665 * Detecting any change on the URL to scroll to the given anchor link 1666 * (a way to detect back history button as we play with the hashes on the URL) 1667 */ 1668 function hashChangeHandler(){ 1669 if(!isScrolling && !options.lockAnchors){ 1670 var value = window.location.hash.replace('#', '').split('/'); 1671 var section = decodeURIComponent(value[0]); 1672 var slide = decodeURIComponent(value[1]); 1673 1674 //when moving to a slide in the first section for the first time (first time to add an anchor to the URL) 1675 var isFirstSlideMove = (typeof lastScrolledDestiny === 'undefined'); 1676 var isFirstScrollMove = (typeof lastScrolledDestiny === 'undefined' && typeof slide === 'undefined' && !slideMoving); 1677 1678 1679 if(section.length){ 1680 /*in order to call scrollpage() only once for each destination at a time 1681 It is called twice for each scroll otherwise, as in case of using anchorlinks `hashChange` 1682 event is fired on every scroll too.*/ 1683 if ((section && section !== lastScrolledDestiny) && !isFirstSlideMove || isFirstScrollMove || (!slideMoving && lastScrolledSlide != slide )) { 1684 scrollPageAndSlide(section, slide); 1685 } 1686 } 1687 } 1688 } 1689 1690 //Sliding with arrow keys, both, vertical and horizontal 1691 function keydownHandler(e) { 1692 1693 clearTimeout(keydownId); 1694 1695 var activeElement = $(':focus'); 1696 1697 if(!activeElement.is('textarea') && !activeElement.is('input') && !activeElement.is('select') && 1698 activeElement.attr('contentEditable') !== "true" && activeElement.attr('contentEditable') !== '' && 1699 options.keyboardScrolling && options.autoScrolling){ 1700 var keyCode = e.which; 1701 1702 //preventing the scroll with arrow keys & spacebar & Page Up & Down keys 1703 var keyControls = [40, 38, 32, 33, 34]; 1704 if($.inArray(keyCode, keyControls) > -1){ 1705 e.preventDefault(); 1706 } 1707 1708 controlPressed = e.ctrlKey; 1709 1710 keydownId = setTimeout(function(){ 1711 onkeydown(e); 1712 },150); 1713 } 1714 } 1715 1716 function tooltipTextHandler(){ 1717 $(this).prev().trigger('click'); 1718 } 1719 1720 //to prevent scrolling while zooming 1721 function keyUpHandler(e){ 1722 if(isWindowFocused){ //the keyup gets fired on new tab ctrl + t in Firefox 1723 controlPressed = e.ctrlKey; 1724 } 1725 } 1726 1727 //binding the mousemove when the mouse's middle button is released 1728 function mouseDownHandler(e){ 1729 //middle button 1730 if (e.which == 2){ 1731 oldPageY = e.pageY; 1732 container.on('mousemove', mouseMoveHandler); 1733 } 1734 } 1735 1736 //unbinding the mousemove when the mouse's middle button is released 1737 function mouseUpHandler(e){ 1738 //middle button 1739 if (e.which == 2){ 1740 container.off('mousemove'); 1741 } 1742 } 1743 1744 //Scrolling horizontally when clicking on the slider controls. 1745 function slideArrowHandler(){ 1746 var section = $(this).closest(SECTION_SEL); 1747 1748 if ($(this).hasClass(SLIDES_PREV)) { 1749 if(isScrollAllowed.m.left){ 1750 FP.moveSlideLeft(section); 1751 } 1752 } else { 1753 if(isScrollAllowed.m.right){ 1754 FP.moveSlideRight(section); 1755 } 1756 } 1757 } 1758 1759 //when opening a new tab (ctrl + t), `control` won't be pressed when comming back. 1760 function blurHandler(){ 1761 isWindowFocused = false;
1762 controlPressed = false; 1763 } 1764 1765 //Scrolls to the section when clicking the navigation bullet 1766 function sectionBulletHandler(e){ 1767 e.preventDefault(); 1768 var index = $(this).parent().index(); 1769 scrollPage($(SECTION_SEL).eq(index)); 1770 } 1771 1772 //Scrolls the slider to the given slide destination for the given section 1773 function slideBulletHandler(e){ 1774 e.preventDefault(); 1775 var slides = $(this).closest(SECTION_SEL).find(SLIDES_WRAPPER_SEL); 1776 var destiny = slides.find(SLIDE_SEL).eq($(this).closest('li').index()); 1777 1778 landscapeScroll(slides, destiny); 1779 } 1780 1781 /** 1782 * Keydown event 1783 */ 1784 function onkeydown(e){ 1785 var shiftPressed = e.shiftKey; 1786 1787 switch (e.which) { 1788 //up 1789 case 38: 1790 case 33: 1791 if(isScrollAllowed.k.up){ 1792 FP.moveSectionUp(); 1793 } 1794 break; 1795 1796 //down 1797 case 32: //spacebar 1798 if(shiftPressed && isScrollAllowed.k.up){ 1799 FP.moveSectionUp(); 1800 break; 1801 } 1802 case 40: 1803 case 34: 1804 if(isScrollAllowed.k.down){ 1805 FP.moveSectionDown(); 1806 } 1807 break; 1808 1809 //Home 1810 case 36: 1811 if(isScrollAllowed.k.up){ 1812 FP.moveTo(1); 1813 } 1814 break; 1815 1816 //End 1817 case 35: 1818 if(isScrollAllowed.k.down){ 1819 FP.moveTo( $(SECTION_SEL).length ); 1820 } 1821 break; 1822 1823 //left 1824 case 37: 1825 if(isScrollAllowed.k.left){ 1826 FP.moveSlideLeft(); 1827 } 1828 break; 1829 1830 //right 1831 case 39: 1832 if(isScrollAllowed.k.right){ 1833 FP.moveSlideRight(); 1834 } 1835 break; 1836 1837 default: 1838 return; // exit this handler for other keys 1839 } 1840 } 1841 1842 /** 1843 * Detecting the direction of the mouse movement. 1844 * Used only for the middle button of the mouse. 1845 */ 1846 var oldPageY = 0; 1847 function mouseMoveHandler(e){ 1848 if(canScroll){ 1849 // moving up 1850 if (e.pageY < oldPageY && isScrollAllowed.m.up){ 1851 FP.moveSectionUp(); 1852 } 1853 1854 // moving down 1855 else if(e.pageY > oldPageY && isScrollAllowed.m.down){ 1856 FP.moveSectionDown(); 1857 } 1858 } 1859 oldPageY = e.pageY; 1860 } 1861 1862 /** 1863 * Scrolls horizontal sliders. 1864 */ 1865 function landscapeScroll(slides, destiny){ 1866 var destinyPos = destiny.position(); 1867 var slideIndex = destiny.index(); 1868 var section = slides.closest(SECTION_SEL); 1869 var sectionIndex = section.index(SECTION_SEL); 1870 var anchorLink = section.data('anchor'); 1871 var slidesNav = section.find(SLIDES_NAV_SEL); 1872 var slideAnchor = getAnchor(destiny); 1873 var prevSlide = section.find(SLIDE_ACTIVE_SEL); 1874 1875 //caching the value of isResizing at the momment the function is called 1876 //because it will be checked later inside a setTimeout and the value might change 1877 var localIsResizing = isResizing; 1878 1879 if(options.onSlideLeave){ 1880 var prevSlideIndex = prevSlide.index(); 1881 var xMovement = getXmovement(prevSlideIndex, slideIndex); 1882 1883 //if the site is not just resizing and readjusting the slides 1884 if(!localIsResizing && xMovement!=='none'){ 1885 if($.isFunction( options.onSlideLeave )){ 1886 if(options.onSlideLeave.call( prevSlide, anchorLink, (sectionIndex + 1), prevSlideIndex, xMovement, slideIndex ) === false){ 1887 slideMoving = false;
1888 return; 1889 } 1890 } 1891 } 1892 } 1893 stopMedia(prevSlide); 1894 1895 destiny.addClass(ACTIVE).siblings().removeClass(ACTIVE); 1896 if(!localIsResizing){ 1897 lazyLoad(destiny); 1898 } 1899 1900 if(!options.loopHorizontal && options.controlArrows){ 1901 //hidding it for the fist slide, showing for the rest 1902 section.find(SLIDES_ARROW_PREV_SEL).toggle(slideIndex!==0); 1903 1904 //hidding it for the last slide, showing for the rest 1905 section.find(SLIDES_ARROW_NEXT_SEL).toggle(!destiny.is(':last-child')); 1906 } 1907 1908 //only changing the URL if the slides are in the current section (not for resize re-adjusting) 1909 if(section.hasClass(ACTIVE)){ 1910 setState(slideIndex, slideAnchor, anchorLink, sectionIndex); 1911 } 1912 1913 var afterSlideLoads = function(){ 1914 //if the site is not just resizing and readjusting the slides 1915 if(!localIsResizing){ 1916 $.isFunction( options.afterSlideLoad ) && options.afterSlideLoad.call( destiny, anchorLink, (sectionIndex + 1), slideAnchor, slideIndex); 1917 } 1918 playMedia(destiny); 1919 1920 //letting them slide again 1921 slideMoving = false; 1922 }; 1923 1924 /*if(options.css3){ 1925 var translate3d = 'translate3d(-' + Math.round(destinyPos.left) + 'px, 0px, 0px)'; 1926 1927 addAnimation(slides.find(SLIDES_CONTAINER_SEL), options.scrollingSpeed>0).css(getTransforms(translate3d)); 1928 1929 afterSlideLoadsId = setTimeout(function(){ 1930 afterSlideLoads(); 1931 }, options.scrollingSpeed, options.easing); 1932 }*/ 1933 if (options.css3) { 1934 var translate3d = 'translate3d(-' + Math.round(destinyPos.left) + 'px, 0px, 0px)'; 1935 setTimeout(function() { 1936 destiny.addClass(ACTIVE).siblings().removeClass(ACTIVE); 1937 destiny.siblings().removeClass('is-leaving'); 1938 slides.find(SLIDES_CONTAINER_SEL).css(getTransforms(translate3d)); 1939 }, 800); 1940 setTimeout(function() { 1941 afterSlideLoads(); 1942 }, options.scrollingSpeed, options.easing); 1943 }else{ 1944 slides.animate({ 1945 scrollLeft : Math.round(destinyPos.left) 1946 }, options.scrollingSpeed, options.easing, function() { 1947 1948 afterSlideLoads(); 1949 }); 1950 } 1951 1952 slidesNav.find(ACTIVE_SEL).removeClass(ACTIVE); 1953 slidesNav.find('li').eq(slideIndex).find('a').addClass(ACTIVE); 1954 } 1955 1956 var previousHeight = windowsHeight; 1957 1958 //when resizing the site, we adjust the heights of the sections, slimScroll... 1959 function resizeHandler(){ 1960 //checking if it needs to get responsive 1961 responsive(); 1962 1963 // rebuild immediately on touch devices 1964 if (isTouchDevice) { 1965 var activeElement = $(document.activeElement); 1966 1967 //if the keyboard is NOT visible 1968 if (!activeElement.is('textarea') && !activeElement.is('input') && !activeElement.is('select')) { 1969 var currentHeight = $window.height(); 1970 1971 //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) 1972 if( Math.abs(currentHeight - previousHeight) > (20 * Math.max(previousHeight, currentHeight) / 100) ){ 1973 FP.reBuild(true); 1974 previousHeight = currentHeight; 1975 } 1976 } 1977 }else{ 1978 //in order to call the functions only when the resize is finished 1979 //http://stackoverflow.com/questions/4298612/jquery-how-to-call-resize-event-only-once-its-finished-resizing 1980 clearTimeout(resizeId); 1981 1982 resizeId = setTimeout(function(){ 1983 FP.reBuild(true); 1984 }, 350); 1985 } 1986 } 1987 1988 /** 1989 * Checks if the site needs to get responsive and disables autoScrolling if so. 1990 * A class `fp-responsive` is added to the plugin's container in case the user wants to use it for his own responsive CSS. 1991 */ 1992 function responsive(){ 1993 var widthLimit = options.responsive || options.responsiveWidth; //backwards compatiblity 1994 var heightLimit = options.responsiveHeight; 1995 1996 //only calculating what we need. Remember its called on the resize event. 1997 var isBreakingPointWidth = widthLimit && $window.outerWidth() < widthLimit; 1998 var isBreakingPointHeight = heightLimit && $window.height() < heightLimit; 1999 2000 if(widthLimit && heightLimit){ 2001 FP.setResponsive(isBreakingPointWidth || isBreakingPointHeight); 2002 } 2003 else if(widthLimit){ 2004 FP.setResponsive(isBreakingPointWidth); 2005 } 2006 else if(heightLimit){ 2007 FP.setResponsive(isBreakingPointHeight); 2008 } 2009 } 2010 2011 /** 2012 * Adds transition animations for the given element 2013 */ 2014 function addAnimation(element){ 2015 var transition = 'all ' + options.scrollingSpeed + 'ms ' + options.easingcss3; 2016 2017 element.removeClass(NO_TRANSITION); 2018 return element.css({
2019 '-webkit-transition': transition, 2020 'transition': transition 2021 }); 2022 } 2023 2024 /** 2025 * Remove transition animations for the given element 2026 */ 2027 function removeAnimation(element){ 2028 return element.addClass(NO_TRANSITION); 2029 } 2030 2031 /** 2032 * Activating the website navigation dots according to the given slide name. 2033 */ 2034 function activateNavDots(name, sectionIndex){ 2035 if(options.navigation){ 2036 $(SECTION_NAV_SEL).find(ACTIVE_SEL).removeClass(ACTIVE); 2037 if(name){ 2038 $(SECTION_NAV_SEL).find('a[href="#' + name + '"]').addClass(ACTIVE); 2039 }else{ 2040 $(SECTION_NAV_SEL).find('li').eq(sectionIndex).find('a').addClass(ACTIVE); 2041 } 2042 } 2043 } 2044 2045 /** 2046 * Activating the website main menu elements according to the given slide name. 2047 */ 2048 function activateMenuElement(name){ 2049 if(options.menu){ 2050 $(options.menu).find(ACTIVE_SEL).removeClass(ACTIVE); 2051 $(options.menu).find('[data-menuanchor="'+name+'"]').addClass(ACTIVE); 2052 } 2053 } 2054 2055 /** 2056 * Sets to active the current menu and vertical nav items. 2057 */ 2058 function activateMenuAndNav(anchor, index){ 2059 activateMenuElement(anchor); 2060 activateNavDots(anchor, index); 2061 } 2062 2063 /** 2064 * Retuns `up` or `down` depending on the scrolling movement to reach its destination 2065 * from the current section. 2066 */ 2067 function getYmovement(destiny){ 2068 var fromIndex = $(SECTION_ACTIVE_SEL).index(SECTION_SEL); 2069 var toIndex = destiny.index(SECTION_SEL); 2070 if( fromIndex == toIndex){ 2071 return 'none'; 2072 } 2073 if(fromIndex > toIndex){ 2074 return 'up'; 2075 } 2076 return 'down'; 2077 } 2078 2079 /** 2080 * Retuns `right` or `left` depending on the scrolling movement to reach its destination 2081 * from the current slide. 2082 */ 2083 function getXmovement(fromIndex, toIndex){ 2084 if( fromIndex == toIndex){ 2085 return 'none'; 2086 } 2087 if(fromIndex > toIndex){ 2088 return 'left'; 2089 } 2090 return 'right'; 2091 } 2092 2093 /** 2094 * Checks if the element needs scrollbar and if the user wants to apply it. 2095 * If so it creates it. 2096 * 2097 * @param {Object} element jQuery object of the section or slide 2098 */ 2099 function createSlimScrolling(element){ 2100 //User doesn't want scrollbar here? Sayonara baby! 2101 if(element.hasClass('fp-noscroll')) return; 2102 2103 //needed to make `scrollHeight` work under Opera 12 2104 element.css('overflow', 'hidden'); 2105 2106 var scrollOverflowHandler = options.scrollOverflowHandler; 2107 var wrap = scrollOverflowHandler.wrapContent(); 2108 //in case element is a slide 2109 var section = element.closest(SECTION_SEL); 2110 var scrollable = scrollOverflowHandler.scrollable(element); 2111 var contentHeight; 2112 2113 //if there was scroll, the contentHeight will be the one in the scrollable section 2114 if(scrollable.length){ 2115 contentHeight = scrollOverflowHandler.scrollHeight(element); 2116 }else{ 2117 contentHeight = element.get(0).scrollHeight; 2118 if(options.verticalCentered){ 2119 contentHeight = element.find(TABLE_CELL_SEL).get(0).scrollHeight; 2120 } 2121 } 2122 2123 var scrollHeight = windowsHeight - parseInt(section.css('padding-bottom')) - parseInt(section.css('padding-top')); 2124 2125 //needs scroll? 2126 if ( contentHeight > scrollHeight) { 2127 //did we already have an scrollbar ? Updating it 2128 if(scrollable.length){ 2129 scrollOverflowHandler.update(element, scrollHeight); 2130 } 2131 //creating the scrolling 2132 else{ 2133 if(options.verticalCentered){ 2134 element.find(TABLE_CELL_SEL).wrapInner(wrap); 2135 }else{ 2136 element.wrapInner(wrap); 2137 } 2138 scrollOverflowHandler.create(element, scrollHeight); 2139 } 2140 } 2141 //removing the scrolling when it is not necessary anymore 2142 else{ 2143 scrollOverflowHandler.remove(element); 2144 } 2145 2146 //undo 2147 element.css('overflow', ''); 2148 } 2149 2150 function addTableClass(element){ 2151 element.addClass(TABLE).wrapInner('<div class="' + TABLE_CELL + '" style="height:' + getTableHeight(element) + 'px;" />'); 2152 } 2153 2154 function getTableHeight(element){ 2155 var sectionHeight = windowsHeight; 2156 2157 if(options.paddingTop || options.paddingBottom){ 2158 var section = element; 2159 if(!section.hasClass(SECTION)){ 2160 section = element.closest(SECTION_SEL); 2161 } 2162 2163 var paddings = parseInt(section.css('padding-top')) + parseInt(section.css('padding-bottom')); 2164 sectionHeight = (windowsHeight - paddings); 2165 } 2166 2167 return sectionHeight; 2168 } 2169 2170 /** 2171 * Adds a css3 transform property to the container class with or without animation depending on the animated param. 2172 */ 2173 function transformContainer(translate3d, animated){ 2174 if(animated){ 2175 addAnimation(container); 2176 }else{ 2177 removeAnimation(container); 2178 } 2179 2180 container.css(getTransforms(translate3d)); 2181 2182 //syncronously removing the class after the animation has been applied. 2183 setTimeout(function(){ 2184 container.removeClass(NO_TRANSITION); 2185 },10); 2186 } 2187 2188 /** 2189 * Gets a section by its anchor / index 2190 */ 2191 function getSectionByAnchor(sectionAnchor){ 2192 //section 2193 var section = container.find(SECTION_SEL + '[data-anchor="'+sectionAnchor+'"]'); 2194 if(!section.length){ 2195 section = $(SECTION_SEL).eq( (sectionAnchor -1) ); 2196 } 2197 2198 return section; 2199 } 2200 2201 /** 2202 * Gets a slide inside a given section by its anchor / index 2203 */ 2204 function getSlideByAnchor(slideAnchor, section){ 2205 var slides = section.find(SLIDES_WRAPPER_SEL); 2206 var slide = slides.find(SLIDE_SEL + '[data-anchor="'+slideAnchor+'"]'); 2207
2208 if(!slide.length){ 2209 slide = slides.find(SLIDE_SEL).eq(slideAnchor); 2210 } 2211 2212 return slide; 2213 } 2214 2215 /** 2216 * Scrolls to the given section and slide anchors 2217 */ 2218 function scrollPageAndSlide(destiny, slide){ 2219 var section = getSectionByAnchor(destiny); 2220 2221 //default slide 2222 if (typeof slide === 'undefined') { 2223 slide = 0; 2224 } 2225 2226 //we need to scroll to the section and then to the slide 2227 if (destiny !== lastScrolledDestiny && !section.hasClass(ACTIVE)){ 2228 scrollPage(section, function(){ 2229 scrollSlider(section, slide); 2230 }); 2231 } 2232 //if we were already in the section 2233 else{ 2234 scrollSlider(section, slide); 2235 } 2236 } 2237 2238 /** 2239 * Scrolls the slider to the given slide destination for the given section 2240 */ 2241 function scrollSlider(section, slideAnchor){ 2242 if(typeof slideAnchor !== 'undefined'){ 2243 var slides = section.find(SLIDES_WRAPPER_SEL); 2244 var destiny = getSlideByAnchor(slideAnchor, section); 2245 2246 if(destiny.length){ 2247 landscapeScroll(slides, destiny); 2248 } 2249 } 2250 } 2251 2252 $.fn.fullpage.scrollDefault = function(section, slideAnchor) { 2253 var section = getSectionByAnchor(section); 2254 if (typeof slideAnchor !== 'undefined') { 2255 var slides = section.find(SLIDES_WRAPPER_SEL); 2256 var destiny = getSlideByAnchor(slideAnchor, section); 2257 if (destiny.length) { 2258 landscapeScroll(slides, destiny); 2259 } 2260 } 2261 2262 } 2263 2264 /** 2265 * Creates a landscape navigation bar with dots for horizontal sliders. 2266 */ 2267 function addSlidesNavigation(section, numSlides){ 2268 section.append('<div class="' + SLIDES_NAV + '"><ul></ul></div>'); 2269 var nav = section.find(SLIDES_NAV_SEL); 2270 2271 //top or bottom 2272 nav.addClass(options.slidesNavPosition); 2273 2274 for(var i=0; i< numSlides; i++){ 2275 nav.find('ul').append('<li><a href="#"><span></span></a></li>'); 2276 } 2277 2278 //centering it 2279 nav.css('margin-left', '-' + (nav.width()/2) + 'px'); 2280 2281 nav.find('li').first().find('a').addClass(ACTIVE); 2282 } 2283 2284 2285 /** 2286 * Sets the state of the website depending on the active section/slide. 2287 * It changes the URL hash when needed and updates the body class. 2288 */ 2289 function setState(slideIndex, slideAnchor, anchorLink, sectionIndex){ 2290 var sectionHash = ''; 2291 2292 if(options.anchors.length && !options.lockAnchors){ 2293 2294 //isn't it the first slide? 2295 if(slideIndex){ 2296 if(typeof anchorLink !== 'undefined'){ 2297 sectionHash = anchorLink; 2298 } 2299 2300 //slide without anchor link? We take the index instead. 2301 if(typeof slideAnchor === 'undefined'){ 2302 slideAnchor = slideIndex; 2303 } 2304 2305 lastScrolledSlide = slideAnchor; 2306 setUrlHash(sectionHash + '/' + slideAnchor); 2307 2308 //first slide won't have slide anchor, just the section one 2309 }else if(typeof slideIndex !== 'undefined'){ 2310 lastScrolledSlide = slideAnchor; 2311 setUrlHash(anchorLink); 2312 } 2313 2314 //section without slides 2315 else{ 2316 setUrlHash(anchorLink); 2317 } 2318 } 2319 2320 setBodyClass(); 2321 } 2322 2323 /** 2324 * Sets the URL hash. 2325 */ 2326 function setUrlHash(url){ 2327 if(options.recordHistory){ 2328 location.hash = url; 2329 }else{ 2330 //Mobile Chrome doesn't work the normal way, so... lets use HTML5 for phones :) 2331 if(isTouchDevice || isTouch){ 2332 window.history.replaceState(undefined, undefined, '#' + url); 2333 }else{ 2334 var baseUrl = window.location.href.split('#')[0]; 2335 window.location.replace( baseUrl + '#' + url ); 2336 } 2337 } 2338 } 2339 2340 /**
2341 * Gets the anchor for the given slide / section. Its index will be used if there's none. 2342 */ 2343 function getAnchor(element){ 2344 var anchor = element.data('anchor'); 2345 var index = element.index(); 2346 2347 //Slide without anchor link? We take the index instead. 2348 if(typeof anchor === 'undefined'){ 2349 anchor = index; 2350 } 2351 2352 return anchor; 2353 } 2354 2355 /** 2356 * Sets a class for the body of the page depending on the active section / slide 2357 */ 2358 function setBodyClass(){ 2359 var section = $(SECTION_ACTIVE_SEL); 2360 var slide = section.find(SLIDE_ACTIVE_SEL); 2361 2362 var sectionAnchor = getAnchor(section); 2363 var slideAnchor = getAnchor(slide); 2364 2365 var text = String(sectionAnchor); 2366 2367 if(slide.length){ 2368 text = text + '-' + slideAnchor; 2369 } 2370 2371 //changing slash for dash to make it a valid CSS style 2372 text = text.replace('/', '-').replace('#',''); 2373 2374 //removing previous anchor classes 2375 var classRe = new RegExp('\\b\\s?' + VIEWING_PREFIX + '-[^\\s]+\\b', "g"); 2376 $body[0].className = $body[0].className.replace(classRe, ''); 2377 2378 //adding the current anchor 2379 $body.addClass(VIEWING_PREFIX + '-' + text); 2380 } 2381 2382 /** 2383 * Checks for translate3d support 2384 * @return boolean 2385 * http://stackoverflow.com/questions/5661671/detecting-transform-translate3d-support 2386 */ 2387 function support3d() { 2388 var el = document.createElement('p'), 2389 has3d, 2390 transforms = { 2391 'webkitTransform':'-webkit-transform', 2392 'OTransform':'-o-transform', 2393 'msTransform':'-ms-transform', 2394 'MozTransform':'-moz-transform', 2395 'transform':'transform' 2396 }; 2397 2398 // Add it to the body to get the computed style. 2399 document.body.insertBefore(el, null); 2400 2401 for (var t in transforms) { 2402 if (el.style[t] !== undefined) { 2403 el.style[t] = 'translate3d(1px,1px,1px)'; 2404 has3d = window.getComputedStyle(el).getPropertyValue(transforms[t]); 2405 } 2406 } 2407 2408 document.body.removeChild(el); 2409 2410 return (has3d !== undefined && has3d.length > 0 && has3d !== 'none'); 2411 } 2412 2413 /** 2414 * Removes the auto scrolling action fired by the mouse wheel and trackpad. 2415 * After this function is called, the mousewheel and trackpad movements won't scroll through sections. 2416 */ 2417 function removeMouseWheelHandler(){ 2418 if (document.addEventListener) { 2419 document.removeEventListener('mousewheel', MouseWheelHandler, false); //IE9, Chrome, Safari, Oper 2420 document.removeEventListener('wheel', MouseWheelHandler, false); //Firefox 2421 document.removeEventListener('MozMousePixelScroll', MouseWheelHandler, false); //old Firefox 2422 } else { 2423 document.detachEvent('onmousewheel', MouseWheelHandler); //IE 6/7/8 2424 } 2425 } 2426 2427 /** 2428 * Adds the auto scrolling action for the mouse wheel and trackpad. 2429 * After this function is called, the mousewheel and trackpad movements will scroll through sections 2430 * https://developer.mozilla.org/en-US/docs/Web/Events/wheel 2431 */ 2432 function addMouseWheelHandler(){ 2433 var prefix = ''; 2434 var _addEventListener; 2435 2436 if (window.addEventListener){ 2437 _addEventListener = "addEventListener"; 2438 }else{ 2439 _addEventListener = "attachEvent"; 2440 prefix = 'on'; 2441 } 2442 2443 // detect available wheel event 2444 var support = 'onwheel' in document.createElement('div') ? 'wheel' : // Modern browsers support "wheel" 2445 document.onmousewheel !== undefined ? 'mousewheel' : // Webkit and IE support at least "mousewheel" 2446 'DOMMouseScroll'; // let's assume that remaining browsers are older Firefox 2447 2448 2449 if(support == 'DOMMouseScroll'){ 2450 document[ _addEventListener ](prefix + 'MozMousePixelScroll', MouseWheelHandler, false); 2451 } 2452 2453 //handle MozMousePixelScroll in older Firefox 2454 else{ 2455 document[ _addEventListener ](prefix + support, MouseWheelHandler, false); 2456 } 2457 } 2458 2459 /** 2460 * Binding the mousemove when the mouse's middle button is pressed 2461 */ 2462 function addMiddleWheelHandler(){ 2463 container 2464 .on('mousedown', mouseDownHandler) 2465 .on('mouseup', mouseUpHandler); 2466 } 2467 2468 /** 2469 * Unbinding the mousemove when the mouse's middle button is released 2470 */ 2471 function removeMiddleWheelHandler(){ 2472 container 2473 .off('mousedown', mouseDownHandler) 2474 .off('mouseup', mouseUpHandler); 2475 } 2476 2477 /** 2478 * Adds the possibility to auto scroll through sections on touch devices. 2479 */ 2480 function addTouchHandler(){ 2481 if(isTouchDevice || isTouch){ 2482 //Microsoft pointers 2483 var MSPointer = getMSPointer(); 2484 2485 $(WRAPPER_SEL).off('touchstart ' + MSPointer.down).on('touchstart ' + MSPointer.down, touchStartHandler); 2486 $(WRAPPER_SEL).off('touchmove ' + MSPointer.move).on('touchmove ' + MSPointer.move, touchMoveHandler); 2487 } 2488 } 2489 2490 /** 2491 * Removes the auto scrolling for touch devices. 2492 */ 2493 function removeTouchHandler(){ 2494 if(isTouchDevice || isTouch){ 2495 //Microsoft pointers 2496 var MSPointer = getMSPointer(); 2497 2498 $(WRAPPER_SEL).off('touchstart ' + MSPointer.down); 2499 $(WRAPPER_SEL).off('touchmove ' + MSPointer.move); 2500 } 2501 } 2502 2503 /* 2504 * Returns and object with Microsoft pointers (for IE<11 and for IE >= 11)
2505 * http://msdn.microsoft.com/en-us/library/ie/dn304886(v=vs.85).aspx 2506 */ 2507 function getMSPointer(){ 2508 var pointer; 2509 2510 //IE >= 11 & rest of browsers 2511 if(window.PointerEvent){ 2512 pointer = { down: 'pointerdown', move: 'pointermove'}; 2513 } 2514 2515 //IE < 11 2516 else{ 2517 pointer = { down: 'MSPointerDown', move: 'MSPointerMove'}; 2518 } 2519 2520 return pointer; 2521 } 2522 2523 /** 2524 * Gets the pageX and pageY properties depending on the browser. 2525 * https://github.com/alvarotrigo/fullPage.js/issues/194#issuecomment-34069854 2526 */ 2527 function getEventsPage(e){ 2528 var events = []; 2529 2530 events.y = (typeof e.pageY !== 'undefined' && (e.pageY || e.pageX) ? e.pageY : e.touches[0].pageY); 2531 events.x = (typeof e.pageX !== 'undefined' && (e.pageY || e.pageX) ? e.pageX : e.touches[0].pageX); 2532 2533 //in touch devices with scrollBar:true, e.pageY is detected, but we have to deal with touch events. #1008 2534 if(isTouch && isReallyTouch(e) && options.scrollBar){ 2535 events.y = e.touches[0].pageY; 2536 events.x = e.touches[0].pageX; 2537 } 2538 2539 return events; 2540 } 2541 2542 /** 2543 * Slides silently (with no animation) the active slider to the given slide. 2544 */ 2545 function silentLandscapeScroll(activeSlide, noCallbacks){ 2546 FP.setScrollingSpeed (0, 'internal'); 2547 2548 if(typeof noCallbacks !== 'undefined'){ 2549 //preventing firing callbacks afterSlideLoad etc. 2550 isResizing = true; 2551 } 2552 2553 landscapeScroll(activeSlide.closest(SLIDES_WRAPPER_SEL), activeSlide); 2554 2555 if(typeof noCallbacks !== 'undefined'){ 2556 isResizing = false; 2557 } 2558 2559 FP.setScrollingSpeed(originals.scrollingSpeed, 'internal'); 2560 } 2561 2562 /** 2563 * Scrolls silently (with no animation) the page to the given Y position. 2564 */ 2565 function silentScroll(top){ 2566 if(options.scrollBar){ 2567 container.scrollTop(top); 2568 } 2569 else if (options.css3) { 2570 var translate3d = 'translate3d(0px, -' + top + 'px, 0px)'; 2571 transformContainer(translate3d, false); 2572 } 2573 else { 2574 container.css('top', -top); 2575 } 2576 } 2577 2578 /** 2579 * Returns the cross-browser transform string. 2580 */ 2581 function getTransforms(translate3d){ 2582 return { 2583 '-webkit-transform': translate3d, 2584 '-moz-transform': translate3d, 2585 '-ms-transform':translate3d, 2586 'transform': translate3d 2587 }; 2588 } 2589 2590 /** 2591 * Allowing or disallowing the mouse/swipe scroll in a given direction. (not for keyboard) 2592 * @type m (mouse) or k (keyboard) 2593 */ 2594 function setIsScrollAllowed(value, direction, type){ 2595 switch (direction){ 2596 case 'up': isScrollAllowed[type].up = value; break; 2597 case 'down': isScrollAllowed[type].down = value; break; 2598 case 'left': isScrollAllowed[type].left = value; break; 2599 case 'right': isScrollAllowed[type].right = value; break; 2600 case 'all': 2601 if(type == 'm'){ 2602 FP.setAllowScrolling(value); 2603 }else{ 2604 FP.setKeyboardScrolling(value); 2605 } 2606 } 2607 } 2608 2609 /* 2610 * Destroys fullpage.js plugin events and optinally its html markup and styles 2611 */ 2612 FP.destroy = function(all){ 2613 FP.setAutoScrolling(false, 'internal'); 2614 FP.setAllowScrolling(false); 2615 FP.setKeyboardScrolling(false); 2616 container.addClass(DESTROYED); 2617 2618 clearTimeout(afterSlideLoadsId); 2619 clearTimeout(afterSectionLoadsId); 2620 clearTimeout(resizeId); 2621 clearTimeout(scrollId); 2622 clearTimeout(scrollId2); 2623 2624 $window 2625 .off('scroll', scrollHandler) 2626 .off('hashchange', hashChangeHandler) 2627 .off('resize', resizeHandler); 2628 2629 $document 2630 .off('click', SECTION_NAV_SEL + ' a') 2631 .off('mouseenter', SECTION_NAV_SEL + ' li') 2632 .off('mouseleave', SECTION_NAV_SEL + ' li') 2633 .off('click', SLIDES_NAV_LINK_SEL) 2634 .off('mouseover', options.normalScrollElements) 2635 .off('mouseout', options.normalScrollElements); 2636 2637 $(SECTION_SEL) 2638 .off('click', SLIDES_ARROW_SEL); 2639 2640 clearTimeout(afterSlideLoadsId); 2641 clearTimeout(afterSectionLoadsId); 2642 2643 //lets make a mess! 2644 if(all){ 2645 destroyStructure(); 2646 } 2647 }; 2648 2649 /* 2650 * Removes inline styles added by fullpage.js 2651 */ 2652 function destroyStructure(){ 2653 //reseting the `top` or `translate` properties to 0 2654 silentScroll(0); 2655 2656 //loading all the lazy load content 2657 container.find('img[data-src], source[data-src], audio[data-src], iframe[data-src]').each(function(){ 2658 $(this).attr('src', $(this).data('src')); 2659 $(this).removeAttr('data-src'); 2660 }); 2661 2662 $(SECTION_NAV_SEL + ', ' + SLIDES_NAV_SEL + ', ' + SLIDES_ARROW_SEL).remove(); 2663 2664 //removing inline styles 2665 $(SECTION_SEL).css( { 2666 'height': '', 2667 'background-color' : '', 2668 'padding': '' 2669 }); 2670 2671 $(SLIDE_SEL).css( { 2672 'width': '' 2673 }); 2674 2675 container.css({ 2676 'height': '', 2677 'position': '',
2678 '-ms-touch-action': '', 2679 'touch-action': '' 2680 }); 2681 2682 $htmlBody.css({ 2683 'overflow': '', 2684 'height': '' 2685 }); 2686 2687 // remove .fp-enabled class 2688 $('html').removeClass(ENABLED); 2689 2690 // remove .fp-responsive class 2691 $body.removeClass(RESPONSIVE); 2692 2693 // remove all of the .fp-viewing- classes 2694 $.each($body.get(0).className.split(/\s+/), function (index, className) { 2695 if (className.indexOf(VIEWING_PREFIX) === 0) { 2696 $body.removeClass(className); 2697 } 2698 }); 2699 2700 //removing added classes 2701 $(SECTION_SEL + ', ' + SLIDE_SEL).each(function(){ 2702 options.scrollOverflowHandler.remove($(this)); 2703 $(this).removeClass(TABLE + ' ' + ACTIVE); 2704 }); 2705 2706 removeAnimation(container); 2707 2708 //Unwrapping content 2709 container.find(TABLE_CELL_SEL + ', ' + SLIDES_CONTAINER_SEL + ', ' + SLIDES_WRAPPER_SEL).each(function(){ 2710 //unwrap not being use in case there's no child element inside and its just text 2711 $(this).replaceWith(this.childNodes); 2712 }); 2713 2714 //scrolling the page to the top with no animation 2715 $htmlBody.scrollTop(0); 2716 2717 //removing selectors 2718 var usedSelectors = [SECTION, SLIDE, SLIDES_CONTAINER]; 2719 $.each(usedSelectors, function(index, value){ 2720 $('.' + value).removeClass(value); 2721 }); 2722 } 2723 2724 /* 2725 * Sets the state for a variable with multiple states (original, and temporal) 2726 * Some variables such as `autoScrolling` or `recordHistory` might change automatically its state when using `responsive` or `autoScrolling:false`. 2727 * This function is used to keep track of both states, the original and the temporal one. 2728 * If type is not 'internal', then we assume the user is globally changing the variable. 2729 */ 2730 function setVariableState(variable, value, type){ 2731 options[variable] = value; 2732 if(type !== 'internal'){ 2733 originals[variable] = value; 2734 } 2735 } 2736 2737 /** 2738 * Displays warnings 2739 */ 2740 function displayWarnings(){ 2741 if($('html').hasClass(ENABLED)){ 2742 showError('error', 'Fullpage.js can only be initialized once and you are doing it multiple times!'); 2743 return; 2744 } 2745 2746 // Disable mutually exclusive settings 2747 if (options.continuousVertical && 2748 (options.loopTop || options.loopBottom)) { 2749 options.continuousVertical = false;
2750 showError('warn', 'Option `loopTop/loopBottom` is mutually exclusive with `continuousVertical`; `continuousVertical` disabled'); 2751 } 2752 2753 if(options.scrollBar && options.scrollOverflow){ 2754 showError('warn', 'Option `scrollBar` is mutually exclusive with `scrollOverflow`. Sections with scrollOverflow might not work well in Firefox'); 2755 } 2756 2757 if(options.continuousVertical && options.scrollBar){ 2758 options.continuousVertical = false; 2759 showError('warn', 'Option `scrollBar` is mutually exclusive with `continuousVertical`; `continuousVertical` disabled'); 2760 } 2761 2762 //anchors can not have the same value as any element ID or NAME 2763 $.each(options.anchors, function(index, name){ 2764 2765 //case insensitive selectors (http://stackoverflow.com/a/19465187/1081396) 2766 var nameAttr = $document.find('[name]').filter(function() { 2767 return $(this).attr('name') && $(this).attr('name').toLowerCase() == name.toLowerCase(); 2768 }); 2769 2770 var idAttr = $document.find('[id]').filter(function() { 2771 return $(this).attr('id') && $(this).attr('id').toLowerCase() == name.toLowerCase(); 2772 }); 2773 2774 if(idAttr.length || nameAttr.length ){ 2775 showError('error', 'data-anchor tags can not have the same value as any `id` element on the site (or `name` element for IE).'); 2776 idAttr.length && showError('error', '"' + name + '" is is being used by another element `id` property'); 2777 nameAttr.length && showError('error', '"' + name + '" is is being used by another element `name` property'); 2778 } 2779 }); 2780 } 2781 2782 /** 2783 * Shows a message in the console of the given type. 2784 */ 2785 function showError(type, text){ 2786 console && console[type] && console[type]('fullPage: ' + text); 2787 } 2788 }; //end of $.fn.fullpage 2789 2790 if(typeof IScroll !== 'undefined'){ 2791 /* 2792 * Turns iScroll `mousewheel` option off dynamically 2793 * https://github.com/cubiq/iscroll/issues/1036 2794 */ 2795 IScroll.prototype.wheelOn = function () { 2796 this.wrapper.addEventListener('wheel', this); 2797 this.wrapper.addEventListener('mousewheel', this); 2798 this.wrapper.addEventListener('DOMMouseScroll', this); 2799 }; 2800 2801 /* 2802 * Turns iScroll `mousewheel` option on dynamically 2803 * https://github.com/cubiq/iscroll/issues/1036 2804 */ 2805 IScroll.prototype.wheelOff = function () { 2806 this.wrapper.removeEventListener('wheel', this); 2807 this.wrapper.removeEventListener('mousewheel', this); 2808 this.wrapper.removeEventListener('DOMMouseScroll', this); 2809 }; 2810 } 2811 2812 /** 2813 * An object to handle overflow scrolling. 2814 * This uses jquery.slimScroll to accomplish overflow scrolling. 2815 * It is possible to pass in an alternate scrollOverflowHandler 2816 * to the fullpage.js option that implements the same functions 2817 * as this handler. 2818 * 2819 * @type {Object} 2820 */ 2821 var iscrollHandler = { 2822 refreshId: null, 2823 iScrollInstances: [], 2824 2825 /** 2826 * Turns off iScroll for the destination section. 2827 * When scrolling very fast on some trackpads (and Apple laptops) the inertial scrolling would 2828 * scroll the destination section/slide before the sections animations ends. 2829 */ 2830 onLeave: function(){ 2831 var scroller = $(SECTION_ACTIVE_SEL).find(SCROLLABLE_SEL).data('iscrollInstance'); 2832 if(typeof scroller !== 'undefined' && scroller){ 2833 scroller.wheelOff(); 2834 } 2835 }, 2836 2837 // Turns on iScroll on section load 2838 afterLoad: function(){ 2839 var scroller = $(SECTION_ACTIVE_SEL).find(SCROLLABLE_SEL).data('iscrollInstance'); 2840 if(typeof scroller !== 'undefined' && scroller){ 2841 scroller.wheelOn(); 2842 } 2843 }, 2844 2845 /** 2846 * Called when overflow scrolling is needed for a section. 2847 * 2848 * @param {Object}
2848 element jQuery object containing current section 2849 * @param {Number} scrollHeight Current window height in pixels 2850 */ 2851 create: function(element, scrollHeight) { 2852 var scrollable = element.find(SCROLLABLE_SEL); 2853 2854 scrollable.height(scrollHeight); 2855 scrollable.each(function() { 2856 var $this = jQuery(this); 2857 var iScrollInstance = $this.data('iscrollInstance'); 2858 if (iScrollInstance) { 2859 $.each(iscrollHandler.iScrollInstances, function(){ 2860 $(this).destroy(); 2861 }); 2862 } 2863 2864 iScrollInstance = new IScroll($this.get(0), iscrollOptions); 2865 iscrollHandler.iScrollInstances.push(iScrollInstance); 2866 $this.data('iscrollInstance', iScrollInstance); 2867 }); 2868 }, 2869 2870 /** 2871 * Return a boolean depending on whether the scrollable element is a 2872 * the end or at the start of the scrolling depending on the given type. 2873 * 2874 * @param {String} type Either 'top' or 'bottom' 2875 * @param {Object} scrollable jQuery object for the scrollable element 2876 * @return {Boolean} 2877 */ 2878 isScrolled: function(type, scrollable) { 2879 var scroller = scrollable.data('iscrollInstance'); 2880 2881 //no scroller? 2882 if (!scroller) { 2883 return true; 2884 } 2885 2886 if (type === 'top') { 2887 return scroller.y >= 0 && !scrollable.scrollTop(); 2888 } else if (type === 'bottom') { 2889 return (0 - scroller.y) + scrollable.scrollTop() + 1 + scrollable.innerHeight() >= scrollable[0].scrollHeight; 2890 } 2891 }, 2892 2893 /** 2894 * Returns the scrollable element for the given section. 2895 * If there are landscape slides, will only return a scrollable element 2896 * if it is in the active slide. 2897 * 2898 * @param {Object} activeSection jQuery object containing current section 2899 * @return {Boolean} 2900 */ 2901 scrollable: function(activeSection){ 2902 // if there are landscape slides, we check if the scrolling bar is in the current one or not 2903 if (activeSection.find(SLIDES_WRAPPER_SEL).length) { 2904 return activeSection.find(SLIDE_ACTIVE_SEL).find(SCROLLABLE_SEL); 2905 } 2906 return activeSection.find(SCROLLABLE_SEL); 2907 }, 2908 2909 /** 2910 * Returns the scroll height of the wrapped content. 2911 * If this is larger than the window height minus section padding, 2912 * overflow scrolling is needed. 2913 * 2914 * @param {Object} element jQuery object containing current section 2915 * @return {Number} 2916 */ 2917 scrollHeight: function(element) { 2918 return element.find(SCROLLABLE_SEL).children().first().get(0).scrollHeight; 2919 }, 2920 2921 /** 2922 * Called when overflow scrolling is no longer needed for a section. 2923 * 2924 * @param {Object} element jQuery object containing current section 2925 */ 2926 remove: function(element) { 2927 var scrollable = element.find(SCROLLABLE_SEL); 2928 if (scrollable.length) { 2929 var iScrollInstance = scrollable.data('iscrollInstance'); 2930 iScrollInstance.destroy(); 2931 2932 scrollable.data('iscrollInstance', null); 2933 } 2934 element.find(SCROLLABLE_SEL).children().first().children().first().unwrap().unwrap(); 2935 }, 2936 2937 /** 2938 * Called when overflow scrolling has already been setup but the 2939 * window height has potentially changed. 2940 * 2941 * @param {Object} element jQuery object containing current section 2942 * @param {Number} scrollHeight Current window height in pixels 2943 */ 2944 update: function(element, scrollHeight) { 2945 //using a timeout in order to execute the refresh function only once when `update` is called multiple times in a 2946 //short period of time. 2947 //it also comes on handy because iScroll requires the use of timeout when using `refresh`. 2948 clearTimeout(iscrollHandler.refreshId); 2949 iscrollHandler.refreshId = setTimeout(function(){ 2950 $.each(iscrollHandler.iScrollInstances, function(){ 2951 $(this).get(0).refresh(); 2952 }); 2953 }, 150); 2954 2955 //updating the wrappers height 2956 element.find(SCROLLABLE_SEL).css('height', scrollHeight + 'px').parent().css('height', scrollHeight + 'px'); 2957 }, 2958 2959 /** 2960 * Called to get any additional elements needed to wrap the section 2961 * content in order to facilitate overflow scrolling. 2962 * 2963 * @return {String|Object} Can be a string containing HTML, 2964 * a DOM element, or jQuery object. 2965 */ 2966 wrapContent: function() { 2967 return '<div class="' + SCROLLABLE + '"><div class="fp-scroller"></div></div>'; 2968 } 2969 }; 2970 2971});
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.