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