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