122 | fullPage.js callbacks allow you to create amazing dynamic sites with a bit of imagination. This example tries to reproduce the Apple iPhone-5c website animations as an example of what fullPage.js is capable of.
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
Amazing stuff
137 | Combining fullPage.js with your own CSS styles and animations, you will be able to create something remarkable.
138 |
139 |
140 |
141 |
142 |
143 |
144 |
Just a demo
145 | This is, of course, just a demo. I didn't want to spend much time on it.
146 | Don't expect it to work perfectly in all kind of screens.
147 | It has been designed to work on 1180px width or over on modern browsers with CSS3.
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
--------------------------------------------------------------------------------
/fullPage.js/js/jquery.fullPage.js:
--------------------------------------------------------------------------------
1 | /**
2 | * fullPage 2.5.4
3 | * https://github.com/alvarotrigo/fullPage.js
4 | * MIT licensed
5 | *
6 | * Copyright (C) 2013 alvarotrigo.com - A project by Alvaro Trigo
7 | */
8 |
9 | (function($) {
10 | $.fn.fullpage = function(options) {
11 | // Create some defaults, extending them with any options that were provided
12 | options = $.extend({
13 | //navigation
14 | 'menu': false,
15 | 'anchors':[],
16 | 'navigation': false,
17 | 'navigationPosition': 'right',
18 | 'navigationColor': '#000',
19 | 'navigationTooltips': [],
20 | 'slidesNavigation': false,
21 | 'slidesNavPosition': 'bottom',
22 | 'scrollBar': false,
23 |
24 | //scrolling
25 | 'css3': true,
26 | 'scrollingSpeed': 700,
27 | 'autoScrolling': true,
28 | 'easing': 'easeInQuart',
29 | 'easingcss3': 'ease',
30 | 'loopBottom': false,
31 | 'loopTop': false,
32 | 'loopHorizontal': true,
33 | 'continuousVertical': false,
34 | 'normalScrollElements': null,
35 | 'scrollOverflow': false,
36 | 'touchSensitivity': 5,
37 | 'normalScrollElementTouchThreshold': 5,
38 |
39 | //Accessibility
40 | 'keyboardScrolling': true,
41 | 'animateAnchor': true,
42 | 'recordHistory': true,
43 |
44 | //design
45 | 'controlArrows': true,
46 | 'controlArrowColor': '#fff',
47 | "verticalCentered": true,
48 | 'resize': true,
49 | 'sectionsColor' : [],
50 | 'paddingTop': 0,
51 | 'paddingBottom': 0,
52 | 'fixedElements': null,
53 | 'responsive': 0,
54 |
55 | //Custom selectors
56 | 'sectionSelector': '.section',
57 | 'slideSelector': '.slide',
58 |
59 |
60 | //events
61 | 'afterLoad': null,
62 | 'onLeave': null,
63 | 'afterRender': null,
64 | 'afterResize': null,
65 | 'afterReBuild': null,
66 | 'afterSlideLoad': null,
67 | 'onSlideLeave': null
68 | }, options);
69 |
70 | displayWarnings();
71 |
72 | //easeInQuart animation included in the plugin
73 | $.extend($.easing,{ easeInQuart: function (x, t, b, c, d) { return c*(t/=d)*t*t*t + b; }});
74 |
75 | //Defines the delay to take place before being able to scroll to the next section
76 | //BE CAREFUL! Not recommened to change it under 400 for a good behavior in laptops and
77 | //Apple devices (laptops, mouses...)
78 | var scrollDelay = 600;
79 |
80 | $.fn.fullpage.setAutoScrolling = function(value, type){
81 | setVariableState('autoScrolling', value, type);
82 |
83 | var element = $('.fp-section.active');
84 |
85 | if(options.autoScrolling && !options.scrollBar){
86 | $('html, body').css({
87 | 'overflow' : 'hidden',
88 | 'height' : '100%'
89 | });
90 |
91 | $.fn.fullpage.setRecordHistory(options.recordHistory, 'internal');
92 |
93 | //for IE touch devices
94 | container.css({
95 | '-ms-touch-action': 'none',
96 | 'touch-action': 'none'
97 | });
98 |
99 | if(element.length){
100 | //moving the container up
101 | silentScroll(element.position().top);
102 | }
103 |
104 | }else{
105 | $('html, body').css({
106 | 'overflow' : 'visible',
107 | 'height' : 'initial'
108 | });
109 |
110 | $.fn.fullpage.setRecordHistory(false, 'internal');
111 |
112 | //for IE touch devices
113 | container.css({
114 | '-ms-touch-action': '',
115 | 'touch-action': ''
116 | });
117 |
118 | silentScroll(0);
119 |
120 | //scrolling the page to the section with no animation
121 | $('html, body').scrollTop(element.position().top);
122 | }
123 |
124 | };
125 |
126 | /**
127 | * Defines wheter to record the history for each hash change in the URL.
128 | */
129 | $.fn.fullpage.setRecordHistory = function(value, type){
130 | setVariableState('recordHistory', value, type);
131 | };
132 |
133 | /**
134 | * Defines the scrolling speed
135 | */
136 | $.fn.fullpage.setScrollingSpeed = function(value, type){
137 | setVariableState('scrollingSpeed', value, type);
138 | };
139 |
140 | /**
141 | * Adds or remove the possiblity of scrolling through sections by using the mouse wheel or the trackpad.
142 | */
143 | $.fn.fullpage.setMouseWheelScrolling = function (value){
144 | if(value){
145 | addMouseWheelHandler();
146 | }else{
147 | removeMouseWheelHandler();
148 | }
149 | };
150 |
151 | /**
152 | * Adds or remove the possiblity of scrolling through sections by using the mouse wheel/trackpad or touch gestures.
153 | * Optionally a second parameter can be used to specify the direction for which the action will be applied.
154 | *
155 | * @param directions string containing the direction or directions separated by comma.
156 | */
157 | $.fn.fullpage.setAllowScrolling = function (value, directions){
158 | if(typeof directions != 'undefined'){
159 | directions = directions.replace(' ', '').split(',');
160 | $.each(directions, function (index, direction){
161 | setIsScrollable(value, direction);
162 | });
163 | }
164 | else if(value){
165 | $.fn.fullpage.setMouseWheelScrolling(true);
166 | addTouchHandler();
167 | }else{
168 | $.fn.fullpage.setMouseWheelScrolling(false);
169 | removeTouchHandler();
170 | }
171 | };
172 |
173 | /**
174 | * Adds or remove the possiblity of scrolling through sections by using the keyboard arrow keys
175 | */
176 | $.fn.fullpage.setKeyboardScrolling = function (value){
177 | options.keyboardScrolling = value;
178 | };
179 |
180 | $.fn.fullpage.moveSectionUp = function(){
181 | var prev = $('.fp-section.active').prev('.fp-section');
182 |
183 | //looping to the bottom if there's no more sections above
184 | if (!prev.length && (options.loopTop || options.continuousVertical)) {
185 | prev = $('.fp-section').last();
186 | }
187 |
188 | if (prev.length) {
189 | scrollPage(prev, null, true);
190 | }
191 | };
192 |
193 | $.fn.fullpage.moveSectionDown = function (){
194 | var next = $('.fp-section.active').next('.fp-section');
195 |
196 | //looping to the top if there's no more sections below
197 | if(!next.length &&
198 | (options.loopBottom || options.continuousVertical)){
199 | next = $('.fp-section').first();
200 | }
201 |
202 | if(next.length){
203 | scrollPage(next, null, false);
204 | }
205 | };
206 |
207 | $.fn.fullpage.moveTo = function (section, slide){
208 | var destiny = '';
209 |
210 | if(isNaN(section)){
211 | destiny = $('[data-anchor="'+section+'"]');
212 | }else{
213 | destiny = $('.fp-section').eq( (section -1) );
214 | }
215 |
216 | if (typeof slide !== 'undefined'){
217 | scrollPageAndSlide(section, slide);
218 | }else if(destiny.length > 0){
219 | scrollPage(destiny);
220 | }
221 | };
222 |
223 | $.fn.fullpage.moveSlideRight = function(){
224 | moveSlide('next');
225 | };
226 |
227 | $.fn.fullpage.moveSlideLeft = function(){
228 | moveSlide('prev');
229 | };
230 |
231 | /**
232 | * When resizing is finished, we adjust the slides sizes and positions
233 | */
234 | $.fn.fullpage.reBuild = function(resizing){
235 | isResizing = true;
236 |
237 | var windowsWidth = $(window).width();
238 | windowsHeight = $(window).height(); //updating global var
239 |
240 | //text and images resizing
241 | if (options.resize) {
242 | resizeMe(windowsHeight, windowsWidth);
243 | }
244 |
245 | $('.fp-section').each(function(){
246 | var scrollHeight = windowsHeight - parseInt($(this).css('padding-bottom')) - parseInt($(this).css('padding-top'));
247 |
248 | //adjusting the height of the table-cell for IE and Firefox
249 | if(options.verticalCentered){
250 | $(this).find('.fp-tableCell').css('height', getTableHeight($(this)) + 'px');
251 | }
252 |
253 | $(this).css('height', windowsHeight + 'px');
254 |
255 | //resizing the scrolling divs
256 | if(options.scrollOverflow){
257 | var slides = $(this).find('.fp-slide');
258 |
259 | if(slides.length){
260 | slides.each(function(){
261 | createSlimScrolling($(this));
262 | });
263 | }else{
264 | createSlimScrolling($(this));
265 | }
266 | }
267 |
268 | //adjusting the position fo the FULL WIDTH slides...
269 | var slides = $(this).find('.fp-slides');
270 | if (slides.length) {
271 | landscapeScroll(slides, slides.find('.fp-slide.active'));
272 | }
273 | });
274 |
275 | //adjusting the position for the current section
276 | var destinyPos = $('.fp-section.active').position();
277 |
278 | var activeSection = $('.fp-section.active');
279 |
280 | //isn't it the first section?
281 | if(activeSection.index('.fp-section')){
282 | scrollPage(activeSection);
283 | }
284 |
285 | isResizing = false;
286 | $.isFunction( options.afterResize ) && resizing && options.afterResize.call( this )
287 | $.isFunction( options.afterReBuild ) && !resizing && options.afterReBuild.call( this );
288 | }
289 |
290 | //flag to avoid very fast sliding for landscape sliders
291 | var slideMoving = false;
292 |
293 | var isTouchDevice = navigator.userAgent.match(/(iPhone|iPod|iPad|Android|BlackBerry|BB10|Windows Phone|Tizen|Bada)/);
294 | var isTouch = (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0) || (navigator.maxTouchPoints));
295 | var container = $(this);
296 | var windowsHeight = $(window).height();
297 | var isMoving = false;
298 | var isResizing = false;
299 | var lastScrolledDestiny;
300 | var lastScrolledSlide;
301 | var nav;
302 | var wrapperSelector = 'fullpage-wrapper';
303 | var isScrollAllowed = { 'up':true, 'down':true, 'left':true, 'right':true };
304 | var originals = jQuery.extend(true, {}, options); //deep copy
305 |
306 | $.fn.fullpage.setAllowScrolling(true);
307 |
308 | //if css3 is not supported, it will use jQuery animations
309 | if(options.css3){
310 | options.css3 = support3d();
311 | }
312 |
313 | if($(this).length){
314 | container.css({
315 | 'height': '100%',
316 | 'position': 'relative'
317 | });
318 |
319 | //adding a class to recognize the container internally in the code
320 | container.addClass(wrapperSelector);
321 | }
322 |
323 | //trying to use fullpage without a selector?
324 | else{
325 | showError('error', "Error! Fullpage.js needs to be initialized with a selector. For example: $('#myContainer').fullpage();");
326 | }
327 |
328 | //adding internal class names to void problem with common ones
329 | $(options.sectionSelector).each(function(){
330 | $(this).addClass('fp-section');
331 | });
332 | $(options.slideSelector).each(function(){
333 | $(this).addClass('fp-slide');
334 | });
335 |
336 | //creating the navigation dots
337 | if (options.navigation) {
338 | addVerticalNavigation();
339 | }
340 |
341 | $('.fp-section').each(function(index){
342 | var that = $(this);
343 | var slides = $(this).find('.fp-slide');
344 | var numSlides = slides.length;
345 |
346 | //if no active section is defined, the 1st one will be the default one
347 | if(!index && $('.fp-section.active').length === 0) {
348 | $(this).addClass('active');
349 | }
350 |
351 | $(this).css('height', windowsHeight + 'px');
352 |
353 | if(options.paddingTop || options.paddingBottom){
354 | $(this).css('padding', options.paddingTop + ' 0 ' + options.paddingBottom + ' 0');
355 | }
356 |
357 | if (typeof options.sectionsColor[index] !== 'undefined') {
358 | $(this).css('background-color', options.sectionsColor[index]);
359 | }
360 |
361 | if (typeof options.anchors[index] !== 'undefined') {
362 | $(this).attr('data-anchor', options.anchors[index]);
363 | }
364 |
365 | // if there's any slide
366 | if (numSlides > 1) {
367 | var sliderWidth = numSlides * 100;
368 | var slideWidth = 100 / numSlides;
369 |
370 | slides.wrapAll('');
371 | slides.parent().wrap('');
372 |
373 | $(this).find('.fp-slidesContainer').css('width', sliderWidth + '%');
374 |
375 | if(options.controlArrows){
376 | createSlideArrows($(this));
377 | }
378 |
379 | if(options.slidesNavigation){
380 | addSlidesNavigation($(this), numSlides);
381 | }
382 |
383 | slides.each(function(index) {
384 | $(this).css('width', slideWidth + '%');
385 |
386 | if(options.verticalCentered){
387 | addTableClass($(this));
388 | }
389 | });
390 |
391 | var startingSlide = that.find('.fp-slide.active');
392 |
393 | //if the slide won#t be an starting point, the default will be the first one
394 | if(startingSlide.length == 0){
395 | slides.eq(0).addClass('active');
396 | }
397 |
398 | //is there a starting point for a non-starting section?
399 | else{
400 | silentLandscapeScroll(startingSlide);
401 | }
402 |
403 | }else{
404 | if(options.verticalCentered){
405 | addTableClass($(this));
406 | }
407 | }
408 |
409 | }).promise().done(function(){
410 | $.fn.fullpage.setAutoScrolling(options.autoScrolling, 'internal');
411 |
412 | //the starting point is a slide?
413 | var activeSlide = $('.fp-section.active').find('.fp-slide.active');
414 |
415 | //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.
416 | if( activeSlide.length && ($('.fp-section.active').index('.fp-section') != 0 || ($('.fp-section.active').index('.fp-section') == 0 && activeSlide.index() != 0))){
417 | silentLandscapeScroll(activeSlide);
418 | }
419 |
420 | //fixed elements need to be moved out of the plugin container due to problems with CSS3.
421 | if(options.fixedElements && options.css3){
422 | $(options.fixedElements).appendTo('body');
423 | }
424 |
425 | //vertical centered of the navigation + first bullet active
426 | if(options.navigation){
427 | nav.css('margin-top', '-' + (nav.height()/2) + 'px');
428 | nav.find('li').eq($('.fp-section.active').index('.fp-section')).find('a').addClass('active');
429 | }
430 |
431 | //moving the menu outside the main container if it is inside (avoid problems with fixed positions when using CSS3 tranforms)
432 | if(options.menu && options.css3 && $(options.menu).closest('.fullpage-wrapper').length){
433 | $(options.menu).appendTo('body');
434 | }
435 |
436 | if(options.scrollOverflow){
437 | if(document.readyState === "complete"){
438 | createSlimScrollingHandler();
439 | }
440 | //after DOM and images are loaded
441 | $(window).on('load', createSlimScrollingHandler);
442 | }else{
443 | $.isFunction( options.afterRender ) && options.afterRender.call( this);
444 | }
445 |
446 | responsive();
447 |
448 | //getting the anchor link in the URL and deleting the `#`
449 | var value = window.location.hash.replace('#', '').split('/');
450 | var destiny = value[0];
451 |
452 | if(destiny.length){
453 | var section = $('[data-anchor="'+destiny+'"]');
454 |
455 | if(!options.animateAnchor && section.length){
456 |
457 | if(options.autoScrolling){
458 | silentScroll(section.position().top);
459 | }
460 | else{
461 | silentScroll(0);
462 | setBodyClass(destiny);
463 |
464 | //scrolling the page to the section with no animation
465 | $('html, body').scrollTop(section.position().top);
466 | }
467 |
468 | activateMenuAndNav(destiny, null);
469 |
470 | $.isFunction( options.afterLoad ) && options.afterLoad.call( this, destiny, (section.index('.fp-section') + 1));
471 |
472 | //updating the active class
473 | section.addClass('active').siblings().removeClass('active');
474 | }
475 | }
476 |
477 |
478 | $(window).on('load', function() {
479 | scrollToAnchor();
480 | });
481 |
482 | });
483 |
484 |
485 | /**
486 | * Creates the control arrows for the given section
487 | */
488 | function createSlideArrows(section){
489 | section.find('.fp-slides').after('');
490 |
491 | if(options.controlArrowColor!='#fff'){
492 | section.find('.fp-controlArrow.fp-next').css('border-color', 'transparent transparent transparent '+options.controlArrowColor);
493 | section.find('.fp-controlArrow.fp-prev').css('border-color', 'transparent '+ options.controlArrowColor + ' transparent transparent');
494 | }
495 |
496 | if(!options.loopHorizontal){
497 | section.find('.fp-controlArrow.fp-prev').hide();
498 | }
499 | }
500 |
501 | /**
502 | * Creates a vertical navigation bar.
503 | */
504 | function addVerticalNavigation(){
505 | $('body').append('
');
506 | nav = $('#fp-nav');
507 |
508 | nav.css('color', options.navigationColor);
509 | nav.addClass(options.navigationPosition);
510 |
511 | for (var i = 0; i < $('.fp-section').length; i++) {
512 | var link = '';
513 | if (options.anchors.length) {
514 | link = options.anchors[i];
515 | }
516 |
517 | var li = '
';
518 |
519 | // Only add tooltip if needed (defined by user)
520 | var tooltip = options.navigationTooltips[i];
521 | if (tooltip != undefined && tooltip != '') {
522 | li += '
' + tooltip + '
';
523 | }
524 |
525 | li += '
';
526 |
527 | nav.find('ul').append(li);
528 | }
529 | }
530 |
531 | function createSlimScrollingHandler(){
532 | $('.fp-section').each(function(){
533 | var slides = $(this).find('.fp-slide');
534 |
535 | if(slides.length){
536 | slides.each(function(){
537 | createSlimScrolling($(this));
538 | });
539 | }else{
540 | createSlimScrolling($(this));
541 | }
542 |
543 | });
544 | $.isFunction( options.afterRender ) && options.afterRender.call( this);
545 | }
546 |
547 | var scrollId;
548 | var scrollId2;
549 | var isScrolling = false;
550 |
551 | //when scrolling...
552 | $(window).on('scroll', scrollHandler);
553 |
554 | function scrollHandler(){
555 | if(!options.autoScrolling || options.scrollBar){
556 | var currentScroll = $(window).scrollTop();
557 | var visibleSectionIndex = 0;
558 | var initial = Math.abs(currentScroll - $('.fp-section').first().offset().top);
559 |
560 | //taking the section which is showing more content in the viewport
561 | $('.fp-section').each(function(index){
562 | var current = Math.abs(currentScroll - $(this).offset().top);
563 |
564 | if(current < initial){
565 | visibleSectionIndex = index;
566 | initial = current;
567 | }
568 | });
569 |
570 | //geting the last one, the current one on the screen
571 | var currentSection = $('.fp-section').eq(visibleSectionIndex);
572 | }
573 |
574 | if(!options.autoScrolling){
575 | //executing only once the first time we reach the section
576 | if(!currentSection.hasClass('active')){
577 | isScrolling = true;
578 |
579 | var leavingSection = $('.fp-section.active').index('.fp-section') + 1;
580 | var yMovement = getYmovement(currentSection);
581 | var anchorLink = currentSection.data('anchor');
582 | var sectionIndex = currentSection.index('.fp-section') + 1;
583 | var activeSlide = currentSection.find('.fp-slide.active');
584 |
585 | if(activeSlide.length){
586 | var slideAnchorLink = activeSlide.data('anchor');
587 | var slideIndex = activeSlide.index();
588 | }
589 |
590 | currentSection.addClass('active').siblings().removeClass('active');
591 |
592 | if(!isMoving){
593 | $.isFunction( options.onLeave ) && options.onLeave.call( this, leavingSection, sectionIndex, yMovement);
594 |
595 | $.isFunction( options.afterLoad ) && options.afterLoad.call( this, anchorLink, sectionIndex);
596 | }
597 |
598 | activateMenuAndNav(anchorLink, 0);
599 |
600 | if(options.anchors.length && !isMoving){
601 | //needed to enter in hashChange event when using the menu with anchor links
602 | lastScrolledDestiny = anchorLink;
603 |
604 | setState(slideIndex, slideAnchorLink, anchorLink, sectionIndex);
605 | }
606 |
607 | //small timeout in order to avoid entering in hashChange event when scrolling is not finished yet
608 | clearTimeout(scrollId);
609 | scrollId = setTimeout(function(){
610 | isScrolling = false;
611 | }, 100);
612 | }
613 | }
614 |
615 | if(options.scrollBar){
616 | //for the auto adjust of the viewport to fit a whole section
617 | clearTimeout(scrollId2);
618 | scrollId2 = setTimeout(function(){
619 | if(!isMoving){
620 | scrollPage(currentSection);
621 | }
622 | }, 1000);
623 | }
624 | }
625 |
626 |
627 | /**
628 | * Determines whether the active section or slide is scrollable through and scrolling bar
629 | */
630 | function isScrollable(activeSection){
631 | //if there are landscape slides, we check if the scrolling bar is in the current one or not
632 | if(activeSection.find('.fp-slides').length){
633 | scrollable= activeSection.find('.fp-slide.active').find('.fp-scrollable');
634 | }else{
635 | scrollable = activeSection.find('.fp-scrollable');
636 | }
637 |
638 | return scrollable;
639 | }
640 |
641 | /**
642 | * Determines the way of scrolling up or down:
643 | * by 'automatically' scrolling a section or by using the default and normal scrolling.
644 | */
645 | function scrolling(type, scrollable){
646 | if (!isScrollAllowed[type]){
647 | return;
648 | }
649 |
650 | if(type == 'down'){
651 | var check = 'bottom';
652 | var scrollSection = $.fn.fullpage.moveSectionDown;
653 | }else{
654 | var check = 'top';
655 | var scrollSection = $.fn.fullpage.moveSectionUp;
656 | }
657 |
658 | if(scrollable.length > 0 ){
659 | //is the scrollbar at the start/end of the scroll?
660 | if(isScrolled(check, scrollable)){
661 | scrollSection();
662 | }else{
663 | return true;
664 | }
665 | }else{
666 | // moved up/down
667 | scrollSection();
668 | }
669 | }
670 |
671 |
672 | var touchStartY = 0;
673 | var touchStartX = 0;
674 | var touchEndY = 0;
675 | var touchEndX = 0;
676 |
677 | /* Detecting touch events
678 |
679 | * As we are changing the top property of the page on scrolling, we can not use the traditional way to detect it.
680 | * This way, the touchstart and the touch moves shows an small difference between them which is the
681 | * used one to determine the direction.
682 | */
683 | function touchMoveHandler(event){
684 | var e = event.originalEvent;
685 |
686 | // additional: if one of the normalScrollElements isn't within options.normalScrollElementTouchThreshold hops up the DOM chain
687 | if (!checkParentForNormalScrollElement(event.target)) {
688 |
689 | if(options.autoScrolling && !options.scrollBar){
690 | //preventing the easing on iOS devices
691 | event.preventDefault();
692 | }
693 |
694 | var activeSection = $('.fp-section.active');
695 | var scrollable = isScrollable(activeSection);
696 |
697 | if (!isMoving && !slideMoving) { //if theres any #
698 | var touchEvents = getEventsPage(e);
699 |
700 | touchEndY = touchEvents['y'];
701 | touchEndX = touchEvents['x'];
702 |
703 | //if movement in the X axys is greater than in the Y and the currect section has slides...
704 | if (activeSection.find('.fp-slides').length && Math.abs(touchStartX - touchEndX) > (Math.abs(touchStartY - touchEndY))) {
705 |
706 | //is the movement greater than the minimum resistance to scroll?
707 | if (Math.abs(touchStartX - touchEndX) > ($(window).width() / 100 * options.touchSensitivity)) {
708 | if (touchStartX > touchEndX) {
709 | if(isScrollAllowed.right){
710 | $.fn.fullpage.moveSlideRight(); //next
711 | }
712 | } else {
713 | if(isScrollAllowed.left){
714 | $.fn.fullpage.moveSlideLeft(); //prev
715 | }
716 | }
717 | }
718 | }
719 |
720 | //vertical scrolling (only when autoScrolling is enabled)
721 | else if(options.autoScrolling && !options.scrollBar){
722 |
723 | //is the movement greater than the minimum resistance to scroll?
724 | if (Math.abs(touchStartY - touchEndY) > ($(window).height() / 100 * options.touchSensitivity)) {
725 | if (touchStartY > touchEndY) {
726 | scrolling('down', scrollable);
727 | } else if (touchEndY > touchStartY) {
728 | scrolling('up', scrollable);
729 | }
730 | }
731 | }
732 | }
733 | }
734 |
735 | }
736 |
737 | /**
738 | * recursive function to loop up the parent nodes to check if one of them exists in options.normalScrollElements
739 | * Currently works well for iOS - Android might need some testing
740 | * @param {Element} el target element / jquery selector (in subsequent nodes)
741 | * @param {int} hop current hop compared to options.normalScrollElementTouchThreshold
742 | * @return {boolean} true if there is a match to options.normalScrollElements
743 | */
744 | function checkParentForNormalScrollElement (el, hop) {
745 | hop = hop || 0;
746 | var parent = $(el).parent();
747 |
748 | if (hop < options.normalScrollElementTouchThreshold &&
749 | parent.is(options.normalScrollElements) ) {
750 | return true;
751 | } else if (hop == options.normalScrollElementTouchThreshold) {
752 | return false;
753 | } else {
754 | return checkParentForNormalScrollElement(parent, ++hop);
755 | }
756 | }
757 |
758 | function touchStartHandler(event){
759 | var e = event.originalEvent;
760 |
761 | var touchEvents = getEventsPage(e);
762 | touchStartY = touchEvents['y'];
763 | touchStartX = touchEvents['x'];
764 | }
765 |
766 |
767 | /**
768 | * Detecting mousewheel scrolling
769 | *
770 | * http://blogs.sitepointstatic.com/examples/tech/mouse-wheel/index.html
771 | * http://www.sitepoint.com/html5-javascript-mouse-wheel/
772 | */
773 | function MouseWheelHandler(e) {
774 | if(options.autoScrolling){
775 | // cross-browser wheel delta
776 | e = window.event || e;
777 | var delta = Math.max(-1, Math.min(1,
778 | (e.wheelDelta || -e.deltaY || -e.detail)));
779 |
780 | //preventing to scroll the site on mouse wheel when scrollbar is present
781 | if(options.scrollBar){
782 | e.preventDefault ? e.preventDefault() : e.returnValue = false;
783 |
784 | }
785 |
786 | var activeSection = $('.fp-section.active');
787 | var scrollable = isScrollable(activeSection);
788 |
789 | if (!isMoving) { //if theres any #
790 | //scrolling down?
791 | if (delta < 0) {
792 | scrolling('down', scrollable);
793 |
794 | //scrolling up?
795 | }else {
796 | scrolling('up', scrollable);
797 | }
798 | }
799 |
800 | return false;
801 | }
802 | }
803 |
804 | function moveSlide(direction){
805 | var activeSection = $('.fp-section.active');
806 | var slides = activeSection.find('.fp-slides');
807 |
808 | // more than one slide needed and nothing should be sliding
809 | if (!slides.length || slideMoving) {
810 | return;
811 | }
812 |
813 | var currentSlide = slides.find('.fp-slide.active');
814 | var destiny = null;
815 |
816 | if(direction === 'prev'){
817 | destiny = currentSlide.prev('.fp-slide');
818 | }else{
819 | destiny = currentSlide.next('.fp-slide');
820 | }
821 |
822 | //isn't there a next slide in the secuence?
823 | if(!destiny.length){
824 | //respect loopHorizontal settin
825 | if (!options.loopHorizontal) return;
826 |
827 | if(direction === 'prev'){
828 | destiny = currentSlide.siblings(':last');
829 | }else{
830 | destiny = currentSlide.siblings(':first');
831 | }
832 | }
833 |
834 | slideMoving = true;
835 |
836 | landscapeScroll(slides, destiny);
837 | }
838 |
839 | /**
840 | * Maintains the active slides in the viewport
841 | * (Because he `scroll` animation might get lost with some actions, such as when using continuousVertical)
842 | */
843 | function keepSlidesPosition(){
844 | $('.fp-slide.active').each(function(){
845 | silentLandscapeScroll($(this));
846 | });
847 | }
848 |
849 | /**
850 | * Scrolls the site to the given element and scrolls to the slide if a callback is given.
851 | */
852 | function scrollPage(element, callback, isMovementUp){
853 | var dest = element.position();
854 | if(typeof dest === "undefined"){ return; } //there's no element to scroll, leaving the function
855 |
856 | //local variables
857 | var v = {
858 | element: element,
859 | callback: callback,
860 | isMovementUp: isMovementUp,
861 | dest: dest,
862 | dtop: dest.top,
863 | yMovement: getYmovement(element),
864 | anchorLink: element.data('anchor'),
865 | sectionIndex: element.index('.fp-section'),
866 | activeSlide: element.find('.fp-slide.active'),
867 | activeSection: $('.fp-section.active'),
868 | leavingSection: $('.fp-section.active').index('.fp-section') + 1,
869 |
870 | //caching the value of isResizing at the momment the function is called
871 | //because it will be checked later inside a setTimeout and the value might change
872 | localIsResizing: isResizing
873 | };
874 |
875 | //quiting when destination scroll is the same as the current one
876 | if((v.activeSection.is(element) && !isResizing) || (options.scrollBar && $(window).scrollTop() === v.dtop)){ return; }
877 |
878 | if(v.activeSlide.length){
879 | var slideAnchorLink = v.activeSlide.data('anchor');
880 | var slideIndex = v.activeSlide.index();
881 | }
882 |
883 | // If continuousVertical && we need to wrap around
884 | if (options.autoScrolling && options.continuousVertical && typeof (v.isMovementUp) !== "undefined" &&
885 | ((!v.isMovementUp && v.yMovement == 'up') || // Intending to scroll down but about to go up or
886 | (v.isMovementUp && v.yMovement == 'down'))) { // intending to scroll up but about to go down
887 |
888 | v = createInfiniteSections(v);
889 | }
890 |
891 | element.addClass('active').siblings().removeClass('active');
892 |
893 | //preventing from activating the MouseWheelHandler event
894 | //more than once if the page is scrolling
895 | isMoving = true;
896 |
897 | setState(slideIndex, slideAnchorLink, v.anchorLink, v.sectionIndex);
898 |
899 | //callback (onLeave) if the site is not just resizing and readjusting the slides
900 | $.isFunction(options.onLeave) && !v.localIsResizing && options.onLeave.call(this, v.leavingSection, (v.sectionIndex + 1), v.yMovement);
901 |
902 | performMovement(v);
903 |
904 | //flag to avoid callingn `scrollPage()` twice in case of using anchor links
905 | lastScrolledDestiny = v.anchorLink;
906 |
907 | //avoid firing it twice (as it does also on scroll)
908 | if(options.autoScrolling){
909 | activateMenuAndNav(v.anchorLink, v.sectionIndex)
910 | }
911 | }
912 |
913 | /**
914 | * Performs the movement (by CSS3 or by jQuery)
915 | */
916 | function performMovement(v){
917 | // using CSS3 translate functionality
918 | if (options.css3 && options.autoScrolling && !options.scrollBar) {
919 |
920 | var translate3d = 'translate3d(0px, -' + v.dtop + 'px, 0px)';
921 | transformContainer(translate3d, true);
922 |
923 | setTimeout(function () {
924 | afterSectionLoads(v);
925 | }, options.scrollingSpeed);
926 | }
927 |
928 | // using jQuery animate
929 | else{
930 | var scrollSettings = getScrollSettings(v);
931 |
932 | $(scrollSettings.element).animate(
933 | scrollSettings.options
934 | , options.scrollingSpeed, options.easing).promise().done(function () { //only one single callback in case of animating `html, body`
935 | afterSectionLoads(v);
936 | });
937 | }
938 | }
939 |
940 | /**
941 | * Gets the scrolling settings depending on the plugin autoScrolling option
942 | */
943 | function getScrollSettings(v){
944 | var scroll = {};
945 |
946 | if(options.autoScrolling && !options.scrollBar){
947 | scroll.options = { 'top': -v.dtop};
948 | scroll.element = '.'+wrapperSelector;
949 | }else{
950 | scroll.options = { 'scrollTop': v.dtop};
951 | scroll.element = 'html, body';
952 | }
953 |
954 | return scroll;
955 | }
956 |
957 | /**
958 | * Adds sections before or after the current one to create the infinite effect.
959 | */
960 | function createInfiniteSections(v){
961 | // Scrolling down
962 | if (!v.isMovementUp) {
963 | // Move all previous sections to after the active section
964 | $(".fp-section.active").after(v.activeSection.prevAll(".fp-section").get().reverse());
965 | }
966 | else { // Scrolling up
967 | // Move all next sections to before the active section
968 | $(".fp-section.active").before(v.activeSection.nextAll(".fp-section"));
969 | }
970 |
971 | // Maintain the displayed position (now that we changed the element order)
972 | silentScroll($('.fp-section.active').position().top);
973 |
974 | // Maintain the active slides visible in the viewport
975 | keepSlidesPosition();
976 |
977 | // save for later the elements that still need to be reordered
978 | v.wrapAroundElements = v.activeSection;
979 |
980 | // Recalculate animation variables
981 | v.dest = v.element.position();
982 | v.dtop = v.dest.top;
983 | v.yMovement = getYmovement(v.element);
984 |
985 | return v;
986 | }
987 |
988 | /**
989 | * Fix section order after continuousVertical changes have been animated
990 | */
991 | function continuousVerticalFixSectionOrder (v) {
992 | // If continuousVertical is in effect (and autoScrolling would also be in effect then),
993 | // finish moving the elements around so the direct navigation will function more simply
994 | if (!v.wrapAroundElements || !v.wrapAroundElements.length) {
995 | return;
996 | }
997 |
998 | if (v.isMovementUp) {
999 | $('.fp-section:first').before(v.wrapAroundElements);
1000 | }
1001 | else {
1002 | $('.fp-section:last').after(v.wrapAroundElements);
1003 | }
1004 |
1005 | silentScroll($('.fp-section.active').position().top);
1006 |
1007 | // Maintain the active slides visible in the viewport
1008 | keepSlidesPosition();
1009 | };
1010 |
1011 |
1012 | /**
1013 | * Actions to do once the section is loaded
1014 | */
1015 | function afterSectionLoads (v){
1016 | continuousVerticalFixSectionOrder(v);
1017 | //callback (afterLoad) if the site is not just resizing and readjusting the slides
1018 | $.isFunction(options.afterLoad) && !v.localIsResizing && options.afterLoad.call(this, v.anchorLink, (v.sectionIndex + 1));
1019 |
1020 | setTimeout(function () {
1021 | isMoving = false;
1022 | $.isFunction(v.callback) && v.callback.call(this);
1023 | }, scrollDelay);
1024 | }
1025 |
1026 |
1027 | /**
1028 | * Scrolls to the anchor in the URL when loading the site
1029 | */
1030 | function scrollToAnchor(){
1031 | //getting the anchor link in the URL and deleting the `#`
1032 | var value = window.location.hash.replace('#', '').split('/');
1033 | var section = value[0];
1034 | var slide = value[1];
1035 |
1036 | if(section){ //if theres any #
1037 | scrollPageAndSlide(section, slide);
1038 | }
1039 | }
1040 |
1041 | //detecting any change on the URL to scroll to the given anchor link
1042 | //(a way to detect back history button as we play with the hashes on the URL)
1043 | $(window).on('hashchange', hashChangeHandler);
1044 |
1045 | function hashChangeHandler(){
1046 | if(!isScrolling){
1047 | var value = window.location.hash.replace('#', '').split('/');
1048 | var section = value[0];
1049 | var slide = value[1];
1050 |
1051 | if(section.length){
1052 | //when moving to a slide in the first section for the first time (first time to add an anchor to the URL)
1053 | var isFirstSlideMove = (typeof lastScrolledDestiny === 'undefined');
1054 | var isFirstScrollMove = (typeof lastScrolledDestiny === 'undefined' && typeof slide === 'undefined' && !slideMoving);
1055 |
1056 | /*in order to call scrollpage() only once for each destination at a time
1057 | It is called twice for each scroll otherwise, as in case of using anchorlinks `hashChange`
1058 | event is fired on every scroll too.*/
1059 | if ((section && section !== lastScrolledDestiny) && !isFirstSlideMove || isFirstScrollMove || (!slideMoving && lastScrolledSlide != slide )) {
1060 | scrollPageAndSlide(section, slide);
1061 | }
1062 | }
1063 | }
1064 | }
1065 |
1066 |
1067 | /**
1068 | * Sliding with arrow keys, both, vertical and horizontal
1069 | */
1070 | $(document).keydown(function(e) {
1071 | //Moving the main page with the keyboard arrows if keyboard scrolling is enabled
1072 | if (options.keyboardScrolling && options.autoScrolling) {
1073 |
1074 | //preventing the scroll with arrow keys
1075 | if(e.which == 40 || e.which == 38){
1076 | e.preventDefault();
1077 | }
1078 |
1079 | if(!isMoving){
1080 | switch (e.which) {
1081 | //up
1082 | case 38:
1083 | case 33:
1084 | $.fn.fullpage.moveSectionUp();
1085 | break;
1086 |
1087 | //down
1088 | case 40:
1089 | case 34:
1090 | $.fn.fullpage.moveSectionDown();
1091 | break;
1092 |
1093 | //Home
1094 | case 36:
1095 | $.fn.fullpage.moveTo(1);
1096 | break;
1097 |
1098 | //End
1099 | case 35:
1100 | $.fn.fullpage.moveTo( $('.fp-section').length );
1101 | break;
1102 |
1103 | //left
1104 | case 37:
1105 | $.fn.fullpage.moveSlideLeft();
1106 | break;
1107 |
1108 | //right
1109 | case 39:
1110 | $.fn.fullpage.moveSlideRight();
1111 | break;
1112 |
1113 | default:
1114 | return; // exit this handler for other keys
1115 | }
1116 | }
1117 | }
1118 | });
1119 |
1120 | /**
1121 | * Scrolls to the section when clicking the navigation bullet
1122 | */
1123 | $(document).on('click touchstart', '#fp-nav a', function(e){
1124 | e.preventDefault();
1125 | var index = $(this).parent().index();
1126 | scrollPage($('.fp-section').eq(index));
1127 | });
1128 |
1129 | /**
1130 | * Scrolls the slider to the given slide destination for the given section
1131 | */
1132 | $(document).on('click touchstart', '.fp-slidesNav a', function(e){
1133 | e.preventDefault();
1134 | var slides = $(this).closest('.fp-section').find('.fp-slides');
1135 | var destiny = slides.find('.fp-slide').eq($(this).closest('li').index());
1136 |
1137 | landscapeScroll(slides, destiny);
1138 | });
1139 |
1140 | if(options.normalScrollElements){
1141 | $(document).on('mouseenter', options.normalScrollElements, function () {
1142 | $.fn.fullpage.setMouseWheelScrolling(false);
1143 | });
1144 |
1145 | $(document).on('mouseleave', options.normalScrollElements, function(){
1146 | $.fn.fullpage.setMouseWheelScrolling(true);
1147 | });
1148 | }
1149 |
1150 | /**
1151 | * Scrolling horizontally when clicking on the slider controls.
1152 | */
1153 | $('.fp-section').on('click touchstart', '.fp-controlArrow', function() {
1154 | if ($(this).hasClass('fp-prev')) {
1155 | $.fn.fullpage.moveSlideLeft();
1156 | } else {
1157 | $.fn.fullpage.moveSlideRight();
1158 | }
1159 | });
1160 |
1161 | /**
1162 | * Scrolls horizontal sliders.
1163 | */
1164 | function landscapeScroll(slides, destiny){
1165 | var destinyPos = destiny.position();
1166 | var slidesContainer = slides.find('.fp-slidesContainer').parent();
1167 | var slideIndex = destiny.index();
1168 | var section = slides.closest('.fp-section');
1169 | var sectionIndex = section.index('.fp-section');
1170 | var anchorLink = section.data('anchor');
1171 | var slidesNav = section.find('.fp-slidesNav');
1172 | var slideAnchor = destiny.data('anchor');
1173 |
1174 | //caching the value of isResizing at the momment the function is called
1175 | //because it will be checked later inside a setTimeout and the value might change
1176 | var localIsResizing = isResizing;
1177 |
1178 | if(options.onSlideLeave){
1179 | var prevSlideIndex = section.find('.fp-slide.active').index();
1180 | var xMovement = getXmovement(prevSlideIndex, slideIndex);
1181 |
1182 | //if the site is not just resizing and readjusting the slides
1183 | if(!localIsResizing && xMovement!=='none'){
1184 | $.isFunction( options.onSlideLeave ) && options.onSlideLeave.call( this, anchorLink, (sectionIndex + 1), prevSlideIndex, xMovement);
1185 | }
1186 | }
1187 |
1188 | destiny.addClass('active').siblings().removeClass('active');
1189 |
1190 |
1191 | if(typeof slideAnchor === 'undefined'){
1192 | slideAnchor = slideIndex;
1193 | }
1194 |
1195 | if(!options.loopHorizontal && options.controlArrows){
1196 | //hidding it for the fist slide, showing for the rest
1197 | section.find('.fp-controlArrow.fp-prev').toggle(slideIndex!=0);
1198 |
1199 | //hidding it for the last slide, showing for the rest
1200 | section.find('.fp-controlArrow.fp-next').toggle(!destiny.is(':last-child'));
1201 | }
1202 |
1203 | //only changing the URL if the slides are in the current section (not for resize re-adjusting)
1204 | if(section.hasClass('active')){
1205 | setState(slideIndex, slideAnchor, anchorLink, sectionIndex);
1206 | }
1207 |
1208 | var afterSlideLoads = function(){
1209 | //if the site is not just resizing and readjusting the slides
1210 | if(!localIsResizing){
1211 | $.isFunction( options.afterSlideLoad ) && options.afterSlideLoad.call( this, anchorLink, (sectionIndex + 1), slideAnchor, slideIndex);
1212 | }
1213 | //letting them slide again
1214 | slideMoving = false;
1215 | };
1216 |
1217 | if(options.css3){
1218 | var translate3d = 'translate3d(-' + destinyPos.left + 'px, 0px, 0px)';
1219 |
1220 | addAnimation(slides.find('.fp-slidesContainer'), options.scrollingSpeed>0).css(getTransforms(translate3d));
1221 |
1222 | setTimeout(function(){
1223 | afterSlideLoads();
1224 | }, options.scrollingSpeed, options.easing);
1225 | }else{
1226 | slidesContainer.animate({
1227 | scrollLeft : destinyPos.left
1228 | }, options.scrollingSpeed, options.easing, function() {
1229 |
1230 | afterSlideLoads();
1231 | });
1232 | }
1233 |
1234 | slidesNav.find('.active').removeClass('active');
1235 | slidesNav.find('li').eq(slideIndex).find('a').addClass('active');
1236 | }
1237 |
1238 | //when resizing the site, we adjust the heights of the sections, slimScroll...
1239 | $(window).resize(resizeHandler);
1240 |
1241 | var previousHeight = windowsHeight;
1242 | var resizeId;
1243 | function resizeHandler(){
1244 | //checking if it needs to get responsive
1245 | responsive();
1246 |
1247 | // rebuild immediately on touch devices
1248 | if (isTouchDevice) {
1249 |
1250 | //if the keyboard is visible
1251 | if ($(document.activeElement).attr('type') !== 'text') {
1252 | var currentHeight = $(window).height();
1253 |
1254 | //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)
1255 | if( Math.abs(currentHeight - previousHeight) > (20 * Math.max(previousHeight, currentHeight) / 100) ){
1256 | $.fn.fullpage.reBuild(true);
1257 | previousHeight = currentHeight;
1258 | }
1259 | }
1260 | }else{
1261 | //in order to call the functions only when the resize is finished
1262 | //http://stackoverflow.com/questions/4298612/jquery-how-to-call-resize-event-only-once-its-finished-resizing
1263 | clearTimeout(resizeId);
1264 |
1265 | resizeId = setTimeout(function(){
1266 | $.fn.fullpage.reBuild(true);
1267 | }, 500);
1268 | }
1269 | }
1270 |
1271 | /**
1272 | * Checks if the site needs to get responsive and disables autoScrolling if so.
1273 | * A class `fp-responsive` is added to the plugin's container in case the user wants to use it for his own responsive CSS.
1274 | */
1275 | function responsive(){
1276 | if(options.responsive){
1277 | var isResponsive = container.hasClass('fp-responsive');
1278 | if ($(window).width() < options.responsive ){
1279 | if(!isResponsive){
1280 | $.fn.fullpage.setAutoScrolling(false, 'internal');
1281 | $('#fp-nav').hide();
1282 | container.addClass('fp-responsive');
1283 | }
1284 | }else if(isResponsive){
1285 | $.fn.fullpage.setAutoScrolling(originals.autoScrolling, 'internal');
1286 | $('#fp-nav').show();
1287 | container.removeClass('fp-responsive');
1288 | }
1289 | }
1290 | }
1291 |
1292 | /**
1293 | * Adds transition animations for the given element
1294 | */
1295 | function addAnimation(element){
1296 | var transition = 'all ' + options.scrollingSpeed + 'ms ' + options.easingcss3;
1297 |
1298 | element.removeClass('fp-notransition');
1299 | return element.css({
1300 | '-webkit-transition': transition,
1301 | 'transition': transition
1302 | });
1303 | }
1304 |
1305 | /**
1306 | * Remove transition animations for the given element
1307 | */
1308 | function removeAnimation(element){
1309 | return element.addClass('fp-notransition');
1310 | }
1311 |
1312 | /**
1313 | * Resizing of the font size depending on the window size as well as some of the images on the site.
1314 | */
1315 | function resizeMe(displayHeight, displayWidth) {
1316 | //Standard dimensions, for which the body font size is correct
1317 | var preferredHeight = 825;
1318 | var preferredWidth = 900;
1319 |
1320 | if (displayHeight < preferredHeight || displayWidth < preferredWidth) {
1321 | var heightPercentage = (displayHeight * 100) / preferredHeight;
1322 | var widthPercentage = (displayWidth * 100) / preferredWidth;
1323 | var percentage = Math.min(heightPercentage, widthPercentage);
1324 | var newFontSize = percentage.toFixed(2);
1325 |
1326 | $("body").css("font-size", newFontSize + '%');
1327 | } else {
1328 | $("body").css("font-size", '100%');
1329 | }
1330 | }
1331 |
1332 | /**
1333 | * Activating the website navigation dots according to the given slide name.
1334 | */
1335 | function activateNavDots(name, sectionIndex){
1336 | if(options.navigation){
1337 | $('#fp-nav').find('.active').removeClass('active');
1338 | if(name){
1339 | $('#fp-nav').find('a[href="#' + name + '"]').addClass('active');
1340 | }else{
1341 | $('#fp-nav').find('li').eq(sectionIndex).find('a').addClass('active');
1342 | }
1343 | }
1344 | }
1345 |
1346 | /**
1347 | * Activating the website main menu elements according to the given slide name.
1348 | */
1349 | function activateMenuElement(name){
1350 | if(options.menu){
1351 | $(options.menu).find('.active').removeClass('active');
1352 | $(options.menu).find('[data-menuanchor="'+name+'"]').addClass('active');
1353 | }
1354 | }
1355 |
1356 | function activateMenuAndNav(anchor, index){
1357 | activateMenuElement(anchor);
1358 | activateNavDots(anchor, index);
1359 | }
1360 |
1361 | /**
1362 | * Return a boolean depending on whether the scrollable element is at the end or at the start of the scrolling
1363 | * depending on the given type.
1364 | */
1365 | function isScrolled(type, scrollable){
1366 | if(type === 'top'){
1367 | return !scrollable.scrollTop();
1368 | }else if(type === 'bottom'){
1369 | return scrollable.scrollTop() + 1 + scrollable.innerHeight() >= scrollable[0].scrollHeight;
1370 | }
1371 | }
1372 |
1373 | /**
1374 | * Retuns `up` or `down` depending on the scrolling movement to reach its destination
1375 | * from the current section.
1376 | */
1377 | function getYmovement(destiny){
1378 | var fromIndex = $('.fp-section.active').index('.fp-section');
1379 | var toIndex = destiny.index('.fp-section');
1380 | if( fromIndex == toIndex){
1381 | return 'none'
1382 | }
1383 | if(fromIndex > toIndex){
1384 | return 'up';
1385 | }
1386 | return 'down';
1387 | }
1388 |
1389 | /**
1390 | * Retuns `right` or `left` depending on the scrolling movement to reach its destination
1391 | * from the current slide.
1392 | */
1393 | function getXmovement(fromIndex, toIndex){
1394 | if( fromIndex == toIndex){
1395 | return 'none'
1396 | }
1397 | if(fromIndex > toIndex){
1398 | return 'left';
1399 | }
1400 | return 'right';
1401 | }
1402 |
1403 |
1404 | function createSlimScrolling(element){
1405 | //needed to make `scrollHeight` work under Opera 12
1406 | element.css('overflow', 'hidden');
1407 |
1408 | //in case element is a slide
1409 | var section = element.closest('.fp-section');
1410 | var scrollable = element.find('.fp-scrollable');
1411 |
1412 | //if there was scroll, the contentHeight will be the one in the scrollable section
1413 | if(scrollable.length){
1414 | var contentHeight = scrollable.get(0).scrollHeight;
1415 | }else{
1416 | var contentHeight = element.get(0).scrollHeight;
1417 | if(options.verticalCentered){
1418 | contentHeight = element.find('.fp-tableCell').get(0).scrollHeight;
1419 | }
1420 | }
1421 |
1422 | var scrollHeight = windowsHeight - parseInt(section.css('padding-bottom')) - parseInt(section.css('padding-top'));
1423 |
1424 | //needs scroll?
1425 | if ( contentHeight > scrollHeight) {
1426 | //was there already an scroll ? Updating it
1427 | if(scrollable.length){
1428 | scrollable.css('height', scrollHeight + 'px').parent().css('height', scrollHeight + 'px');
1429 | }
1430 | //creating the scrolling
1431 | else{
1432 | if(options.verticalCentered){
1433 | element.find('.fp-tableCell').wrapInner('');
1434 | }else{
1435 | element.wrapInner('');
1436 | }
1437 |
1438 | element.find('.fp-scrollable').slimScroll({
1439 | allowPageScroll: true,
1440 | height: scrollHeight + 'px',
1441 | size: '10px',
1442 | alwaysVisible: true
1443 | });
1444 | }
1445 | }
1446 |
1447 | //removing the scrolling when it is not necessary anymore
1448 | else{
1449 | removeSlimScroll(element);
1450 | }
1451 |
1452 | //undo
1453 | element.css('overflow', '');
1454 | }
1455 |
1456 | function removeSlimScroll(element){
1457 | element.find('.fp-scrollable').children().first().unwrap().unwrap();
1458 | element.find('.slimScrollBar').remove();
1459 | element.find('.slimScrollRail').remove();
1460 | }
1461 |
1462 | function addTableClass(element){
1463 | element.addClass('fp-table').wrapInner('');
1464 | }
1465 |
1466 | function getTableHeight(element){
1467 | var sectionHeight = windowsHeight;
1468 |
1469 | if(options.paddingTop || options.paddingBottom){
1470 | var section = element;
1471 | if(!section.hasClass('fp-section')){
1472 | section = element.closest('.fp-section');
1473 | }
1474 |
1475 | var paddings = parseInt(section.css('padding-top')) + parseInt(section.css('padding-bottom'));
1476 | sectionHeight = (windowsHeight - paddings);
1477 | }
1478 |
1479 | return sectionHeight;
1480 | }
1481 |
1482 | /**
1483 | * Adds a css3 transform property to the container class with or without animation depending on the animated param.
1484 | */
1485 | function transformContainer(translate3d, animated){
1486 | if(animated){
1487 | addAnimation(container);
1488 | }else{
1489 | removeAnimation(container);
1490 | }
1491 |
1492 | container.css(getTransforms(translate3d));
1493 |
1494 | //syncronously removing the class after the animation has been applied.
1495 | setTimeout(function(){
1496 | container.removeClass('fp-notransition');
1497 | },10)
1498 | }
1499 |
1500 |
1501 | /**
1502 | * Scrolls to the given section and slide
1503 | */
1504 | function scrollPageAndSlide(destiny, slide){
1505 | if (typeof slide === 'undefined') {
1506 | slide = 0;
1507 | }
1508 |
1509 | if(isNaN(destiny)){
1510 | var section = $('[data-anchor="'+destiny+'"]');
1511 | }else{
1512 | var section = $('.fp-section').eq( (destiny -1) );
1513 | }
1514 |
1515 |
1516 | //we need to scroll to the section and then to the slide
1517 | if (destiny !== lastScrolledDestiny && !section.hasClass('active')){
1518 | scrollPage(section, function(){
1519 | scrollSlider(section, slide)
1520 | });
1521 | }
1522 | //if we were already in the section
1523 | else{
1524 | scrollSlider(section, slide);
1525 | }
1526 | }
1527 |
1528 | /**
1529 | * Scrolls the slider to the given slide destination for the given section
1530 | */
1531 | function scrollSlider(section, slide){
1532 | if(typeof slide != 'undefined'){
1533 | var slides = section.find('.fp-slides');
1534 | var destiny = slides.find('[data-anchor="'+slide+'"]');
1535 |
1536 | if(!destiny.length){
1537 | destiny = slides.find('.fp-slide').eq(slide);
1538 | }
1539 |
1540 | if(destiny.length){
1541 | landscapeScroll(slides, destiny);
1542 | }
1543 | }
1544 | }
1545 |
1546 | /**
1547 | * Creates a landscape navigation bar with dots for horizontal sliders.
1548 | */
1549 | function addSlidesNavigation(section, numSlides){
1550 | section.append('
');
1551 | var nav = section.find('.fp-slidesNav');
1552 |
1553 | //top or bottom
1554 | nav.addClass(options.slidesNavPosition);
1555 |
1556 | for(var i=0; i< numSlides; i++){
1557 | nav.find('ul').append('
');
1558 | }
1559 |
1560 | //centering it
1561 | nav.css('margin-left', '-' + (nav.width()/2) + 'px');
1562 |
1563 | nav.find('li').first().find('a').addClass('active');
1564 | }
1565 |
1566 |
1567 | /**
1568 | * Sets the state of the website depending on the active section/slide.
1569 | * It changes the URL hash when needed and updates the body class.
1570 | */
1571 | function setState(slideIndex, slideAnchor, anchorLink, sectionIndex){
1572 | var sectionHash = '';
1573 |
1574 | if(options.anchors.length){
1575 |
1576 | //isn't it the first slide?
1577 | if(slideIndex){
1578 | if(typeof anchorLink !== 'undefined'){
1579 | sectionHash = anchorLink;
1580 | }
1581 |
1582 | //slide without anchor link? We take the index instead.
1583 | if(typeof slideAnchor === 'undefined'){
1584 | slideAnchor = slideIndex;
1585 | }
1586 |
1587 | lastScrolledSlide = slideAnchor;
1588 | setUrlHash(sectionHash + '/' + slideAnchor);
1589 |
1590 | //first slide won't have slide anchor, just the section one
1591 | }else if(typeof slideIndex !== 'undefined'){
1592 | lastScrolledSlide = slideAnchor;
1593 | setUrlHash(anchorLink);
1594 | }
1595 |
1596 | //section without slides
1597 | else{
1598 | setUrlHash(anchorLink);
1599 | }
1600 |
1601 | setBodyClass(location.hash);
1602 | }
1603 | else if(typeof slideIndex !== 'undefined'){
1604 | setBodyClass(sectionIndex + '-' + slideIndex);
1605 | }
1606 | else{
1607 | setBodyClass(String(sectionIndex));
1608 | }
1609 | }
1610 |
1611 | /**
1612 | * Sets the URL hash.
1613 | */
1614 | function setUrlHash(url){
1615 | if(options.recordHistory){
1616 | location.hash = url;
1617 | }else{
1618 | //Mobile Chrome doesn't work the normal way, so... lets use HTML5 for phones :)
1619 | if(isTouchDevice || isTouch){
1620 | history.replaceState(undefined, undefined, "#" + url)
1621 | }else{
1622 | var baseUrl = window.location.href.split('#')[0];
1623 | window.location.replace( baseUrl + '#' + url );
1624 | }
1625 | }
1626 | }
1627 |
1628 | /**
1629 | * Sets a class for the body of the page depending on the active section / slide
1630 | */
1631 | function setBodyClass(text){
1632 | //changing slash for dash to make it a valid CSS style
1633 | text = text.replace('/', '-').replace('#','');
1634 |
1635 | //removing previous anchor classes
1636 | $("body")[0].className = $("body")[0].className.replace(/\b\s?fp-viewing-[^\s]+\b/g, '');
1637 |
1638 | //adding the current anchor
1639 | $("body").addClass("fp-viewing-" + text);
1640 | }
1641 |
1642 | /**
1643 | * Checks for translate3d support
1644 | * @return boolean
1645 | * http://stackoverflow.com/questions/5661671/detecting-transform-translate3d-support
1646 | */
1647 | function support3d() {
1648 | var el = document.createElement('p'),
1649 | has3d,
1650 | transforms = {
1651 | 'webkitTransform':'-webkit-transform',
1652 | 'OTransform':'-o-transform',
1653 | 'msTransform':'-ms-transform',
1654 | 'MozTransform':'-moz-transform',
1655 | 'transform':'transform'
1656 | };
1657 |
1658 | // Add it to the body to get the computed style.
1659 | document.body.insertBefore(el, null);
1660 |
1661 | for (var t in transforms) {
1662 | if (el.style[t] !== undefined) {
1663 | el.style[t] = "translate3d(1px,1px,1px)";
1664 | has3d = window.getComputedStyle(el).getPropertyValue(transforms[t]);
1665 | }
1666 | }
1667 |
1668 | document.body.removeChild(el);
1669 |
1670 | return (has3d !== undefined && has3d.length > 0 && has3d !== "none");
1671 | }
1672 |
1673 |
1674 |
1675 | /**
1676 | * Removes the auto scrolling action fired by the mouse wheel and trackpad.
1677 | * After this function is called, the mousewheel and trackpad movements won't scroll through sections.
1678 | */
1679 | function removeMouseWheelHandler(){
1680 | if (document.addEventListener) {
1681 | document.removeEventListener('mousewheel', MouseWheelHandler, false); //IE9, Chrome, Safari, Oper
1682 | document.removeEventListener('wheel', MouseWheelHandler, false); //Firefox
1683 | } else {
1684 | document.detachEvent("onmousewheel", MouseWheelHandler); //IE 6/7/8
1685 | }
1686 | }
1687 |
1688 |
1689 | /**
1690 | * Adds the auto scrolling action for the mouse wheel and trackpad.
1691 | * After this function is called, the mousewheel and trackpad movements will scroll through sections
1692 | */
1693 | function addMouseWheelHandler(){
1694 | if (document.addEventListener) {
1695 | document.addEventListener("mousewheel", MouseWheelHandler, false); //IE9, Chrome, Safari, Oper
1696 | document.addEventListener("wheel", MouseWheelHandler, false); //Firefox
1697 | } else {
1698 | document.attachEvent("onmousewheel", MouseWheelHandler); //IE 6/7/8
1699 | }
1700 | }
1701 |
1702 |
1703 | /**
1704 | * Adds the possibility to auto scroll through sections on touch devices.
1705 | */
1706 | function addTouchHandler(){
1707 | if(isTouchDevice || isTouch){
1708 | //Microsoft pointers
1709 | MSPointer = getMSPointer();
1710 |
1711 | $(document).off('touchstart ' + MSPointer.down).on('touchstart ' + MSPointer.down, touchStartHandler);
1712 | $(document).off('touchmove ' + MSPointer.move).on('touchmove ' + MSPointer.move, touchMoveHandler);
1713 | }
1714 | }
1715 |
1716 | /**
1717 | * Removes the auto scrolling for touch devices.
1718 | */
1719 | function removeTouchHandler(){
1720 | if(isTouchDevice || isTouch){
1721 | //Microsoft pointers
1722 | MSPointer = getMSPointer();
1723 |
1724 | $(document).off('touchstart ' + MSPointer.down);
1725 | $(document).off('touchmove ' + MSPointer.move);
1726 | }
1727 | }
1728 |
1729 |
1730 | /*
1731 | * Returns and object with Microsoft pointers (for IE<11 and for IE >= 11)
1732 | * http://msdn.microsoft.com/en-us/library/ie/dn304886(v=vs.85).aspx
1733 | */
1734 | function getMSPointer(){
1735 | var pointer;
1736 |
1737 | //IE >= 11 & rest of browsers
1738 | if(window.PointerEvent){
1739 | pointer = { down: "pointerdown", move: "pointermove"};
1740 | }
1741 |
1742 | //IE < 11
1743 | else{
1744 | pointer = { down: "MSPointerDown", move: "MSPointerMove"};
1745 | }
1746 |
1747 | return pointer;
1748 | }
1749 | /**
1750 | * Gets the pageX and pageY properties depending on the browser.
1751 | * https://github.com/alvarotrigo/fullPage.js/issues/194#issuecomment-34069854
1752 | */
1753 | function getEventsPage(e){
1754 | var events = new Array();
1755 |
1756 | events['y'] = (typeof e.pageY !== 'undefined' && (e.pageY || e.pageX) ? e.pageY : e.touches[0].pageY);
1757 | events['x'] = (typeof e.pageX !== 'undefined' && (e.pageY || e.pageX) ? e.pageX : e.touches[0].pageX);
1758 |
1759 | return events;
1760 | }
1761 |
1762 | function silentLandscapeScroll(activeSlide){
1763 | $.fn.fullpage.setScrollingSpeed (0, 'internal');
1764 | landscapeScroll(activeSlide.closest('.fp-slides'), activeSlide);
1765 | $.fn.fullpage.setScrollingSpeed(originals.scrollingSpeed, 'internal');
1766 | }
1767 |
1768 | function silentScroll(top){
1769 | if(options.scrollBar){
1770 | container.scrollTop(top);
1771 | }
1772 | else if (options.css3) {
1773 | var translate3d = 'translate3d(0px, -' + top + 'px, 0px)';
1774 | transformContainer(translate3d, false);
1775 | }
1776 | else {
1777 | container.css("top", -top);
1778 | }
1779 | }
1780 |
1781 | function getTransforms(translate3d){
1782 | return {
1783 | '-webkit-transform': translate3d,
1784 | '-moz-transform': translate3d,
1785 | '-ms-transform':translate3d,
1786 | 'transform': translate3d
1787 | };
1788 | }
1789 |
1790 | function setIsScrollable(value, direction){
1791 | switch (direction){
1792 | case 'up': isScrollAllowed.up = value; break;
1793 | case 'down': isScrollAllowed.down = value; break;
1794 | case 'left': isScrollAllowed.left = value; break;
1795 | case 'right': isScrollAllowed.right = value; break;
1796 | case 'all': $.fn.fullpage.setAllowScrolling(value);
1797 | }
1798 | }
1799 |
1800 |
1801 | /*
1802 | * Destroys fullpage.js plugin events and optinally its html markup and styles
1803 | */
1804 | $.fn.fullpage.destroy = function(all){
1805 | $.fn.fullpage.setAutoScrolling(false, 'internal');
1806 | $.fn.fullpage.setAllowScrolling(false);
1807 | $.fn.fullpage.setKeyboardScrolling(false);
1808 |
1809 |
1810 | $(window)
1811 | .off('scroll', scrollHandler)
1812 | .off('hashchange', hashChangeHandler)
1813 | .off('resize', resizeHandler);
1814 |
1815 | $(document)
1816 | .off('click', '#fp-nav a')
1817 | .off('mouseenter', '#fp-nav li')
1818 | .off('mouseleave', '#fp-nav li')
1819 | .off('click', '.fp-slidesNav a')
1820 | .off('mouseover', options.normalScrollElements)
1821 | .off('mouseout', options.normalScrollElements);
1822 |
1823 | $('.fp-section')
1824 | .off('click', '.fp-controlArrow');
1825 |
1826 | //lets make a mess!
1827 | if(all){
1828 | destroyStructure();
1829 | }
1830 | };
1831 |
1832 | /*
1833 | * Removes inline styles added by fullpage.js
1834 | */
1835 | function destroyStructure(){
1836 | //reseting the `top` or `translate` properties to 0
1837 | silentScroll(0);
1838 |
1839 | $('#fp-nav, .fp-slidesNav, .fp-controlArrow').remove();
1840 |
1841 | //removing inline styles
1842 | $('.fp-section').css( {
1843 | 'height': '',
1844 | 'background-color' : '',
1845 | 'padding': ''
1846 | });
1847 |
1848 | $('.fp-slide').css( {
1849 | 'width': ''
1850 | });
1851 |
1852 | container.css({
1853 | 'height': '',
1854 | 'position': '',
1855 | '-ms-touch-action': '',
1856 | 'touch-action': ''
1857 | });
1858 |
1859 | //removing added classes
1860 | $('.fp-section, .fp-slide').each(function(){
1861 | removeSlimScroll($(this));
1862 | $(this).removeClass('fp-table active');
1863 | });
1864 |
1865 | removeAnimation(container);
1866 | removeAnimation(container.find('.fp-easing'));
1867 |
1868 | //Unwrapping content
1869 | container.find('.fp-tableCell, .fp-slidesContainer, .fp-slides').each(function(){
1870 | //unwrap not being use in case there's no child element inside and its just text
1871 | $(this).replaceWith(this.childNodes);
1872 | });
1873 |
1874 | //scrolling the page to the top with no animation
1875 | $('html, body').scrollTop(0);
1876 | }
1877 |
1878 | /*
1879 | * Sets the state for a variable with multiple states (original, and temporal)
1880 | * Some variables such as `autoScrolling` or `recordHistory` might change automatically its state when using `responsive` or `autoScrolling:false`.
1881 | * This function is used to keep track of both states, the original and the temporal one.
1882 | * If type is not 'internal', then we assume the user is globally changing the variable.
1883 | */
1884 | function setVariableState(variable, value, type){
1885 | options[variable] = value;
1886 | if(type !== 'internal'){
1887 | originals[variable] = value;
1888 | }
1889 | }
1890 |
1891 | /**
1892 | * Displays warnings
1893 | */
1894 | function displayWarnings(){
1895 | // Disable mutually exclusive settings
1896 | if (options.continuousVertical &&
1897 | (options.loopTop || options.loopBottom)) {
1898 | options.continuousVertical = false;
1899 | showError('warn', "Option `loopTop/loopBottom` is mutually exclusive with `continuousVertical`; `continuousVertical` disabled");
1900 | }
1901 | if(options.continuousVertical && options.scrollBar){
1902 | options.continuousVertical = false;
1903 | showError('warn', "Option `scrollBar` is mutually exclusive with `continuousVertical`; `continuousVertical` disabled");
1904 | }
1905 |
1906 | //anchors can not have the same value as any element ID or NAME
1907 | $.each(options.anchors, function(index, name){
1908 | if($('#' + name).length || $('[name="'+name+'"]').length ){
1909 | showError('error', "data-anchor tags can not have the same value as any `id` element on the site (or `name` element for IE).");
1910 | }
1911 | });
1912 | }
1913 |
1914 | function showError(type, text){
1915 | console && console[type] && console[type]('fullPage: ' + text);
1916 | }
1917 | };
1918 | })(jQuery);
1919 |
--------------------------------------------------------------------------------
/fullPage.js/js/jquery.fullPage.min.js:
--------------------------------------------------------------------------------
1 | /**
2 | * fullPage 2.5.4
3 | * https://github.com/alvarotrigo/fullPage.js
4 | * MIT licensed
5 | *
6 | * Copyright (C) 2013 alvarotrigo.com - A project by Alvaro Trigo
7 | */
8 | (function(b){b.fn.fullpage=function(c){function pa(a){a.find(".fp-slides").after('');"#fff"!=c.controlArrowColor&&(a.find(".fp-controlArrow.fp-next").css("border-color","transparent transparent transparent "+c.controlArrowColor),a.find(".fp-controlArrow.fp-prev").css("border-color","transparent "+c.controlArrowColor+" transparent transparent"));c.loopHorizontal||a.find(".fp-controlArrow.fp-prev").hide()}function qa(){b("body").append('