commit 9dad059f70b731932311f2d30a5dc46ab4512942 Author: Yuri van Midden Date: Sun Sep 20 22:46:45 2020 +0200 Initial commit diff --git a/angle-double-down-solid.svg b/angle-double-down-solid.svg new file mode 100644 index 0000000..ae03af7 --- /dev/null +++ b/angle-double-down-solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/covid-19-info-en.json b/covid-19-info-en.json new file mode 100644 index 0000000..e69de29 diff --git a/css/fullpage.css b/css/fullpage.css new file mode 100644 index 0000000..58ef6e2 --- /dev/null +++ b/css/fullpage.css @@ -0,0 +1,224 @@ +/*! + * fullPage 3.0.2 + * https://github.com/alvarotrigo/fullPage.js + * + * @license GPLv3 for open source use only + * or Fullpage Commercial License for commercial use + * http://alvarotrigo.com/fullPage/pricing/ + * + * Copyright (C) 2018 http://alvarotrigo.com/fullPage - A project by Alvaro Trigo + */ +html.fp-enabled, +.fp-enabled body { + margin: 0; + padding: 0; + overflow:hidden; + + /*Avoid flicker on slides transitions for mobile phones #336 */ + -webkit-tap-highlight-color: rgba(0,0,0,0); +} +.fp-section { + position: relative; + -webkit-box-sizing: border-box; /* Safari<=5 Android<=3 */ + -moz-box-sizing: border-box; /* <=28 */ + box-sizing: border-box; +} +.fp-slide { + float: left; +} +.fp-slide, .fp-slidesContainer { + height: 100%; + display: block; +} +.fp-slides { + z-index:1; + height: 100%; + overflow: hidden; + position: relative; + -webkit-transition: all 0.3s ease-out; /* Safari<=6 Android<=4.3 */ + transition: all 0.3s ease-out; +} +.fp-section.fp-table, .fp-slide.fp-table { + display: table; + table-layout:fixed; + width: 100%; +} +.fp-tableCell { + display: table-cell; + vertical-align: middle; + width: 100%; + height: 100%; +} +.fp-slidesContainer { + float: left; + position: relative; +} +.fp-controlArrow { + -webkit-user-select: none; /* webkit (safari, chrome) browsers */ + -moz-user-select: none; /* mozilla browsers */ + -khtml-user-select: none; /* webkit (konqueror) browsers */ + -ms-user-select: none; /* IE10+ */ + position: absolute; + z-index: 4; + top: 50%; + cursor: pointer; + width: 0; + height: 0; + border-style: solid; + margin-top: -38px; + -webkit-transform: translate3d(0,0,0); + -ms-transform: translate3d(0,0,0); + transform: translate3d(0,0,0); +} +.fp-controlArrow.fp-prev { + left: 15px; + width: 0; + border-width: 38.5px 34px 38.5px 0; + border-color: transparent #fff transparent transparent; +} +.fp-controlArrow.fp-next { + right: 15px; + border-width: 38.5px 0 38.5px 34px; + border-color: transparent transparent transparent #fff; +} +.fp-scrollable { + overflow: hidden; + position: relative; +} +.fp-scroller{ + overflow: hidden; +} +.iScrollIndicator{ + border: 0 !important; +} +.fp-notransition { + -webkit-transition: none !important; + transition: none !important; +} +#fp-nav { + position: fixed; + z-index: 100; + margin-top: -32px; + top: 50%; + opacity: 1; + -webkit-transform: translate3d(0,0,0); +} +#fp-nav.fp-right { + right: 17px; +} +#fp-nav.fp-left { + left: 17px; +} +.fp-slidesNav{ + position: absolute; + z-index: 4; + opacity: 1; + -webkit-transform: translate3d(0,0,0); + -ms-transform: translate3d(0,0,0); + transform: translate3d(0,0,0); + left: 0 !important; + right: 0; + margin: 0 auto !important; +} +.fp-slidesNav.fp-bottom { + bottom: 17px; +} +.fp-slidesNav.fp-top { + top: 17px; +} +#fp-nav ul, +.fp-slidesNav ul { + margin: 0; + padding: 0; +} +#fp-nav ul li, +.fp-slidesNav ul li { + display: block; + width: 14px; + height: 13px; + margin: 7px; + position:relative; +} +.fp-slidesNav ul li { + display: inline-block; +} +#fp-nav ul li a, +.fp-slidesNav ul li a { + display: block; + position: relative; + z-index: 1; + width: 100%; + height: 100%; + cursor: pointer; + text-decoration: none; +} +#fp-nav ul li a.active span, +.fp-slidesNav ul li a.active span, +#fp-nav ul li:hover a.active span, +.fp-slidesNav ul li:hover a.active span{ + height: 12px; + width: 12px; + margin: -6px 0 0 -6px; + border-radius: 100%; + } +#fp-nav ul li a span, +.fp-slidesNav ul li a span { + border-radius: 50%; + position: absolute; + z-index: 1; + height: 4px; + width: 4px; + border: 0; + background: #333; + left: 50%; + top: 50%; + margin: -2px 0 0 -2px; + -webkit-transition: all 0.1s ease-in-out; + -moz-transition: all 0.1s ease-in-out; + -o-transition: all 0.1s ease-in-out; + transition: all 0.1s ease-in-out; +} +#fp-nav ul li:hover a span, +.fp-slidesNav ul li:hover a span{ + width: 10px; + height: 10px; + margin: -5px 0px 0px -5px; +} +#fp-nav ul li .fp-tooltip { + position: absolute; + top: -2px; + color: #fff; + font-size: 14px; + font-family: arial, helvetica, sans-serif; + white-space: nowrap; + max-width: 220px; + overflow: hidden; + display: block; + opacity: 0; + width: 0; + cursor: pointer; +} +#fp-nav ul li:hover .fp-tooltip, +#fp-nav.fp-show-active a.active + .fp-tooltip { + -webkit-transition: opacity 0.2s ease-in; + transition: opacity 0.2s ease-in; + width: auto; + opacity: 1; +} +#fp-nav ul li .fp-tooltip.fp-right { + right: 20px; +} +#fp-nav ul li .fp-tooltip.fp-left { + left: 20px; +} +.fp-auto-height.fp-section, +.fp-auto-height .fp-slide, +.fp-auto-height .fp-tableCell{ + height: auto !important; +} + +.fp-responsive .fp-auto-height-responsive.fp-section, +.fp-responsive .fp-auto-height-responsive .fp-slide, +.fp-responsive .fp-auto-height-responsive .fp-tableCell { + height: auto !important; +} \ No newline at end of file diff --git a/harambee.ico b/harambee.ico new file mode 100644 index 0000000..e3a102e Binary files /dev/null and b/harambee.ico differ diff --git a/index.html b/index.html new file mode 100644 index 0000000..e08a63c --- /dev/null +++ b/index.html @@ -0,0 +1,288 @@ + + + + + + + + + + + + + + + + + + + + Harambee - COVID-19 maatregelen + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+
+ +

Informatie over COVID-19 maatregelen bij Harambee

+

De universiteit heeft verschillende regels opgesteld zodat we veilig kunnen sporten. Je vind ze hier op een rijtje.

+

Mochten aan de hand van deze pagina ontduidelijkheden zijn, mail dan het bestuur: bestuur@harambee.nl.

+ + COVID-19 reglement + +
+
+
+
+

Voor sporters

+
    +
  • Was je handen voor en na trainingen en wedstrijden.
  • +
  • Hou buiten rally's altijd 1,5 meter afstand tot elkaar. Ook op de spelersbank.
  • +
  • Voorafgaand aan een wedstrijd mag een team niet de zaal in zolang er nog andere ploegen in de hal bezig zijn.
  • +
  • Voorafgaand aan wedstrijden geven we geen handen.
  • +
  • Bij voorkeur niet yellen binnen 1,5 meter van elkaar.
  • +
  • Na trainingen en wedstrijden moeten de gebruikte ballen worden gedesinfecteerd.
  • +
+
+
+

Faciliteiten

+
    +
  • Kleedkamers zijn beperkt beschikbaar, max. 6 personen per kleedkamer.
  • +
  • Max. 2 personen tegelijk in de douches.
  • +
+
+
+

Voor toeschouwers

+
    +
  • Publiek in de sporthallen is nog niet toegestaan!
  • +
  • De kantine is gewoon geopend. Indien je verzekerd wil zijn van een zitplaats dien je te reserveren.
  • +
+
+
+
+ +
+
+
+ + + + + \ No newline at end of file diff --git a/js/fullpage.js b/js/fullpage.js new file mode 100644 index 0000000..808b42a --- /dev/null +++ b/js/fullpage.js @@ -0,0 +1,3869 @@ +/*! + * fullPage 3.0.2 + * https://github.com/alvarotrigo/fullPage.js + * + * @license GPLv3 for open source use only + * or Fullpage Commercial License for commercial use + * http://alvarotrigo.com/fullPage/pricing/ + * + * Copyright (C) 2018 http://alvarotrigo.com/fullPage - A project by Alvaro Trigo + */ +(function( root, window, document, factory, undefined) { + if( typeof define === 'function' && define.amd ) { + // AMD. Register as an anonymous module. + define( function() { + root.fullpage = factory(window, document); + return root.fullpage; + } ); + } else if( typeof exports === 'object' ) { + // Node. Does not work with strict CommonJS. + module.exports = factory(window, document); + } else { + // Browser globals. + window.fullpage = factory(window, document); + } +}(this, window, document, function(window, document){ + 'use strict'; + + // keeping central set of classnames and selectors + var WRAPPER = 'fullpage-wrapper'; + var WRAPPER_SEL = '.' + WRAPPER; + + // slimscroll + var SCROLLABLE = 'fp-scrollable'; + var SCROLLABLE_SEL = '.' + SCROLLABLE; + + // util + var RESPONSIVE = 'fp-responsive'; + var NO_TRANSITION = 'fp-notransition'; + var DESTROYED = 'fp-destroyed'; + var ENABLED = 'fp-enabled'; + var VIEWING_PREFIX = 'fp-viewing'; + var ACTIVE = 'active'; + var ACTIVE_SEL = '.' + ACTIVE; + var COMPLETELY = 'fp-completely'; + var COMPLETELY_SEL = '.' + COMPLETELY; + + // section + var SECTION_DEFAULT_SEL = '.section'; + var SECTION = 'fp-section'; + var SECTION_SEL = '.' + SECTION; + var SECTION_ACTIVE_SEL = SECTION_SEL + ACTIVE_SEL; + var TABLE_CELL = 'fp-tableCell'; + var TABLE_CELL_SEL = '.' + TABLE_CELL; + var AUTO_HEIGHT = 'fp-auto-height'; + var AUTO_HEIGHT_SEL = '.' + AUTO_HEIGHT; + var NORMAL_SCROLL = 'fp-normal-scroll'; + var NORMAL_SCROLL_SEL = '.' + NORMAL_SCROLL; + + // section nav + var SECTION_NAV = 'fp-nav'; + var SECTION_NAV_SEL = '#' + SECTION_NAV; + var SECTION_NAV_TOOLTIP = 'fp-tooltip'; + var SECTION_NAV_TOOLTIP_SEL='.'+SECTION_NAV_TOOLTIP; + var SHOW_ACTIVE_TOOLTIP = 'fp-show-active'; + + // slide + var SLIDE_DEFAULT_SEL = '.slide'; + var SLIDE = 'fp-slide'; + var SLIDE_SEL = '.' + SLIDE; + var SLIDE_ACTIVE_SEL = SLIDE_SEL + ACTIVE_SEL; + var SLIDES_WRAPPER = 'fp-slides'; + var SLIDES_WRAPPER_SEL = '.' + SLIDES_WRAPPER; + var SLIDES_CONTAINER = 'fp-slidesContainer'; + var SLIDES_CONTAINER_SEL = '.' + SLIDES_CONTAINER; + var TABLE = 'fp-table'; + + // slide nav + var SLIDES_NAV = 'fp-slidesNav'; + var SLIDES_NAV_SEL = '.' + SLIDES_NAV; + var SLIDES_NAV_LINK_SEL = SLIDES_NAV_SEL + ' a'; + var SLIDES_ARROW = 'fp-controlArrow'; + var SLIDES_ARROW_SEL = '.' + SLIDES_ARROW; + var SLIDES_PREV = 'fp-prev'; + var SLIDES_PREV_SEL = '.' + SLIDES_PREV; + var SLIDES_ARROW_PREV = SLIDES_ARROW + ' ' + SLIDES_PREV; + var SLIDES_ARROW_PREV_SEL = SLIDES_ARROW_SEL + SLIDES_PREV_SEL; + var SLIDES_NEXT = 'fp-next'; + var SLIDES_NEXT_SEL = '.' + SLIDES_NEXT; + var SLIDES_ARROW_NEXT = SLIDES_ARROW + ' ' + SLIDES_NEXT; + var SLIDES_ARROW_NEXT_SEL = SLIDES_ARROW_SEL + SLIDES_NEXT_SEL; + + function initialise(containerSelector, options) { + var isLicenseValid = options && new RegExp('([\\d\\w]{8}-){3}[\\d\\w]{8}|OPEN-SOURCE-GPLV3-LICENSE').test(options.licenseKey) || document.domain.indexOf('alvarotrigo.com') > -1; + + //only once my friend! + if(hasClass($('html'), ENABLED)){ displayWarnings(); return; } + + // common jQuery objects + var $htmlBody = $('html, body'); + var $body = $('body')[0]; + + var FP = {}; + + // Creating some defaults, extending them with any options that were provided + options = deepExtend({ + //navigation + menu: false, + anchors:[], + lockAnchors: false, + navigation: false, + navigationPosition: 'right', + navigationTooltips: [], + showActiveTooltip: false, + slidesNavigation: false, + slidesNavPosition: 'bottom', + scrollBar: false, + hybrid: false, + + //scrolling + css3: true, + scrollingSpeed: 700, + autoScrolling: true, + fitToSection: true, + fitToSectionDelay: 1000, + easing: 'easeInOutCubic', + easingcss3: 'ease', + loopBottom: false, + loopTop: false, + loopHorizontal: true, + continuousVertical: false, + continuousHorizontal: false, + scrollHorizontally: false, + interlockedSlides: false, + dragAndMove: false, + offsetSections: false, + resetSliders: false, + fadingEffect: false, + normalScrollElements: null, + scrollOverflow: false, + scrollOverflowReset: false, + scrollOverflowHandler: window.fp_scrolloverflow ? window.fp_scrolloverflow.iscrollHandler : null, + scrollOverflowOptions: null, + touchSensitivity: 5, + normalScrollElementTouchThreshold: 5, + bigSectionsDestination: null, + + //Accessibility + keyboardScrolling: true, + animateAnchor: true, + recordHistory: true, + + //design + controlArrows: true, + controlArrowColor: '#fff', + verticalCentered: true, + sectionsColor : [], + paddingTop: 0, + paddingBottom: 0, + fixedElements: null, + responsive: 0, //backwards compabitility with responsiveWiddth + responsiveWidth: 0, + responsiveHeight: 0, + responsiveSlides: false, + parallax: false, + parallaxOptions: { + type: 'reveal', + percentage: 62, + property: 'translate' + }, + + //Custom selectors + sectionSelector: SECTION_DEFAULT_SEL, + slideSelector: SLIDE_DEFAULT_SEL, + + //events + v2compatible: false, + afterLoad: null, + onLeave: null, + afterRender: null, + afterResize: null, + afterReBuild: null, + afterSlideLoad: null, + onSlideLeave: null, + afterResponsive: null, + + lazyLoading: true + }, options); + + //flag to avoid very fast sliding for landscape sliders + var slideMoving = false; + + var isTouchDevice = navigator.userAgent.match(/(iPhone|iPod|iPad|Android|playbook|silk|BlackBerry|BB10|Windows Phone|Tizen|Bada|webOS|IEMobile|Opera Mini)/); + var isTouch = (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0) || (navigator.maxTouchPoints)); + var container = typeof containerSelector === 'string' ? $(containerSelector)[0] : containerSelector; + var windowsHeight = getWindowHeight(); + var isResizing = false; + var isWindowFocused = true; + var lastScrolledDestiny; + var lastScrolledSlide; + var canScroll = true; + var scrollings = []; + var controlPressed; + var startingSection; + var isScrollAllowed = {}; + isScrollAllowed.m = { 'up':true, 'down':true, 'left':true, 'right':true }; + isScrollAllowed.k = deepExtend({}, isScrollAllowed.m); + var MSPointer = getMSPointer(); + var events = { + touchmove: 'ontouchmove' in window ? 'touchmove' : MSPointer.move, + touchstart: 'ontouchstart' in window ? 'touchstart' : MSPointer.down + }; + var scrollBarHandler; + + // taken from https://github.com/udacity/ud891/blob/gh-pages/lesson2-focus/07-modals-and-keyboard-traps/solution/modal.js + var focusableElementsString = 'a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, [tabindex="0"], [contenteditable]'; + + //timeouts + var resizeId; + var afterSectionLoadsId; + var afterSlideLoadsId; + var scrollId; + var scrollId2; + var keydownId; + var originals = deepExtend({}, options); //deep copy + var activeAnimation; + + displayWarnings(); + + //easeInOutCubic animation included in the plugin + window.fp_easings = deepExtend(window.fp_easings, { + easeInOutCubic: function (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; + } + }); + + /** + * Sets the autoScroll option. + * It changes the scroll bar visibility and the history of the site as a result. + */ + function setAutoScrolling(value, type){ + //removing the transformation + if(!value){ + silentScroll(0); + } + + setVariableState('autoScrolling', value, type); + + var element = $(SECTION_ACTIVE_SEL)[0]; + + if(options.autoScrolling && !options.scrollBar){ + css($htmlBody, { + 'overflow': 'hidden', + 'height': '100%' + }); + + setRecordHistory(originals.recordHistory, 'internal'); + + //for IE touch devices + css(container, { + '-ms-touch-action': 'none', + 'touch-action': 'none' + }); + + if(element != null){ + //moving the container up + silentScroll(element.offsetTop); + } + + }else{ + css($htmlBody, { + 'overflow' : 'visible', + 'height' : 'initial' + }); + + setRecordHistory(false, 'internal'); + + //for IE touch devices + css(container, { + '-ms-touch-action': '', + 'touch-action': '' + }); + + //scrolling the page to the section with no animation + if (element != null) { + var scrollSettings = getScrollSettings(element.offsetTop); + scrollSettings.element.scrollTo(0, scrollSettings.options); + } + } + } + + /** + * Defines wheter to record the history for each hash change in the URL. + */ + function setRecordHistory(value, type){ + setVariableState('recordHistory', value, type); + } + + /** + * Defines the scrolling speed + */ + function setScrollingSpeed(value, type){ + setVariableState('scrollingSpeed', value, type); + } + + /** + * Sets fitToSection + */ + function setFitToSection(value, type){ + setVariableState('fitToSection', value, type); + } + + /** + * Sets lockAnchors + */ + function setLockAnchors(value){ + options.lockAnchors = value; + } + + /** + * Adds or remove the possibility of scrolling through sections by using the mouse wheel or the trackpad. + */ + function setMouseWheelScrolling(value){ + if(value){ + addMouseWheelHandler(); + addMiddleWheelHandler(); + }else{ + removeMouseWheelHandler(); + removeMiddleWheelHandler(); + } + } + + /** + * Adds or remove the possibility of scrolling through sections by using the mouse wheel/trackpad or touch gestures. + * Optionally a second parameter can be used to specify the direction for which the action will be applied. + * + * @param directions string containing the direction or directions separated by comma. + */ + function setAllowScrolling(value, directions){ + if(typeof directions !== 'undefined'){ + directions = directions.replace(/ /g,'').split(','); + + directions.forEach(function (direction){ + setIsScrollAllowed(value, direction, 'm'); + }); + } + else{ + setIsScrollAllowed(value, 'all', 'm'); + + if(value){ + setMouseWheelScrolling(true); + addTouchHandler(); + }else{ + setMouseWheelScrolling(false); + removeTouchHandler(); + } + } + } + + /** + * Adds or remove the possibility of scrolling through sections by using the keyboard arrow keys + */ + function setKeyboardScrolling(value, directions){ + if(typeof directions !== 'undefined'){ + directions = directions.replace(/ /g,'').split(','); + + directions.forEach(function(direction){ + setIsScrollAllowed(value, direction, 'k'); + }); + }else{ + setIsScrollAllowed(value, 'all', 'k'); + options.keyboardScrolling = value; + } + } + + /** + * Moves the page up one section. + */ + function moveSectionUp(){ + var prev = prevUntil($(SECTION_ACTIVE_SEL)[0], SECTION_SEL); + + //looping to the bottom if there's no more sections above + if (!prev && (options.loopTop || options.continuousVertical)) { + prev = last($(SECTION_SEL)); + } + + if (prev != null) { + scrollPage(prev, null, true); + } + } + + /** + * Moves the page down one section. + */ + function moveSectionDown(){ + var next = nextUntil($(SECTION_ACTIVE_SEL)[0], SECTION_SEL); + + //looping to the top if there's no more sections below + if(!next && + (options.loopBottom || options.continuousVertical)){ + next = $(SECTION_SEL)[0]; + } + + if(next != null){ + scrollPage(next, null, false); + } + } + + /** + * Moves the page to the given section and slide with no animation. + * Anchors or index positions can be used as params. + */ + function silentMoveTo(sectionAnchor, slideAnchor){ + setScrollingSpeed (0, 'internal'); + moveTo(sectionAnchor, slideAnchor); + setScrollingSpeed (originals.scrollingSpeed, 'internal'); + } + + /** + * Moves the page to the given section and slide. + * Anchors or index positions can be used as params. + */ + function moveTo(sectionAnchor, slideAnchor){ + var destiny = getSectionByAnchor(sectionAnchor); + + if (typeof slideAnchor !== 'undefined'){ + scrollPageAndSlide(sectionAnchor, slideAnchor); + }else if(destiny != null){ + scrollPage(destiny); + } + } + + /** + * Slides right the slider of the active section. + * Optional `section` param. + */ + function moveSlideRight(section){ + moveSlide('right', section); + } + + /** + * Slides left the slider of the active section. + * Optional `section` param. + */ + function moveSlideLeft(section){ + moveSlide('left', section); + } + + /** + * When resizing is finished, we adjust the slides sizes and positions + */ + function reBuild(resizing){ + if(hasClass(container, DESTROYED)){ return; } //nothing to do if the plugin was destroyed + + isResizing = true; + + windowsHeight = getWindowHeight(); //updating global var + + var sections = $(SECTION_SEL); + for (var i = 0; i < sections.length; ++i) { + var section = sections[i]; + var slidesWrap = $(SLIDES_WRAPPER_SEL, section)[0]; + var slides = $(SLIDE_SEL, section); + + //adjusting the height of the table-cell for IE and Firefox + if(options.verticalCentered){ + css($(TABLE_CELL_SEL, section), {'height': getTableHeight(section) + 'px'}); + } + + css(section, {'height': windowsHeight + 'px'}); + + //adjusting the position fo the FULL WIDTH slides... + if (slides.length > 1) { + landscapeScroll(slidesWrap, $(SLIDE_ACTIVE_SEL, slidesWrap)[0]); + } + } + + if(options.scrollOverflow){ + scrollBarHandler.createScrollBarForAll(); + } + + var activeSection = $(SECTION_ACTIVE_SEL)[0]; + var sectionIndex = index(activeSection, SECTION_SEL); + + //isn't it the first section? + if(sectionIndex){ + //adjusting the position for the current section + silentMoveTo(sectionIndex + 1); + } + + isResizing = false; + if(isFunction( options.afterResize ) && resizing){ + options.afterResize.call(container, window.innerWidth, window.innerHeight); + } + if(isFunction( options.afterReBuild ) && !resizing){ + options.afterReBuild.call(container); + } + } + + /** + * Turns fullPage.js to normal scrolling mode when the viewport `width` or `height` + * are smaller than the set limit values. + */ + function setResponsive(active){ + var isResponsive = hasClass($body, RESPONSIVE); + + if(active){ + if(!isResponsive){ + setAutoScrolling(false, 'internal'); + setFitToSection(false, 'internal'); + hide($(SECTION_NAV_SEL)); + addClass($body, RESPONSIVE); + if(isFunction( options.afterResponsive )){ + options.afterResponsive.call( container, active); + } + } + } + else if(isResponsive){ + setAutoScrolling(originals.autoScrolling, 'internal'); + setFitToSection(originals.autoScrolling, 'internal'); + show($(SECTION_NAV_SEL)); + removeClass($body, RESPONSIVE); + if(isFunction( options.afterResponsive )){ + options.afterResponsive.call( container, active); + } + } + } + + if(container){ + //public functions + FP.version = '3.0.2'; + FP.setAutoScrolling = setAutoScrolling; + FP.setRecordHistory = setRecordHistory; + FP.setScrollingSpeed = setScrollingSpeed; + FP.setFitToSection = setFitToSection; + FP.setLockAnchors = setLockAnchors; + FP.setMouseWheelScrolling = setMouseWheelScrolling; + FP.setAllowScrolling = setAllowScrolling; + FP.setKeyboardScrolling = setKeyboardScrolling; + FP.moveSectionUp = moveSectionUp; + FP.moveSectionDown = moveSectionDown; + FP.silentMoveTo = silentMoveTo; + FP.moveTo = moveTo; + FP.moveSlideRight = moveSlideRight; + FP.moveSlideLeft = moveSlideLeft; + FP.fitToSection = fitToSection; + FP.reBuild = reBuild; + FP.setResponsive = setResponsive; + FP.getFullpageData = options; + FP.destroy = destroy; + FP.getActiveSection = getActiveSection; + FP.getActiveSlide = getActiveSlide; + + FP.test = { + top: '0px', + translate3d: 'translate3d(0px, 0px, 0px)', + translate3dH: (function(){ + var a = []; + for(var i = 0; i < $(options.sectionSelector, container).length; i++){ + a.push('translate3d(0px, 0px, 0px)'); + } + return a; + })(), + left: (function(){ + var a = []; + for(var i = 0; i < $(options.sectionSelector, container).length; i++){ + a.push(0); + } + return a; + })(), + options: options, + setAutoScrolling: setAutoScrolling + }; + + //functions we want to share across files but which are not + //mean to be used on their own by developers + FP.shared = { + afterRenderActions: afterRenderActions + }; + + window.fullpage_api = FP; + + init(); + + bindEvents(); + } + + function init(){ + //if css3 is not supported, it will use jQuery animations + if(options.css3){ + options.css3 = support3d(); + } + + options.scrollBar = options.scrollBar || options.hybrid; + + setOptionsFromDOM(); + prepareDom(); + setAllowScrolling(true); + setAutoScrolling(options.autoScrolling, 'internal'); + responsive(); + + //setting the class for the body element + setBodyClass(); + + if(document.readyState === 'complete'){ + scrollToAnchor(); + } + window.addEventListener('load', scrollToAnchor); + } + + function bindEvents(){ + + //when scrolling... + window.addEventListener('scroll', scrollHandler); + + //detecting any change on the URL to scroll to the given anchor link + //(a way to detect back history button as we play with the hashes on the URL) + window.addEventListener('hashchange', hashChangeHandler); + + //when opening a new tab (ctrl + t), `control` won't be pressed when coming back. + window.addEventListener('blur', blurHandler); + + //when resizing the site, we adjust the heights of the sections, slimScroll... + window.addEventListener('resize', resizeHandler); + + //Sliding with arrow keys, both, vertical and horizontal + document.addEventListener('keydown', keydownHandler); + + //to prevent scrolling while zooming + document.addEventListener('keyup', keyUpHandler); + + //Scrolls to the section when clicking the navigation bullet + //simulating the jQuery .on('click') event using delegation + ['click', 'touchstart'].forEach(function(eventName){ + document.addEventListener(eventName, function(e){ + var target = e.target; + + if(target && closest(target, SECTION_NAV_SEL + ' a')){ + sectionBulletHandler.call(target, e); + } + else if(matches(target, SECTION_NAV_TOOLTIP_SEL)){ + tooltipTextHandler.call(target); + } + else if(matches(target, SLIDES_ARROW_SEL)){ + slideArrowHandler.call(target, e); + } + else if(matches(target, SLIDES_NAV_LINK_SEL) || closest(target, SLIDES_NAV_LINK_SEL) != null){ + slideBulletHandler.call(target, e); + } + }); + }); + + /** + * Applying normalScroll elements. + * Ignoring the scrolls over the specified selectors. + */ + if(options.normalScrollElements){ + ['mouseenter', 'touchstart'].forEach(function(eventName){ + forMouseLeaveOrTOuch(eventName, false); + }); + + ['mouseleave', 'touchend'].forEach(function(eventName){ + forMouseLeaveOrTOuch(eventName, true); + }); + } + } + + function forMouseLeaveOrTOuch(eventName, allowScrolling){ + //a way to pass arguments to the onMouseEnterOrLeave function + document['fp_' + eventName] = allowScrolling; + document.addEventListener(eventName, onMouseEnterOrLeave, true); //capturing phase + } + + function onMouseEnterOrLeave(e) { + if(e.target == document){ + return; + } + var normalSelectors = options.normalScrollElements.split(','); + normalSelectors.forEach(function(normalSelector){ + if(matches(e.target, normalSelector)){ + setAllowScrolling(document['fp_' + e.type]); //e.type = eventName + } + }); + } + + /** + * Setting options from DOM elements if they are not provided. + */ + function setOptionsFromDOM(){ + + //no anchors option? Checking for them in the DOM attributes + if(!options.anchors.length){ + var attrName = '[data-anchor]'; + var anchors = $(options.sectionSelector.split(',').join(attrName + ',') + attrName, container); + if(anchors.length){ + anchors.forEach(function(item){ + options.anchors.push(item.getAttribute('data-anchor').toString()); + }); + } + } + + //no tooltips option? Checking for them in the DOM attributes + if(!options.navigationTooltips.length){ + var attrName = '[data-tooltip]'; + var tooltips = $(options.sectionSelector.split(',').join(attrName + ',') + attrName, container); + if(tooltips.length){ + tooltips.forEach(function(item){ + options.navigationTooltips.push(item.getAttribute('data-tooltip').toString()); + }); + } + } + } + + /** + * Works over the DOM structure to set it up for the current fullpage options. + */ + function prepareDom(){ + css(container, { + 'height': '100%', + 'position': 'relative' + }); + + //adding a class to recognize the container internally in the code + addClass(container, WRAPPER); + addClass($('html'), ENABLED); + + //due to https://github.com/alvarotrigo/fullPage.js/issues/1502 + windowsHeight = getWindowHeight(); + + removeClass(container, DESTROYED); //in case it was destroyed before initializing it again + + addInternalSelectors(); + + var sections = $(SECTION_SEL); + + //styling the sections / slides / menu + for(var i = 0; i 0) { + styleSlides(section, slides, numSlides); + }else{ + if(options.verticalCentered){ + addTableClass(section); + } + } + } + + //fixed elements need to be moved out of the plugin container due to problems with CSS3. + if(options.fixedElements && options.css3){ + $(options.fixedElements).forEach(function(item){ + $body.appendChild(item); + }); + } + + //vertical centered of the navigation + active bullet + if(options.navigation){ + addVerticalNavigation(); + } + + enableYoutubeAPI(); + + if(options.scrollOverflow){ + scrollBarHandler = options.scrollOverflowHandler.init(options); + }else{ + afterRenderActions(); + } + } + + /** + * Styles the horizontal slides for a section. + */ + function styleSlides(section, slides, numSlides){ + var sliderWidth = numSlides * 100; + var slideWidth = 100 / numSlides; + + var slidesWrapper = document.createElement('div'); + slidesWrapper.className = SLIDES_WRAPPER; //fp-slides + wrapAll(slides, slidesWrapper); + + var slidesContainer = document.createElement('div'); + slidesContainer.className = SLIDES_CONTAINER; //fp-slidesContainer + wrapAll(slides, slidesContainer); + + css($(SLIDES_CONTAINER_SEL, section), {'width': sliderWidth + '%'}); + + if(numSlides > 1){ + if(options.controlArrows){ + createSlideArrows(section); + } + + if(options.slidesNavigation){ + addSlidesNavigation(section, numSlides); + } + } + + slides.forEach(function(slide) { + css(slide, {'width': slideWidth + '%'}); + + if(options.verticalCentered){ + addTableClass(slide); + } + }); + + var startingSlide = $(SLIDE_ACTIVE_SEL, section)[0]; + + //if the slide won't be an starting point, the default will be the first one + //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. + if( startingSlide != null && (index($(SECTION_ACTIVE_SEL), SECTION_SEL) !== 0 || (index($(SECTION_ACTIVE_SEL), SECTION_SEL) === 0 && index(startingSlide) !== 0))){ + silentLandscapeScroll(startingSlide, 'internal'); + }else{ + addClass(slides[0], ACTIVE); + } + } + + /** + * Styling vertical sections + */ + function styleSection(section, index){ + //if no active section is defined, the 1st one will be the default one + if(!index && $(SECTION_ACTIVE_SEL)[0] == null) { + addClass(section, ACTIVE); + } + startingSection = $(SECTION_ACTIVE_SEL)[0]; + + css(section, {'height': windowsHeight + 'px'}); + + if(options.paddingTop){ + css(section, {'padding-top': options.paddingTop}); + } + + if(options.paddingBottom){ + css(section, {'padding-bottom': options.paddingBottom}); + } + + if (typeof options.sectionsColor[index] !== 'undefined') { + css(section, {'background-color': options.sectionsColor[index]}); + } + + if (typeof options.anchors[index] !== 'undefined') { + section.setAttribute('data-anchor', options.anchors[index]); + } + } + + /** + * Sets the data-anchor attributes to the menu elements and activates the current one. + */ + function styleMenu(section, index){ + if (typeof options.anchors[index] !== 'undefined') { + //activating the menu / nav element on load + if(hasClass(section, ACTIVE)){ + activateMenuAndNav(options.anchors[index], index); + } + } + + //moving the menu outside the main container if it is inside (avoid problems with fixed positions when using CSS3 tranforms) + if(options.menu && options.css3 && closest($(options.menu)[0], WRAPPER_SEL) != null){ + $body.appendChild($(options.menu)[0]); + } + } + + /** + * Adds internal classes to be able to provide customizable selectors + * keeping the link with the style sheet. + */ + function addInternalSelectors(){ + addClass($(options.sectionSelector, container), SECTION); + addClass($(options.slideSelector, container), SLIDE); + } + + /** + * Creates the control arrows for the given section + */ + function createSlideArrows(section){ + var arrows = [createElementFromHTML('
'), createElementFromHTML('
')]; + after($(SLIDES_WRAPPER_SEL, section)[0], arrows); + + if(options.controlArrowColor !== '#fff'){ + css($(SLIDES_ARROW_NEXT_SEL, section), {'border-color': 'transparent transparent transparent '+options.controlArrowColor}); + css($(SLIDES_ARROW_PREV_SEL, section), {'border-color': 'transparent '+ options.controlArrowColor + ' transparent transparent'}); + } + + if(!options.loopHorizontal){ + hide($(SLIDES_ARROW_PREV_SEL, section)); + } + } + + /** + * Creates a vertical navigation bar. + */ + function addVerticalNavigation(){ + var navigation = document.createElement('div'); + navigation.setAttribute('id', SECTION_NAV); + + var divUl = document.createElement('ul'); + navigation.appendChild(divUl); + + appendTo(navigation, $body); + var nav = $(SECTION_NAV_SEL)[0]; + + addClass(nav, 'fp-' + options.navigationPosition); + + if(options.showActiveTooltip){ + addClass(nav, SHOW_ACTIVE_TOOLTIP); + } + + var li = ''; + + for (var i = 0; i < $(SECTION_SEL).length; i++) { + var link = ''; + if (options.anchors.length) { + link = options.anchors[i]; + } + + li += '
  • '; + + // Only add tooltip if needed (defined by user) + var tooltip = options.navigationTooltips[i]; + + if (typeof tooltip !== 'undefined' && tooltip !== '') { + li += '
    ' + tooltip + '
    '; + } + + li += '
  • '; + } + $('ul', nav)[0].innerHTML = li; + + //centering it vertically + css($(SECTION_NAV_SEL), {'margin-top': '-' + ($(SECTION_NAV_SEL)[0].offsetHeight/2) + 'px'}); + + //activating the current active section + + var bullet = $('li', $(SECTION_NAV_SEL)[0])[index($(SECTION_ACTIVE_SEL)[0], SECTION_SEL)]; + addClass($('a', bullet), ACTIVE); + } + + /* + * Enables the Youtube videos API so we can control their flow if necessary. + */ + function enableYoutubeAPI(){ + $('iframe[src*="youtube.com/embed/"]', container).forEach(function(item){ + addURLParam(item, 'enablejsapi=1'); + }); + } + + /** + * Adds a new parameter and its value to the `src` of a given element + */ + function addURLParam(element, newParam){ + var originalSrc = element.getAttribute('src'); + element.setAttribute('src', originalSrc + getUrlParamSign(originalSrc) + newParam); + } + + /* + * Returns the prefix sign to use for a new parameter in an existen URL. + * + * @return {String} ? | & + */ + function getUrlParamSign(url){ + return ( !/\?/.test( url ) ) ? '?' : '&'; + } + + /** + * Actions and callbacks to fire afterRender + */ + function afterRenderActions(){ + var section = $(SECTION_ACTIVE_SEL)[0]; + + addClass(section, COMPLETELY); + + lazyLoad(section); + playMedia(section); + + if(options.scrollOverflow){ + options.scrollOverflowHandler.afterLoad(); + } + + if(isDestinyTheStartingSection() && isFunction(options.afterLoad) ){ + fireCallback('afterLoad', { + activeSection: null, + element: section, + direction: null, + + //for backwards compatibility callback (to be removed in a future!) + anchorLink: section.getAttribute('data-anchor'), + sectionIndex: index(section, SECTION_SEL) + }); + } + + if(isFunction(options.afterRender)){ + fireCallback('afterRender'); + } + } + + /** + * Determines if the URL anchor destiny is the starting section (the one using 'active' class before initialization) + */ + function isDestinyTheStartingSection(){ + var destinationSection = getSectionByAnchor(getAnchorsURL().section); + return !destinationSection || typeof destinationSection !=='undefined' && index(destinationSection) === index(startingSection); + } + + var isScrolling = false; + var lastScroll = 0; + + //when scrolling... + function scrollHandler(){ + var currentSection; + + if(!options.autoScrolling || options.scrollBar){ + var currentScroll = getScrollTop(); + var scrollDirection = getScrollDirection(currentScroll); + var visibleSectionIndex = 0; + var screen_mid = currentScroll + (getWindowHeight() / 2.0); + var isAtBottom = $body.offsetHeight - getWindowHeight() === currentScroll; + var sections = $(SECTION_SEL); + + //when using `auto-height` for a small last section it won't be centered in the viewport + if(isAtBottom){ + visibleSectionIndex = sections.length - 1; + } + //is at top? when using `auto-height` for a small first section it won't be centered in the viewport + else if(!currentScroll){ + visibleSectionIndex = 0; + } + + //taking the section which is showing more content in the viewport + else{ + for (var i = 0; i < sections.length; ++i) { + var section = sections[i]; + + // Pick the the last section which passes the middle line of the screen. + if (section.offsetTop <= screen_mid) + { + visibleSectionIndex = i; + } + } + } + + if(isCompletelyInViewPort(scrollDirection)){ + if(!hasClass($(SECTION_ACTIVE_SEL)[0], COMPLETELY)){ + addClass($(SECTION_ACTIVE_SEL)[0], COMPLETELY); + removeClass(siblings($(SECTION_ACTIVE_SEL)[0]), COMPLETELY); + } + } + + //geting the last one, the current one on the screen + currentSection = sections[visibleSectionIndex]; + + //setting the visible section as active when manually scrolling + //executing only once the first time we reach the section + if(!hasClass(currentSection, ACTIVE)){ + isScrolling = true; + var leavingSection = $(SECTION_ACTIVE_SEL)[0]; + var leavingSectionIndex = index(leavingSection, SECTION_SEL) + 1; + var yMovement = getYmovement(currentSection); + var anchorLink = currentSection.getAttribute('data-anchor'); + var sectionIndex = index(currentSection, SECTION_SEL) + 1; + var activeSlide = $(SLIDE_ACTIVE_SEL, currentSection)[0]; + var slideIndex; + var slideAnchorLink; + var callbacksParams = { + activeSection: leavingSection, + sectionIndex: sectionIndex -1, + anchorLink: anchorLink, + element: currentSection, + leavingSection: leavingSectionIndex, + direction: yMovement + }; + + if(activeSlide){ + slideAnchorLink = activeSlide.getAttribute('data-anchor'); + slideIndex = index(activeSlide); + } + + if(canScroll){ + addClass(currentSection, ACTIVE); + removeClass(siblings(currentSection), ACTIVE); + + if(isFunction( options.onLeave )){ + fireCallback('onLeave', callbacksParams); + } + if(isFunction( options.afterLoad )){ + fireCallback('afterLoad', callbacksParams); + } + + stopMedia(leavingSection); + lazyLoad(currentSection); + playMedia(currentSection); + + activateMenuAndNav(anchorLink, sectionIndex - 1); + + if(options.anchors.length){ + //needed to enter in hashChange event when using the menu with anchor links + lastScrolledDestiny = anchorLink; + } + setState(slideIndex, slideAnchorLink, anchorLink, sectionIndex); + } + + //small timeout in order to avoid entering in hashChange event when scrolling is not finished yet + clearTimeout(scrollId); + scrollId = setTimeout(function(){ + isScrolling = false; + }, 100); + } + + if(options.fitToSection){ + //for the auto adjust of the viewport to fit a whole section + clearTimeout(scrollId2); + + scrollId2 = setTimeout(function(){ + //checking it again in case it changed during the delay + if(options.fitToSection && + + //is the destination element bigger than the viewport? + $(SECTION_ACTIVE_SEL)[0].offsetHeight <= windowsHeight + ){ + fitToSection(); + } + }, options.fitToSectionDelay); + } + } + } + + /** + * Fits the site to the nearest active section + */ + function fitToSection(){ + //checking fitToSection again in case it was set to false before the timeout delay + if(canScroll){ + //allows to scroll to an active section and + //if the section is already active, we prevent firing callbacks + isResizing = true; + + scrollPage($(SECTION_ACTIVE_SEL)[0]); + isResizing = false; + } + } + + /** + * Determines whether the active section has seen in its whole or not. + */ + function isCompletelyInViewPort(movement){ + var top = $(SECTION_ACTIVE_SEL)[0].offsetTop; + var bottom = top + getWindowHeight(); + + if(movement == 'up'){ + return bottom >= (getScrollTop() + getWindowHeight()); + } + return top <= getScrollTop(); + } + + /** + * Gets the directon of the the scrolling fired by the scroll event. + */ + function getScrollDirection(currentScroll){ + var direction = currentScroll > lastScroll ? 'down' : 'up'; + + lastScroll = currentScroll; + + //needed for auto-height sections to determine if we want to scroll to the top or bottom of the destination + previousDestTop = currentScroll; + + return direction; + } + + /** + * Determines the way of scrolling up or down: + * by 'automatically' scrolling a section or by using the default and normal scrolling. + */ + function scrolling(type){ + if (!isScrollAllowed.m[type]){ + return; + } + + var scrollSection = (type === 'down') ? moveSectionDown : moveSectionUp; + + if(options.scrollOverflow){ + var scrollable = options.scrollOverflowHandler.scrollable($(SECTION_ACTIVE_SEL)[0]); + var check = (type === 'down') ? 'bottom' : 'top'; + + if(scrollable != null ){ + //is the scrollbar at the start/end of the scroll? + if(options.scrollOverflowHandler.isScrolled(check, scrollable)){ + scrollSection(); + }else{ + return true; + } + }else{ + // moved up/down + scrollSection(); + } + }else{ + // moved up/down + scrollSection(); + } + } + + /* + * Preventing bouncing in iOS #2285 + */ + function preventBouncing(e){ + if(options.autoScrolling && isReallyTouch(e)){ + //preventing the easing on iOS devices + preventDefault(e); + } + } + + var touchStartY = 0; + var touchStartX = 0; + var touchEndY = 0; + var touchEndX = 0; + + /* Detecting touch events + + * As we are changing the top property of the page on scrolling, we can not use the traditional way to detect it. + * This way, the touchstart and the touch moves shows an small difference between them which is the + * used one to determine the direction. + */ + function touchMoveHandler(e){ + var activeSection = closest(e.target, SECTION_SEL); + + // additional: if one of the normalScrollElements isn't within options.normalScrollElementTouchThreshold hops up the DOM chain + if (isReallyTouch(e) ) { + + if(options.autoScrolling){ + //preventing the easing on iOS devices + preventDefault(e); + } + + var touchEvents = getEventsPage(e); + + touchEndY = touchEvents.y; + touchEndX = touchEvents.x; + + //if movement in the X axys is greater than in the Y and the currect section has slides... + if ($(SLIDES_WRAPPER_SEL, activeSection).length && Math.abs(touchStartX - touchEndX) > (Math.abs(touchStartY - touchEndY))) { + + //is the movement greater than the minimum resistance to scroll? + if (!slideMoving && Math.abs(touchStartX - touchEndX) > (window.innerWidth / 100 * options.touchSensitivity)) { + if (touchStartX > touchEndX) { + if(isScrollAllowed.m.right){ + moveSlideRight(activeSection); //next + } + } else { + if(isScrollAllowed.m.left){ + moveSlideLeft(activeSection); //prev + } + } + } + } + + //vertical scrolling (only when autoScrolling is enabled) + else if(options.autoScrolling && canScroll){ + + //is the movement greater than the minimum resistance to scroll? + if (Math.abs(touchStartY - touchEndY) > (window.innerHeight / 100 * options.touchSensitivity)) { + if (touchStartY > touchEndY) { + scrolling('down'); + } else if (touchEndY > touchStartY) { + scrolling('up'); + } + } + } + } + } + + /** + * As IE >= 10 fires both touch and mouse events when using a mouse in a touchscreen + * this way we make sure that is really a touch event what IE is detecting. + */ + function isReallyTouch(e){ + //if is not IE || IE is detecting `touch` or `pen` + return typeof e.pointerType === 'undefined' || e.pointerType != 'mouse'; + } + + /** + * Handler for the touch start event. + */ + function touchStartHandler(e){ + + //stopping the auto scroll to adjust to a section + if(options.fitToSection){ + activeAnimation = false; + } + + if(isReallyTouch(e)){ + var touchEvents = getEventsPage(e); + touchStartY = touchEvents.y; + touchStartX = touchEvents.x; + } + } + + /** + * Gets the average of the last `number` elements of the given array. + */ + function getAverage(elements, number){ + var sum = 0; + + //taking `number` elements from the end to make the average, if there are not enought, 1 + var lastElements = elements.slice(Math.max(elements.length - number, 1)); + + for(var i = 0; i < lastElements.length; i++){ + sum = sum + lastElements[i]; + } + + return Math.ceil(sum/number); + } + + /** + * Detecting mousewheel scrolling + * + * http://blogs.sitepointstatic.com/examples/tech/mouse-wheel/index.html + * http://www.sitepoint.com/html5-javascript-mouse-wheel/ + */ + var prevTime = new Date().getTime(); + + function MouseWheelHandler(e) { + var curTime = new Date().getTime(); + var isNormalScroll = hasClass($(COMPLETELY_SEL)[0], NORMAL_SCROLL); + + //autoscrolling and not zooming? + if(options.autoScrolling && !controlPressed && !isNormalScroll){ + // cross-browser wheel delta + e = e || window.event; + var value = e.wheelDelta || -e.deltaY || -e.detail; + var delta = Math.max(-1, Math.min(1, value)); + + var horizontalDetection = typeof e.wheelDeltaX !== 'undefined' || typeof e.deltaX !== 'undefined'; + var isScrollingVertically = (Math.abs(e.wheelDeltaX) < Math.abs(e.wheelDelta)) || (Math.abs(e.deltaX ) < Math.abs(e.deltaY) || !horizontalDetection); + + //Limiting the array to 150 (lets not waste memory!) + if(scrollings.length > 149){ + scrollings.shift(); + } + + //keeping record of the previous scrollings + scrollings.push(Math.abs(value)); + + //preventing to scroll the site on mouse wheel when scrollbar is present + if(options.scrollBar){ + preventDefault(e); + } + + //time difference between the last scroll and the current one + var timeDiff = curTime-prevTime; + prevTime = curTime; + + //haven't they scrolled in a while? + //(enough to be consider a different scrolling action to scroll another section) + if(timeDiff > 200){ + //emptying the array, we dont care about old scrollings for our averages + scrollings = []; + } + + if(canScroll){ + var averageEnd = getAverage(scrollings, 10); + var averageMiddle = getAverage(scrollings, 70); + var isAccelerating = averageEnd >= averageMiddle; + + //to avoid double swipes... + if(isAccelerating && isScrollingVertically){ + //scrolling down? + if (delta < 0) { + scrolling('down'); + + //scrolling up? + }else { + scrolling('up'); + } + } + } + + return false; + } + + if(options.fitToSection){ + //stopping the auto scroll to adjust to a section + activeAnimation = false; + } + } + + /** + * Slides a slider to the given direction. + * Optional `section` param. + */ + function moveSlide(direction, section){ + var activeSection = section == null ? $(SECTION_ACTIVE_SEL)[0] : section; + var slides = $(SLIDES_WRAPPER_SEL, activeSection)[0]; + + // more than one slide needed and nothing should be sliding + if (slides == null || slideMoving || $(SLIDE_SEL, slides).length < 2) { + return; + } + + var currentSlide = $(SLIDE_ACTIVE_SEL, slides)[0]; + var destiny = null; + + if(direction === 'left'){ + destiny = prevUntil(currentSlide, SLIDE_SEL); + }else{ + destiny = nextUntil(currentSlide, SLIDE_SEL); + } + + //isn't there a next slide in the secuence? + if(destiny == null){ + //respect loopHorizontal settin + if (!options.loopHorizontal) return; + + var slideSiblings = siblings(currentSlide); + if(direction === 'left'){ + destiny = slideSiblings[slideSiblings.length - 1]; //last + }else{ + destiny = slideSiblings[0]; //first + } + } + + slideMoving = true && !FP.test.isTesting; + landscapeScroll(slides, destiny, direction); + } + + /** + * Maintains the active slides in the viewport + * (Because the `scroll` animation might get lost with some actions, such as when using continuousVertical) + */ + function keepSlidesPosition(){ + var activeSlides = $(SLIDE_ACTIVE_SEL); + for( var i =0; i previousDestTop; + var sectionBottom = position - windowsHeight + elementHeight; + var bigSectionsDestination = options.bigSectionsDestination; + + //is the destination element bigger than the viewport? + if(elementHeight > windowsHeight){ + //scrolling up? + if(!isScrollingDown && !bigSectionsDestination || bigSectionsDestination === 'bottom' ){ + position = sectionBottom; + } + } + + //sections equal or smaller than the viewport height && scrolling down? || is resizing and its in the last section + else if(isScrollingDown || (isResizing && next(element) == null) ){ + //The bottom of the destination will be at the bottom of the viewport + position = sectionBottom; + } + + /* + Keeping record of the last scrolled position to determine the scrolling direction. + No conventional methods can be used as the scroll bar might not be present + AND the section might not be active if it is auto-height and didnt reach the middle + of the viewport. + */ + previousDestTop = position; + return position; + } + + /** + * Scrolls the site to the given element and scrolls to the slide if a callback is given. + */ + function scrollPage(element, callback, isMovementUp){ + if(element == null){ return; } //there's no element to scroll, leaving the function + + var dtop = getDestinationPosition(element); + var slideAnchorLink; + var slideIndex; + + //local variables + var v = { + element: element, + callback: callback, + isMovementUp: isMovementUp, + dtop: dtop, + yMovement: getYmovement(element), + anchorLink: element.getAttribute('data-anchor'), + sectionIndex: index(element, SECTION_SEL), + activeSlide: $(SLIDE_ACTIVE_SEL, element)[0], + activeSection: $(SECTION_ACTIVE_SEL)[0], + leavingSection: index($(SECTION_ACTIVE_SEL), SECTION_SEL) + 1, + + //caching the value of isResizing at the momment the function is called + //because it will be checked later inside a setTimeout and the value might change + localIsResizing: isResizing + }; + + //quiting when destination scroll is the same as the current one + if((v.activeSection == element && !isResizing) || (options.scrollBar && getScrollTop() === v.dtop && !hasClass(element, AUTO_HEIGHT) )){ return; } + + if(v.activeSlide != null){ + slideAnchorLink = v.activeSlide.getAttribute('data-anchor'); + slideIndex = index(v.activeSlide); + } + + //callback (onLeave) if the site is not just resizing and readjusting the slides + if(isFunction(options.onLeave) && !v.localIsResizing){ + var direction = v.yMovement; + + //required for continousVertical + if(typeof isMovementUp !== 'undefined'){ + direction = isMovementUp ? 'up' : 'down'; + } + + //for the callback + v.direction = direction; + + if(fireCallback('onLeave', v) === false){ + return; + } + } + + // If continuousVertical && we need to wrap around + if (options.autoScrolling && options.continuousVertical && typeof (v.isMovementUp) !== "undefined" && + ((!v.isMovementUp && v.yMovement == 'up') || // Intending to scroll down but about to go up or + (v.isMovementUp && v.yMovement == 'down'))) { // intending to scroll up but about to go down + + v = createInfiniteSections(v); + } + + //pausing media of the leaving section (if we are not just resizing, as destinatino will be the same one) + if(!v.localIsResizing){ + stopMedia(v.activeSection); + } + + if(options.scrollOverflow){ + options.scrollOverflowHandler.beforeLeave(); + } + + addClass(element, ACTIVE); + removeClass(siblings(element), ACTIVE); + lazyLoad(element); + + if(options.scrollOverflow){ + options.scrollOverflowHandler.onLeave(); + } + + //preventing from activating the MouseWheelHandler event + //more than once if the page is scrolling + canScroll = false || FP.test.isTesting; + + setState(slideIndex, slideAnchorLink, v.anchorLink, v.sectionIndex); + + performMovement(v); + + //flag to avoid callingn `scrollPage()` twice in case of using anchor links + lastScrolledDestiny = v.anchorLink; + + //avoid firing it twice (as it does also on scroll) + activateMenuAndNav(v.anchorLink, v.sectionIndex); + } + + /** + * Dispatch events & callbacks making sure it does it on the right format, depending on + * whether v2compatible is being used or not. + */ + function fireCallback(eventName, v){ + var eventData = getEventData(eventName, v); + + if(!options.v2compatible){ + trigger(container, eventName, eventData); + + if(options[eventName].apply(eventData[Object.keys(eventData)[0]], toArray(eventData)) === false){ + return false; + } + } + else{ + if(options[eventName].apply(eventData[0], eventData.slice(1)) === false){ + return false; + } + } + + return true; + } + + /** + * Makes sure to only create a Panel object if the element exist + */ + function nullOrSection(el){ + return el ? new Section(el) : null; + } + + function nullOrSlide(el){ + return el ? new Slide(el) : null; + } + + /** + * Gets the event's data for the given event on the right format. Depending on whether + * v2compatible is being used or not. + */ + function getEventData(eventName, v){ + var paramsPerEvent; + + if(!options.v2compatible){ + + //using functions to run only the necessary bits within the object + paramsPerEvent = { + afterRender: function(){ + return { + section: nullOrSection($(SECTION_ACTIVE_SEL)[0]), + slide: nullOrSlide($(SLIDE_ACTIVE_SEL, $(SECTION_ACTIVE_SEL)[0])[0]) + }; + }, + onLeave: function(){ + return { + origin: nullOrSection(v.activeSection), + destination: nullOrSection(v.element), + direction: v.direction + }; + }, + + afterLoad: function(){ + return paramsPerEvent.onLeave(); + }, + + afterSlideLoad: function(){ + return { + section: nullOrSection(v.section), + origin: nullOrSlide(v.prevSlide), + destination: nullOrSlide(v.destiny), + direction: v.direction + }; + }, + + onSlideLeave: function(){ + return paramsPerEvent.afterSlideLoad(); + } + }; + } + else{ + paramsPerEvent = { + afterRender: function(){ return [container]; }, + onLeave: function(){ return [v.activeSection, v.leavingSection, (v.sectionIndex + 1), v.direction]; }, + afterLoad: function(){ return [v.element, v.anchorLink, (v.sectionIndex + 1)]; }, + afterSlideLoad: function(){ return [v.destiny, v.anchorLink, (v.sectionIndex + 1), v.slideAnchor, v.slideIndex]; }, + onSlideLeave: function(){ return [v.prevSlide, v.anchorLink, (v.sectionIndex + 1), v.prevSlideIndex, v.direction, v.slideIndex]; }, + }; + } + + return paramsPerEvent[eventName](); + } + + /** + * Performs the vertical movement (by CSS3 or by jQuery) + */ + function performMovement(v){ + // using CSS3 translate functionality + if (options.css3 && options.autoScrolling && !options.scrollBar) { + + // The first section can have a negative value in iOS 10. Not quite sure why: -0.0142822265625 + // that's why we round it to 0. + var translate3d = 'translate3d(0px, -' + Math.round(v.dtop) + 'px, 0px)'; + transformContainer(translate3d, true); + + //even when the scrollingSpeed is 0 there's a little delay, which might cause the + //scrollingSpeed to change in case of using silentMoveTo(); + if(options.scrollingSpeed){ + clearTimeout(afterSectionLoadsId); + afterSectionLoadsId = setTimeout(function () { + afterSectionLoads(v); + }, options.scrollingSpeed); + }else{ + afterSectionLoads(v); + } + } + + // using JS to animate + else{ + var scrollSettings = getScrollSettings(v.dtop); + FP.test.top = -v.dtop + 'px'; + + scrollTo(scrollSettings.element, scrollSettings.options, options.scrollingSpeed, function(){ + if(options.scrollBar){ + + /* Hack! + The timeout prevents setting the most dominant section in the viewport as "active" when the user + scrolled to a smaller section by using the mousewheel (auto scrolling) rather than draging the scroll bar. + + When using scrollBar:true It seems like the scroll events still getting propagated even after the scrolling animation has finished. + */ + setTimeout(function(){ + afterSectionLoads(v); + },30); + }else{ + afterSectionLoads(v); + } + }); + } + } + + /** + * Gets the scrolling settings depending on the plugin autoScrolling option + */ + function getScrollSettings(top){ + var scroll = {}; + + //top property animation + if(options.autoScrolling && !options.scrollBar){ + scroll.options = -top; + scroll.element = $(WRAPPER_SEL)[0]; + } + + //window real scrolling + else{ + scroll.options = top; + scroll.element = window; + } + + return scroll; + } + + /** + * Adds sections before or after the current one to create the infinite effect. + */ + function createInfiniteSections(v){ + // Scrolling down + if (!v.isMovementUp) { + // Move all previous sections to after the active section + after($(SECTION_ACTIVE_SEL)[0], prevAll(v.activeSection, SECTION_SEL).reverse()); + } + else { // Scrolling up + // Move all next sections to before the active section + before($(SECTION_ACTIVE_SEL)[0], nextAll(v.activeSection, SECTION_SEL)); + } + + // Maintain the displayed position (now that we changed the element order) + silentScroll($(SECTION_ACTIVE_SEL)[0].offsetTop); + + // Maintain the active slides visible in the viewport + keepSlidesPosition(); + + // save for later the elements that still need to be reordered + v.wrapAroundElements = v.activeSection; + + // Recalculate animation variables + v.dtop = v.element.offsetTop; + v.yMovement = getYmovement(v.element); + + //sections will temporally have another position in the DOM + //updating this values in case we need them + v.leavingSection = index(v.activeSection, SECTION_SEL) + 1; + v.sectionIndex = index(v.element, SECTION_SEL); + + return v; + } + + /** + * Fix section order after continuousVertical changes have been animated + */ + function continuousVerticalFixSectionOrder (v) { + // If continuousVertical is in effect (and autoScrolling would also be in effect then), + // finish moving the elements around so the direct navigation will function more simply + if (v.wrapAroundElements == null) { + return; + } + + if (v.isMovementUp) { + before($(SECTION_SEL)[0], v.wrapAroundElements); + } + else { + after($(SECTION_SEL)[$(SECTION_SEL).length-1], v.wrapAroundElements); + } + + silentScroll($(SECTION_ACTIVE_SEL)[0].offsetTop); + + // Maintain the active slides visible in the viewport + keepSlidesPosition(); + } + + + /** + * Actions to do once the section is loaded. + */ + function afterSectionLoads (v){ + continuousVerticalFixSectionOrder(v); + + //callback (afterLoad) if the site is not just resizing and readjusting the slides + if(isFunction(options.afterLoad) && !v.localIsResizing){ + fireCallback('afterLoad', v); + } + + if(options.scrollOverflow){ + options.scrollOverflowHandler.afterLoad(); + } + + if(!v.localIsResizing){ + playMedia(v.element); + } + + addClass(v.element, COMPLETELY); + removeClass(siblings(v.element), COMPLETELY); + + canScroll = true; + + if(isFunction(v.callback)){ + v.callback(); + } + } + + /** + * Sets the value for the given attribute from the `data-` attribute with the same suffix + * ie: data-srcset ==> srcset | data-src ==> src + */ + function setSrc(element, attribute){ + element.setAttribute(attribute, element.getAttribute('data-' + attribute)); + element.removeAttribute('data-' + attribute); + } + + /** + * Lazy loads image, video and audio elements. + */ + function lazyLoad(destiny){ + if (!options.lazyLoading){ + return; + } + + var panel = getSlideOrSection(destiny); + + $('img[data-src], img[data-srcset], source[data-src], source[data-srcset], video[data-src], audio[data-src], iframe[data-src]', panel).forEach(function(element){ + ['src', 'srcset'].forEach(function(type){ + var attribute = element.getAttribute('data-' + type); + if(attribute != null && attribute){ + setSrc(element, type); + } + }); + + if(matches(element, 'source')){ + var elementToPlay = closest(element, 'video, audio'); + if(elementToPlay){ + elementToPlay.load(); + } + } + }); + } + + /** + * Plays video and audio elements. + */ + function playMedia(destiny){ + var panel = getSlideOrSection(destiny); + + //playing HTML5 media elements + $('video, audio', panel).forEach(function(element){ + if( element.hasAttribute('data-autoplay') && typeof element.play === 'function' ) { + element.play(); + } + }); + + //youtube videos + $('iframe[src*="youtube.com/embed/"]', panel).forEach(function(element){ + if ( element.hasAttribute('data-autoplay') ){ + playYoutube(element); + } + + //in case the URL was not loaded yet. On page load we need time for the new URL (with the API string) to load. + element.onload = function() { + if ( element.hasAttribute('data-autoplay') ){ + playYoutube(element); + } + }; + }); + } + + /** + * Plays a youtube video + */ + function playYoutube(element){ + element.contentWindow.postMessage('{"event":"command","func":"playVideo","args":""}', '*'); + } + + /** + * Stops video and audio elements. + */ + function stopMedia(destiny){ + var panel = getSlideOrSection(destiny); + + //stopping HTML5 media elements + $('video, audio', panel).forEach(function(element){ + if( !element.hasAttribute('data-keepplaying') && typeof element.pause === 'function' ) { + element.pause(); + } + }); + + //youtube videos + $('iframe[src*="youtube.com/embed/"]', panel).forEach(function(element){ + if( /youtube\.com\/embed\//.test(element.getAttribute('src')) && !element.hasAttribute('data-keepplaying')){ + element.contentWindow.postMessage('{"event":"command","func":"pauseVideo","args":""}','*'); + } + }); + } + + /** + * Gets the active slide (or section) for the given section + */ + function getSlideOrSection(destiny){ + var slide = $(SLIDE_ACTIVE_SEL, destiny); + if( slide.length ) { + destiny = slide[0]; + } + + return destiny; + } + + /** + * Scrolls to the anchor in the URL when loading the site + */ + function scrollToAnchor(){ + var anchors = getAnchorsURL(); + var sectionAnchor = anchors.section; + var slideAnchor = anchors.slide; + + if(sectionAnchor){ //if theres any # + if(options.animateAnchor){ + scrollPageAndSlide(sectionAnchor, slideAnchor); + }else{ + silentMoveTo(sectionAnchor, slideAnchor); + } + } + } + + /** + * Detecting any change on the URL to scroll to the given anchor link + * (a way to detect back history button as we play with the hashes on the URL) + */ + function hashChangeHandler(){ + if(!isScrolling && !options.lockAnchors){ + var anchors = getAnchorsURL(); + var sectionAnchor = anchors.section; + var slideAnchor = anchors.slide; + + //when moving to a slide in the first section for the first time (first time to add an anchor to the URL) + var isFirstSlideMove = (typeof lastScrolledDestiny === 'undefined'); + var isFirstScrollMove = (typeof lastScrolledDestiny === 'undefined' && typeof slideAnchor === 'undefined' && !slideMoving); + + if(sectionAnchor && sectionAnchor.length){ + /*in order to call scrollpage() only once for each destination at a time + It is called twice for each scroll otherwise, as in case of using anchorlinks `hashChange` + event is fired on every scroll too.*/ + if ((sectionAnchor && sectionAnchor !== lastScrolledDestiny) && !isFirstSlideMove + || isFirstScrollMove + || (!slideMoving && lastScrolledSlide != slideAnchor )){ + + scrollPageAndSlide(sectionAnchor, slideAnchor); + } + } + } + } + + //gets the URL anchors (section and slide) + function getAnchorsURL(){ + var section; + var slide; + var hash = window.location.hash; + + if(hash.length){ + //getting the anchor link in the URL and deleting the `#` + var anchorsParts = hash.replace('#', '').split('/'); + + //using / for visual reasons and not as a section/slide separator #2803 + var isFunkyAnchor = hash.indexOf('#/') > -1; + + section = isFunkyAnchor ? '/' + anchorsParts[1] : decodeURIComponent(anchorsParts[0]); + + var slideAnchor = isFunkyAnchor ? anchorsParts[2] : anchorsParts[1]; + if(slideAnchor && slideAnchor.length){ + slide = decodeURIComponent(slideAnchor); + } + } + + return { + section: section, + slide: slide + }; + } + + //Sliding with arrow keys, both, vertical and horizontal + function keydownHandler(e) { + clearTimeout(keydownId); + + var activeElement = document.activeElement; + var keyCode = e.keyCode; + + //tab? + if(keyCode === 9){ + onTab(e); + } + + else if(!matches(activeElement, 'textarea') && !matches(activeElement, 'input') && !matches(activeElement, 'select') && + activeElement.getAttribute('contentEditable') !== "true" && activeElement.getAttribute('contentEditable') !== '' && + options.keyboardScrolling && options.autoScrolling){ + + //preventing the scroll with arrow keys & spacebar & Page Up & Down keys + var keyControls = [40, 38, 32, 33, 34]; + if(keyControls.indexOf(keyCode) > -1){ + preventDefault(e); + } + + controlPressed = e.ctrlKey; + + keydownId = setTimeout(function(){ + onkeydown(e); + },150); + } + } + + function tooltipTextHandler(){ + /*jshint validthis:true */ + trigger(prev(this), 'click'); + } + + //to prevent scrolling while zooming + function keyUpHandler(e){ + if(isWindowFocused){ //the keyup gets fired on new tab ctrl + t in Firefox + controlPressed = e.ctrlKey; + } + } + + //binding the mousemove when the mouse's middle button is released + function mouseDownHandler(e){ + //middle button + if (e.which == 2){ + oldPageY = e.pageY; + container.addEventListener('mousemove', mouseMoveHandler); + } + } + + //unbinding the mousemove when the mouse's middle button is released + function mouseUpHandler(e){ + //middle button + if (e.which == 2){ + container.removeEventListener('mousemove', mouseMoveHandler); + } + } + + /** + * Makes sure the tab key will only focus elements within the current section/slide + * preventing this way from breaking the page. + * Based on "Modals and keyboard traps" + * from https://developers.google.com/web/fundamentals/accessibility/focus/using-tabindex + */ + function onTab(e){ + var isShiftPressed = e.shiftKey; + var activeElement = document.activeElement; + var activeSection = $(SECTION_ACTIVE_SEL)[0]; + var activeSlide = $(SLIDE_ACTIVE_SEL, activeSection)[0]; + var focusableWrapper = activeSlide ? activeSlide : activeSection; + var focusableElements = $(focusableElementsString + ':not([tabindex="-1"])', focusableWrapper); + + function preventAndFocusFirst(e){ + preventDefault(e); + return focusableElements[0].focus(); + } + + //is there an element with focus? + if(activeElement){ + if(closest(activeElement, SECTION_ACTIVE_SEL + ',' + SLIDE_ACTIVE_SEL) == null){ + activeElement = preventAndFocusFirst(e); + } + } + + //no element if focused? Let's focus the first one of the section/slide + else{ + preventAndFocusFirst(e); + } + + //when reached the first or last focusable element of the section/slide + //we prevent the tab action to keep it in the last focusable element + if(!isShiftPressed && activeElement == focusableElements[focusableElements.length - 1] || + isShiftPressed && activeElement == focusableElements[0] + ){ + preventDefault(e); + } + } + + //Scrolling horizontally when clicking on the slider controls. + function slideArrowHandler(){ + /*jshint validthis:true */ + var section = closest(this, SECTION_SEL); + + /*jshint validthis:true */ + if (hasClass(this, SLIDES_PREV)) { + if(isScrollAllowed.m.left){ + moveSlideLeft(section); + } + } else { + if(isScrollAllowed.m.right){ + moveSlideRight(section); + } + } + } + + //when opening a new tab (ctrl + t), `control` won't be pressed when coming back. + function blurHandler(){ + isWindowFocused = false; + controlPressed = false; + } + + //Scrolls to the section when clicking the navigation bullet + function sectionBulletHandler(e){ + preventDefault(e); + + /*jshint validthis:true */ + var indexBullet = index(closest(this, SECTION_NAV_SEL + ' li')); + scrollPage($(SECTION_SEL)[indexBullet]); + } + + //Scrolls the slider to the given slide destination for the given section + function slideBulletHandler(e){ + preventDefault(e); + + /*jshint validthis:true */ + var slides = $(SLIDES_WRAPPER_SEL, closest(this, SECTION_SEL))[0]; + var destiny = $(SLIDE_SEL, slides)[index(closest(this, 'li'))]; + + landscapeScroll(slides, destiny); + } + + /** + * Keydown event + */ + function onkeydown(e){ + var shiftPressed = e.shiftKey; + + //do nothing if we can not scroll or we are not using horizotnal key arrows. + if(!canScroll && [37,39].indexOf(e.keyCode) < 0){ + return; + } + + switch (e.keyCode) { + //up + case 38: + case 33: + if(isScrollAllowed.k.up){ + moveSectionUp(); + } + break; + + //down + case 32: //spacebar + if(shiftPressed && isScrollAllowed.k.up){ + moveSectionUp(); + break; + } + /* falls through */ + case 40: + case 34: + if(isScrollAllowed.k.down){ + moveSectionDown(); + } + break; + + //Home + case 36: + if(isScrollAllowed.k.up){ + moveTo(1); + } + break; + + //End + case 35: + if(isScrollAllowed.k.down){ + moveTo( $(SECTION_SEL).length ); + } + break; + + //left + case 37: + if(isScrollAllowed.k.left){ + moveSlideLeft(); + } + break; + + //right + case 39: + if(isScrollAllowed.k.right){ + moveSlideRight(); + } + break; + + default: + return; // exit this handler for other keys + } + } + + /** + * Detecting the direction of the mouse movement. + * Used only for the middle button of the mouse. + */ + var oldPageY = 0; + function mouseMoveHandler(e){ + if(canScroll){ + // moving up + if (e.pageY < oldPageY && isScrollAllowed.m.up){ + moveSectionUp(); + } + + // moving down + else if(e.pageY > oldPageY && isScrollAllowed.m.down){ + moveSectionDown(); + } + } + oldPageY = e.pageY; + } + + /** + * Scrolls horizontal sliders. + */ + function landscapeScroll(slides, destiny, direction){ + var section = closest(slides, SECTION_SEL); + var v = { + slides: slides, + destiny: destiny, + direction: direction, + destinyPos: {left: destiny.offsetLeft}, + slideIndex: index(destiny), + section: section, + sectionIndex: index(section, SECTION_SEL), + anchorLink: section.getAttribute('data-anchor'), + slidesNav: $(SLIDES_NAV_SEL, section)[0], + slideAnchor: getAnchor(destiny), + prevSlide: $(SLIDE_ACTIVE_SEL, section)[0], + prevSlideIndex: index($(SLIDE_ACTIVE_SEL, section)[0]), + + //caching the value of isResizing at the momment the function is called + //because it will be checked later inside a setTimeout and the value might change + localIsResizing: isResizing + }; + v.xMovement = getXmovement(v.prevSlideIndex, v.slideIndex); + + //important!! Only do it when not resizing + if(!v.localIsResizing){ + //preventing from scrolling to the next/prev section when using scrollHorizontally + canScroll = false; + } + + if(options.onSlideLeave){ + + //if the site is not just resizing and readjusting the slides + if(!v.localIsResizing && v.xMovement!=='none'){ + if(isFunction( options.onSlideLeave )){ + if( fireCallback('onSlideLeave', v) === false){ + slideMoving = false; + return; + } + } + } + } + + addClass(destiny, ACTIVE); + removeClass(siblings(destiny), ACTIVE); + + if(!v.localIsResizing){ + stopMedia(v.prevSlide); + lazyLoad(destiny); + } + + if(!options.loopHorizontal && options.controlArrows){ + //hidding it for the fist slide, showing for the rest + toggle($(SLIDES_ARROW_PREV_SEL, section), v.slideIndex!==0); + + //hidding it for the last slide, showing for the rest + toggle($(SLIDES_ARROW_NEXT_SEL, section), next(destiny) != null); + } + + //only changing the URL if the slides are in the current section (not for resize re-adjusting) + if(hasClass(section, ACTIVE) && !v.localIsResizing){ + setState(v.slideIndex, v.slideAnchor, v.anchorLink, v.sectionIndex); + } + + performHorizontalMove(slides, v, true); + } + + + function afterSlideLoads(v){ + activeSlidesNavigation(v.slidesNav, v.slideIndex); + + //if the site is not just resizing and readjusting the slides + if(!v.localIsResizing){ + if(isFunction( options.afterSlideLoad )){ + fireCallback('afterSlideLoad', v); + } + + //needs to be inside the condition to prevent problems with continuousVertical and scrollHorizontally + //and to prevent double scroll right after a windows resize + canScroll = true; + + playMedia(v.destiny); + } + + //letting them slide again + slideMoving = false; + } + + /** + * Performs the horizontal movement. (CSS3 or jQuery) + * + * @param fireCallback {Bool} - determines whether or not to fire the callback + */ + function performHorizontalMove(slides, v, fireCallback){ + var destinyPos = v.destinyPos; + + if(options.css3){ + var translate3d = 'translate3d(-' + Math.round(destinyPos.left) + 'px, 0px, 0px)'; + + FP.test.translate3dH[v.sectionIndex] = translate3d; + css(addAnimation($(SLIDES_CONTAINER_SEL, slides)), getTransforms(translate3d)); + + afterSlideLoadsId = setTimeout(function(){ + if(fireCallback){ + afterSlideLoads(v); + } + }, options.scrollingSpeed); + }else{ + FP.test.left[v.sectionIndex] = Math.round(destinyPos.left); + + scrollTo(slides, Math.round(destinyPos.left), options.scrollingSpeed, function(){ + if(fireCallback){ + afterSlideLoads(v); + } + }); + } + } + + /** + * Sets the state for the horizontal bullet navigations. + */ + function activeSlidesNavigation(slidesNav, slideIndex){ + if(options.slidesNavigation && slidesNav != null){ + removeClass($(ACTIVE_SEL, slidesNav), ACTIVE); + addClass( $('a', $('li', slidesNav)[slideIndex] ), ACTIVE); + } + } + + var previousHeight = windowsHeight; + + //when resizing the site, we adjust the heights of the sections, slimScroll... + function resizeHandler(){ + //checking if it needs to get responsive + responsive(); + + // rebuild immediately on touch devices + if (isTouchDevice) { + var activeElement = document.activeElement; + + //if the keyboard is NOT visible + if (!matches(activeElement, 'textarea') && !matches(activeElement, 'input') && !matches(activeElement, 'select')) { + var currentHeight = getWindowHeight(); + + //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) + if( Math.abs(currentHeight - previousHeight) > (20 * Math.max(previousHeight, currentHeight) / 100) ){ + reBuild(true); + previousHeight = currentHeight; + } + } + }else{ + //in order to call the functions only when the resize is finished + //http://stackoverflow.com/questions/4298612/jquery-how-to-call-resize-event-only-once-its-finished-resizing + clearTimeout(resizeId); + + resizeId = setTimeout(function(){ + reBuild(true); + }, 350); + } + } + + /** + * Checks if the site needs to get responsive and disables autoScrolling if so. + * A class `fp-responsive` is added to the plugin's container in case the user wants to use it for his own responsive CSS. + */ + function responsive(){ + var widthLimit = options.responsive || options.responsiveWidth; //backwards compatiblity + var heightLimit = options.responsiveHeight; + + //only calculating what we need. Remember its called on the resize event. + var isBreakingPointWidth = widthLimit && window.innerWidth < widthLimit; + var isBreakingPointHeight = heightLimit && window.innerHeight < heightLimit; + + if(widthLimit && heightLimit){ + setResponsive(isBreakingPointWidth || isBreakingPointHeight); + } + else if(widthLimit){ + setResponsive(isBreakingPointWidth); + } + else if(heightLimit){ + setResponsive(isBreakingPointHeight); + } + } + + /** + * Adds transition animations for the given element + */ + function addAnimation(element){ + var transition = 'all ' + options.scrollingSpeed + 'ms ' + options.easingcss3; + + removeClass(element, NO_TRANSITION); + return css(element, { + '-webkit-transition': transition, + 'transition': transition + }); + } + + /** + * Remove transition animations for the given element + */ + function removeAnimation(element){ + return addClass(element, NO_TRANSITION); + } + + /** + * Activating the vertical navigation bullets according to the given slide name. + */ + function activateNavDots(name, sectionIndex){ + if(options.navigation && $(SECTION_NAV_SEL)[0] != null){ + removeClass($(ACTIVE_SEL, $(SECTION_NAV_SEL)[0]), ACTIVE); + if(name){ + addClass( $('a[href="#' + name + '"]', $(SECTION_NAV_SEL)[0]), ACTIVE); + }else{ + addClass($('a', $('li', $(SECTION_NAV_SEL)[0])[sectionIndex]), ACTIVE); + } + } + } + + /** + * Activating the website main menu elements according to the given slide name. + */ + function activateMenuElement(name){ + var menu = $(options.menu)[0]; + if(options.menu && menu != null){ + removeClass($(ACTIVE_SEL, menu), ACTIVE); + addClass($('[data-menuanchor="'+name+'"]', menu), ACTIVE); + } + } + + /** + * Sets to active the current menu and vertical nav items. + */ + function activateMenuAndNav(anchor, index){ + activateMenuElement(anchor); + activateNavDots(anchor, index); + } + + /** + * Retuns `up` or `down` depending on the scrolling movement to reach its destination + * from the current section. + */ + function getYmovement(destiny){ + var fromIndex = index($(SECTION_ACTIVE_SEL)[0], SECTION_SEL); + var toIndex = index(destiny, SECTION_SEL); + if( fromIndex == toIndex){ + return 'none'; + } + if(fromIndex > toIndex){ + return 'up'; + } + return 'down'; + } + + /** + * Retuns `right` or `left` depending on the scrolling movement to reach its destination + * from the current slide. + */ + function getXmovement(fromIndex, toIndex){ + if( fromIndex == toIndex){ + return 'none'; + } + if(fromIndex > toIndex){ + return 'left'; + } + return 'right'; + } + + function addTableClass(element){ + //In case we are styling for the 2nd time as in with reponsiveSlides + if(!hasClass(element, TABLE)){ + var wrapper = document.createElement('div'); + wrapper.className = TABLE_CELL; + wrapper.style.height = getTableHeight(element) + 'px'; + + addClass(element, TABLE); + wrapInner(element, wrapper); + } + } + + function getTableHeight(element){ + var sectionHeight = windowsHeight; + + if(options.paddingTop || options.paddingBottom){ + var section = element; + if(!hasClass(section, SECTION)){ + section = closest(element, SECTION_SEL); + } + + var paddings = parseInt(getComputedStyle(section)['padding-top']) + parseInt(getComputedStyle(section)['padding-bottom']); + sectionHeight = (windowsHeight - paddings); + } + + return sectionHeight; + } + + /** + * Adds a css3 transform property to the container class with or without animation depending on the animated param. + */ + function transformContainer(translate3d, animated){ + if(animated){ + addAnimation(container); + }else{ + removeAnimation(container); + } + + css(container, getTransforms(translate3d)); + FP.test.translate3d = translate3d; + + //syncronously removing the class after the animation has been applied. + setTimeout(function(){ + removeClass(container, NO_TRANSITION); + },10); + } + + /** + * Gets a section by its anchor / index + */ + function getSectionByAnchor(sectionAnchor){ + var section = $(SECTION_SEL + '[data-anchor="'+sectionAnchor+'"]', container)[0]; + if(!section){ + var sectionIndex = typeof sectionAnchor !== 'undefined' ? sectionAnchor -1 : 0; + section = $(SECTION_SEL)[sectionIndex]; + } + + return section; + } + + /** + * Gets a slide inside a given section by its anchor / index + */ + function getSlideByAnchor(slideAnchor, section){ + var slide = $(SLIDE_SEL + '[data-anchor="'+slideAnchor+'"]', section)[0]; + if(slide == null){ + slideAnchor = typeof slideAnchor !== 'undefined' ? slideAnchor : 0; + slide = $(SLIDE_SEL, section)[slideAnchor]; + } + + return slide; + } + + /** + * Scrolls to the given section and slide anchors + */ + function scrollPageAndSlide(sectionAnchor, slideAnchor){ + var section = getSectionByAnchor(sectionAnchor); + + //do nothing if there's no section with the given anchor name + if(section == null) return; + + var slide = getSlideByAnchor(slideAnchor, section); + + //we need to scroll to the section and then to the slide + if (sectionAnchor !== lastScrolledDestiny && !hasClass(section, ACTIVE)){ + scrollPage(section, function(){ + scrollSlider(slide); + }); + } + //if we were already in the section + else{ + scrollSlider(slide); + } + } + + /** + * Scrolls the slider to the given slide destination for the given section + */ + function scrollSlider(slide){ + if(slide != null){ + landscapeScroll(closest(slide, SLIDES_WRAPPER_SEL), slide); + } + } + + /** + * Creates a landscape navigation bar with dots for horizontal sliders. + */ + function addSlidesNavigation(section, numSlides){ + appendTo(createElementFromHTML('
      '), section); + var nav = $(SLIDES_NAV_SEL, section)[0]; + + //top or bottom + addClass(nav, 'fp-' + options.slidesNavPosition); + + for(var i=0; i< numSlides; i++){ + appendTo(createElementFromHTML('
    • '), $('ul', nav)[0] ); + } + + //centering it + css(nav, {'margin-left': '-' + (nav.innerWidth/2) + 'px'}); + + addClass($('a', $('li', nav)[0] ), ACTIVE); + } + + + /** + * Sets the state of the website depending on the active section/slide. + * It changes the URL hash when needed and updates the body class. + */ + function setState(slideIndex, slideAnchor, anchorLink, sectionIndex){ + var sectionHash = ''; + + if(options.anchors.length && !options.lockAnchors){ + + //isn't it the first slide? + if(slideIndex){ + if(anchorLink != null){ + sectionHash = anchorLink; + } + + //slide without anchor link? We take the index instead. + if(slideAnchor == null){ + slideAnchor = slideIndex; + } + + lastScrolledSlide = slideAnchor; + setUrlHash(sectionHash + '/' + slideAnchor); + + //first slide won't have slide anchor, just the section one + }else if(slideIndex != null){ + lastScrolledSlide = slideAnchor; + setUrlHash(anchorLink); + } + + //section without slides + else{ + setUrlHash(anchorLink); + } + } + + setBodyClass(); + } + + /** + * Sets the URL hash. + */ + function setUrlHash(url){ + if(options.recordHistory){ + location.hash = url; + }else{ + //Mobile Chrome doesn't work the normal way, so... lets use HTML5 for phones :) + if(isTouchDevice || isTouch){ + window.history.replaceState(undefined, undefined, '#' + url); + }else{ + var baseUrl = window.location.href.split('#')[0]; + window.location.replace( baseUrl + '#' + url ); + } + } + } + + /** + * Gets the anchor for the given slide / section. Its index will be used if there's none. + */ + function getAnchor(element){ + if(!element){ + return null; + } + var anchor = element.getAttribute('data-anchor'); + var elementIndex = index(element); + + //Slide without anchor link? We take the index instead. + if(anchor == null){ + anchor = elementIndex; + } + + return anchor; + } + + /** + * Sets a class for the body of the page depending on the active section / slide + */ + function setBodyClass(){ + var section = $(SECTION_ACTIVE_SEL)[0]; + var slide = $(SLIDE_ACTIVE_SEL, section)[0]; + + var sectionAnchor = getAnchor(section); + var slideAnchor = getAnchor(slide); + + var text = String(sectionAnchor); + + if(slide){ + text = text + '-' + slideAnchor; + } + + //changing slash for dash to make it a valid CSS style + text = text.replace('/', '-').replace('#',''); + + //removing previous anchor classes + var classRe = new RegExp('\\b\\s?' + VIEWING_PREFIX + '-[^\\s]+\\b', "g"); + $body.className = $body.className.replace(classRe, ''); + + //adding the current anchor + addClass($body, VIEWING_PREFIX + '-' + text); + } + + /** + * Checks for translate3d support + * @return boolean + * http://stackoverflow.com/questions/5661671/detecting-transform-translate3d-support + */ + function support3d() { + var el = document.createElement('p'), + has3d, + transforms = { + 'webkitTransform':'-webkit-transform', + 'OTransform':'-o-transform', + 'msTransform':'-ms-transform', + 'MozTransform':'-moz-transform', + 'transform':'transform' + }; + + //preventing the style p:empty{display: none;} from returning the wrong result + el.style.display = 'block' + + // Add it to the body to get the computed style. + document.body.insertBefore(el, null); + + for (var t in transforms) { + if (el.style[t] !== undefined) { + el.style[t] = 'translate3d(1px,1px,1px)'; + has3d = window.getComputedStyle(el).getPropertyValue(transforms[t]); + } + } + + document.body.removeChild(el); + + return (has3d !== undefined && has3d.length > 0 && has3d !== 'none'); + } + + /** + * Removes the auto scrolling action fired by the mouse wheel and trackpad. + * After this function is called, the mousewheel and trackpad movements won't scroll through sections. + */ + function removeMouseWheelHandler(){ + if (document.addEventListener) { + document.removeEventListener('mousewheel', MouseWheelHandler, false); //IE9, Chrome, Safari, Oper + document.removeEventListener('wheel', MouseWheelHandler, false); //Firefox + document.removeEventListener('MozMousePixelScroll', MouseWheelHandler, false); //old Firefox + } else { + document.detachEvent('onmousewheel', MouseWheelHandler); //IE 6/7/8 + } + } + + /** + * Adds the auto scrolling action for the mouse wheel and trackpad. + * After this function is called, the mousewheel and trackpad movements will scroll through sections + * https://developer.mozilla.org/en-US/docs/Web/Events/wheel + */ + function addMouseWheelHandler(){ + var prefix = ''; + var _addEventListener; + + if (window.addEventListener){ + _addEventListener = "addEventListener"; + }else{ + _addEventListener = "attachEvent"; + prefix = 'on'; + } + + // detect available wheel event + var support = 'onwheel' in document.createElement('div') ? 'wheel' : // Modern browsers support "wheel" + document.onmousewheel !== undefined ? 'mousewheel' : // Webkit and IE support at least "mousewheel" + 'DOMMouseScroll'; // let's assume that remaining browsers are older Firefox + + + if(support == 'DOMMouseScroll'){ + document[ _addEventListener ](prefix + 'MozMousePixelScroll', MouseWheelHandler, false); + } + + //handle MozMousePixelScroll in older Firefox + else{ + document[ _addEventListener ](prefix + support, MouseWheelHandler, false); + } + } + + /** + * Binding the mousemove when the mouse's middle button is pressed + */ + function addMiddleWheelHandler(){ + container.addEventListener('mousedown', mouseDownHandler); + container.addEventListener('mouseup', mouseUpHandler); + } + + /** + * Unbinding the mousemove when the mouse's middle button is released + */ + function removeMiddleWheelHandler(){ + container.removeEventListener('mousedown', mouseDownHandler); + container.removeEventListener('mouseup', mouseUpHandler); + } + + /** + * Adds the possibility to auto scroll through sections on touch devices. + */ + function addTouchHandler(){ + if(isTouchDevice || isTouch){ + if(options.autoScrolling){ + $body.removeEventListener(events.touchmove, preventBouncing, {passive: false}); + $body.addEventListener(events.touchmove, preventBouncing, {passive: false}); + } + + $(WRAPPER_SEL)[0].removeEventListener(events.touchstart, touchStartHandler); + $(WRAPPER_SEL)[0].removeEventListener(events.touchmove, touchMoveHandler, {passive: false}); + + $(WRAPPER_SEL)[0].addEventListener(events.touchstart, touchStartHandler); + $(WRAPPER_SEL)[0].addEventListener(events.touchmove, touchMoveHandler, {passive: false}); + } + } + + /** + * Removes the auto scrolling for touch devices. + */ + function removeTouchHandler(){ + if(isTouchDevice || isTouch){ + // normalScrollElements requires it off #2691 + if(options.autoScrolling){ + $body.removeEventListener(events.touchmove, touchMoveHandler, {passive: false}); + $body.removeEventListener(events.touchmove, preventBouncing, {passive: false}); + } + + $(WRAPPER_SEL)[0].removeEventListener(events.touchstart, touchStartHandler); + $(WRAPPER_SEL)[0].removeEventListener(events.touchmove, touchMoveHandler, {passive: false}); + } + } + + /* + * Returns and object with Microsoft pointers (for IE<11 and for IE >= 11) + * http://msdn.microsoft.com/en-us/library/ie/dn304886(v=vs.85).aspx + */ + function getMSPointer(){ + var pointer; + + //IE >= 11 & rest of browsers + if(window.PointerEvent){ + pointer = { down: 'pointerdown', move: 'pointermove'}; + } + + //IE < 11 + else{ + pointer = { down: 'MSPointerDown', move: 'MSPointerMove'}; + } + + return pointer; + } + + /** + * Gets the pageX and pageY properties depending on the browser. + * https://github.com/alvarotrigo/fullPage.js/issues/194#issuecomment-34069854 + */ + function getEventsPage(e){ + var events = []; + + events.y = (typeof e.pageY !== 'undefined' && (e.pageY || e.pageX) ? e.pageY : e.touches[0].pageY); + events.x = (typeof e.pageX !== 'undefined' && (e.pageY || e.pageX) ? e.pageX : e.touches[0].pageX); + + //in touch devices with scrollBar:true, e.pageY is detected, but we have to deal with touch events. #1008 + if(isTouch && isReallyTouch(e) && options.scrollBar && typeof e.touches !== 'undefined'){ + events.y = e.touches[0].pageY; + events.x = e.touches[0].pageX; + } + + return events; + } + + /** + * Slides silently (with no animation) the active slider to the given slide. + * @param noCallback {bool} true or defined -> no callbacks + */ + function silentLandscapeScroll(activeSlide, noCallbacks){ + setScrollingSpeed(0, 'internal'); + + if(typeof noCallbacks !== 'undefined'){ + //preventing firing callbacks afterSlideLoad etc. + isResizing = true; + } + + landscapeScroll(closest(activeSlide, SLIDES_WRAPPER_SEL), activeSlide); + + if(typeof noCallbacks !== 'undefined'){ + isResizing = false; + } + + setScrollingSpeed(originals.scrollingSpeed, 'internal'); + } + + /** + * Scrolls silently (with no animation) the page to the given Y position. + */ + function silentScroll(top){ + // The first section can have a negative value in iOS 10. Not quite sure why: -0.0142822265625 + // that's why we round it to 0. + var roundedTop = Math.round(top); + + if (options.css3 && options.autoScrolling && !options.scrollBar){ + var translate3d = 'translate3d(0px, -' + roundedTop + 'px, 0px)'; + transformContainer(translate3d, false); + } + else if(options.autoScrolling && !options.scrollBar){ + css(container, {'top': -roundedTop + 'px'}); + FP.test.top = -roundedTop + 'px'; + } + else{ + var scrollSettings = getScrollSettings(roundedTop); + setScrolling(scrollSettings.element, scrollSettings.options); + } + } + + /** + * Returns the cross-browser transform string. + */ + function getTransforms(translate3d){ + return { + '-webkit-transform': translate3d, + '-moz-transform': translate3d, + '-ms-transform':translate3d, + 'transform': translate3d + }; + } + + /** + * Allowing or disallowing the mouse/swipe scroll in a given direction. (not for keyboard) + * @type m (mouse) or k (keyboard) + */ + function setIsScrollAllowed(value, direction, type){ + //up, down, left, right + if(direction !== 'all'){ + isScrollAllowed[type][direction] = value; + } + + //all directions? + else{ + Object.keys(isScrollAllowed[type]).forEach(function(key){ + isScrollAllowed[type][key] = value; + }); + } + } + + /* + * Destroys fullpage.js plugin events and optinally its html markup and styles + */ + function destroy(all){ + setAutoScrolling(false, 'internal'); + setAllowScrolling(false); + setKeyboardScrolling(false); + addClass(container, DESTROYED); + + clearTimeout(afterSlideLoadsId); + clearTimeout(afterSectionLoadsId); + clearTimeout(resizeId); + clearTimeout(scrollId); + clearTimeout(scrollId2); + + + window.removeEventListener('scroll', scrollHandler); + window.removeEventListener('hashchange', hashChangeHandler); + window.removeEventListener('resize', resizeHandler); + + document.removeEventListener('keydown', keydownHandler); + document.removeEventListener('keyup', keyUpHandler); + + var clickTouchEvents = [sectionBulletHandler, tooltipTextHandler, slideArrowHandler, slideBulletHandler]; + ['click', 'touchstart'].forEach(function(eventName){ + clickTouchEvents.forEach(function(foo){ + document.removeEventListener(eventName, foo); + }); + }); + + ['mouseenter', 'touchstart', 'mouseleave', 'touchend'].forEach(function(eventName){ + document.removeEventListener(eventName, onMouseEnterOrLeave, true); //true is required! + }); + + clearTimeout(afterSlideLoadsId); + clearTimeout(afterSectionLoadsId); + + //lets make a mess! + if(all){ + destroyStructure(); + } + } + + /* + * Removes inline styles added by fullpage.js + */ + function destroyStructure(){ + //reseting the `top` or `translate` properties to 0 + silentScroll(0); + + //loading all the lazy load content + $('img[data-src], source[data-src], audio[data-src], iframe[data-src]', container).forEach(function(item){ + setSrc(item, 'src'); + }); + + $('img[data-srcset]').forEach(function(item){ + setSrc(item, 'srcset'); + }); + + remove($(SECTION_NAV_SEL + ', ' + SLIDES_NAV_SEL + ', ' + SLIDES_ARROW_SEL)); + + //removing inline styles + css($(SECTION_SEL), { + 'height': '', + 'background-color' : '', + 'padding': '' + }); + + css($(SLIDE_SEL), { + 'width': '' + }); + + css(container, { + 'height': '', + 'position': '', + '-ms-touch-action': '', + 'touch-action': '' + }); + + css($htmlBody, { + 'overflow': '', + 'height': '' + }); + + // remove .fp-enabled class + removeClass($('html'), ENABLED); + + // remove .fp-responsive class + removeClass($body, RESPONSIVE); + + // remove all of the .fp-viewing- classes + $body.className.split(/\s+/).forEach(function (className) { + if (className.indexOf(VIEWING_PREFIX) === 0) { + removeClass($body, className); + } + }); + + //removing added classes + $(SECTION_SEL + ', ' + SLIDE_SEL).forEach(function(item){ + if(options.scrollOverflowHandler){ + options.scrollOverflowHandler.remove(item); + } + removeClass(item, TABLE + ' ' + ACTIVE + ' ' + COMPLETELY); + var previousStyles = item.getAttribute('data-fp-styles'); + if(previousStyles){ + item.setAttribute('style', item.getAttribute('data-fp-styles')); + } + }); + + //removing the applied transition from the fullpage wrapper + removeAnimation(container); + + //Unwrapping content + [TABLE_CELL_SEL, SLIDES_CONTAINER_SEL,SLIDES_WRAPPER_SEL].forEach(function(selector){ + $(selector, container).forEach(function(item){ + //unwrap not being use in case there's no child element inside and its just text + item.outerHTML = item.innerHTML; + }); + }); + + //removing the applied transition from the fullpage wrapper + css(container, { + '-webkit-transition': 'none', + 'transition': 'none' + }); + + //scrolling the page to the top with no animation + $('html')[0].scrollTo(0, 0); + $('body')[0].scrollTo(0, 0); + + //removing selectors + var usedSelectors = [SECTION, SLIDE, SLIDES_CONTAINER]; + usedSelectors.forEach(function(item){ + removeClass($('.' + item), item); + }); + } + + /* + * Sets the state for a variable with multiple states (original, and temporal) + * Some variables such as `autoScrolling` or `recordHistory` might change automatically its state when using `responsive` or `autoScrolling:false`. + * This function is used to keep track of both states, the original and the temporal one. + * If type is not 'internal', then we assume the user is globally changing the variable. + */ + function setVariableState(variable, value, type){ + options[variable] = value; + if(type !== 'internal'){ + originals[variable] = value; + } + } + + /** + * Displays warnings + */ + function displayWarnings(){ + if(!isLicenseValid){ + showError('error', 'Fullpage.js version 3 has changed its license to GPLv3 and it requires a `licenseKey` option. Read about it here:'); + showError('error', 'https://github.com/alvarotrigo/fullPage.js#options.'); + } + + var extensions = ['fadingEffect', 'continuousHorizontal', 'scrollHorizontally', 'interlockedSlides', 'resetSliders', 'responsiveSlides', 'offsetSections', 'dragAndMove', 'scrollOverflowReset', 'parallax']; + if(hasClass($('html'), ENABLED)){ + showError('error', 'Fullpage.js can only be initialized once and you are doing it multiple times!'); + return; + } + + // Disable mutually exclusive settings + if (options.continuousVertical && + (options.loopTop || options.loopBottom)) { + options.continuousVertical = false; + showError('warn', 'Option `loopTop/loopBottom` is mutually exclusive with `continuousVertical`; `continuousVertical` disabled'); + } + + if(options.scrollBar && options.scrollOverflow){ + showError('warn', 'Option `scrollBar` is mutually exclusive with `scrollOverflow`. Sections with scrollOverflow might not work well in Firefox'); + } + + if(options.continuousVertical && (options.scrollBar || !options.autoScrolling)){ + options.continuousVertical = false; + showError('warn', 'Scroll bars (`scrollBar:true` or `autoScrolling:false`) are mutually exclusive with `continuousVertical`; `continuousVertical` disabled'); + } + + if(options.scrollOverflow && options.scrollOverflowHandler == null){ + options.scrollOverflow = false; + showError('error', 'The option `scrollOverflow:true` requires the file `scrolloverflow.min.js`. Please include it before fullPage.js.'); + } + + //using extensions? Wrong file! + extensions.forEach(function(extension){ + //is the option set to true? + if(options[extension]){ + showError('warn', 'fullpage.js extensions require fullpage.extensions.min.js file instead of the usual fullpage.js. Requested: '+ extension); + } + }); + + //anchors can not have the same value as any element ID or NAME + options.anchors.forEach(function(name){ + + //case insensitive selectors (http://stackoverflow.com/a/19465187/1081396) + var nameAttr = [].slice.call($('[name]')).filter(function(item) { + return item.getAttribute('name') && item.getAttribute('name').toLowerCase() == name.toLowerCase(); + }); + + var idAttr = [].slice.call($('[id]')).filter(function(item) { + return item.getAttribute('id') && item.getAttribute('id').toLowerCase() == name.toLowerCase(); + }); + + if(idAttr.length || nameAttr.length ){ + showError('error', 'data-anchor tags can not have the same value as any `id` element on the site (or `name` element for IE).'); + if(idAttr.length){ + showError('error', '"' + name + '" is is being used by another element `id` property'); + } + if(nameAttr.length){ + showError('error', '"' + name + '" is is being used by another element `name` property'); + } + } + }); + } + + /** + * Getting the position of the element to scroll when using jQuery animations + */ + function getScrolledPosition(element){ + var position; + + //is not the window element and is a slide? + if(element.self != window && hasClass(element, SLIDES_WRAPPER)){ + position = element.scrollLeft; + } + else if(!options.autoScrolling || options.scrollBar){ + position = getScrollTop(); + } + else{ + position = element.offsetTop; + } + + //gets the top property of the wrapper + return position; + } + + /** + * Simulates the animated scrollTop of jQuery. Used when css3:false or scrollBar:true or autoScrolling:false + * http://stackoverflow.com/a/16136789/1081396 + */ + function scrollTo(element, to, duration, callback) { + var start = getScrolledPosition(element); + var change = to - start; + var currentTime = 0; + var increment = 20; + activeAnimation = true; + + var animateScroll = function(){ + if(activeAnimation){ //in order to stope it from other function whenever we want + var val = to; + + currentTime += increment; + + if(duration){ + val = window.fp_easings[options.easing](currentTime, start, change, duration); + } + + setScrolling(element, val); + + if(currentTime < duration) { + setTimeout(animateScroll, increment); + }else if(typeof callback !== 'undefined'){ + callback(); + } + }else if (currentTime < duration){ + callback(); + } + }; + + animateScroll(); + } + + /** + * Scrolls the page / slider the given number of pixels. + * It will do it one or another way dependiong on the library's config. + */ + function setScrolling(element, val){ + if(!options.autoScrolling || options.scrollBar || (element.self != window && hasClass(element, SLIDES_WRAPPER))){ + + //scrolling horizontally through the slides? + if(element.self != window && hasClass(element, SLIDES_WRAPPER)){ + element.scrollLeft = val; + } + //vertical scroll + else{ + element.scrollTo(0, val); + } + }else{ + element.style.top = val + 'px'; + } + } + + /** + * Gets the active slide. + */ + function getActiveSlide(){ + var activeSlide = $(SLIDE_ACTIVE_SEL, $(SECTION_ACTIVE_SEL)[0])[0]; + return nullOrSlide(activeSlide); + } + + /** + * Gets the active section. + */ + function getActiveSection(){ + return new Section($(SECTION_ACTIVE_SEL)[0]); + } + + /** + * Item. Slide or Section objects share the same properties. + */ + function Item(el, selector){ + this.anchor = el.getAttribute('data-anchor'); + this.item = el; + this.index = index(el, selector); + this.isLast = this.index === $(selector).length -1; + this.isFirst = !this.index; + } + + /** + * Section object + */ + function Section(el){ + Item.call(this, el, SECTION_SEL); + } + + /** + * Slide object + */ + function Slide(el){ + Item.call(this, el, SLIDE_SEL); + } + + return FP; + } //end of $.fn.fullpage + + + //utils + /** + * Shows a message in the console of the given type. + */ + function showError(type, text){ + window.console && window.console[type] && window.console[type]('fullPage: ' + text); + } + + /** + * Equivalent or jQuery function $(). + */ + function $(selector, context){ + context = arguments.length > 1 ? context : document; + return context ? context.querySelectorAll(selector) : null; + } + + /** + * Extends a given Object properties and its childs. + */ + function deepExtend(out) { + out = out || {}; + + for (var i = 1; i < arguments.length; i++) { + var obj = arguments[i]; + + if (!obj) + continue; + + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + if (typeof obj[key] === 'object' && obj[key] != null) + out[key] = deepExtend(out[key], obj[key]); + else + out[key] = obj[key]; + } + } + } + + return out; + } + + /** + * Checks if the passed element contains the passed class. + */ + function hasClass(el, className){ + if(el == null){ + return false; + } + if (el.classList){ + return el.classList.contains(className); + } + return new RegExp('(^| )' + className + '( |$)', 'gi').test(el.className); + } + + /** + * Gets the window height. Crossbrowser. + */ + function getWindowHeight(){ + return 'innerHeight' in window ? window.innerHeight : document.documentElement.offsetHeight; + } + + /** + * Set's the CSS properties for the passed item/s. + * @param {NodeList|HTMLElement} items + * @param {Object} props css properties and values. + */ + function css(items, props) { + items = getList(items); + + var key; + for (key in props) { + if (props.hasOwnProperty(key)) { + if (key !== null) { + for (var i = 0; i < items.length; i++) { + var item = items[i]; + item.style[key] = props[key]; + } + } + } + } + + return items; + } + + /** + * Generic function to get the previous or next element. + */ + function until(item, selector, fn){ + var sibling = item[fn]; + while(sibling && !matches(sibling, selector)){ + sibling = sibling[fn]; + } + + return sibling; + } + + /** + * Gets the previous element to the passed element that matches the passed selector. + */ + function prevUntil(item, selector){ + return until(item, selector, 'previousElementSibling'); + } + + /** + * Gets the next element to the passed element that matches the passed selector. + */ + function nextUntil(item, selector){ + return until(item, selector, 'nextElementSibling'); + } + + /** + * Gets the previous element to the passed element. + */ + function prev(item){ + return item.previousElementSibling; + } + + /** + * Gets the next element to the passed element. + */ + function next(item){ + return item.nextElementSibling; + } + + /** + * Gets the last element from the passed list of elements. + */ + function last(item){ + return item[item.length-1]; + } + + /** + * Gets index from the passed element. + * @param {String} selector is optional. + */ + function index(item, selector) { + item = isArrayOrList(item) ? item[0] : item; + var children = selector != null? $(selector, item.parentNode) : item.parentNode.childNodes; + var num = 0; + for (var i=0; iafdas'); + * wrapInner(document.querySelector('#pepe'), element); + * + * https://jsfiddle.net/zexxz0tw/6/ + * + * https://stackoverflow.com/a/21817590/1081396 + */ + function wrapInner(parent, wrapper) { + if (typeof wrapper === "string"){ + wrapper = createElementFromHTML(wrapper); + } + + parent.appendChild(wrapper); + + while(parent.firstChild !== wrapper){ + wrapper.appendChild(parent.firstChild); + } + } + + /** + * http://stackoverflow.com/questions/22100853/dom-pure-javascript-solution-to-jquery-closest-implementation + * Returns the element or `false` if there's none + */ + function closest(el, selector) { + if(el && el.nodeType === 1){ + if(matches(el, selector)){ + return el; + } + return closest(el.parentNode, selector); + } + return null; + } + + /** + * Places one element (rel) after another one or group of them (reference). + * @param {HTMLElement} reference + * @param {HTMLElement|NodeList|String} el + * https://jsfiddle.net/9s97hhzv/1/ + */ + function after(reference, el) { + insertBefore(reference, reference.nextSibling, el); + } + + /** + * Places one element (rel) before another one or group of them (reference). + * @param {HTMLElement} reference + * @param {HTMLElement|NodeList|String} el + * https://jsfiddle.net/9s97hhzv/1/ + */ + function before(reference, el) { + insertBefore(reference, reference, el); + } + + /** + * Based in https://stackoverflow.com/a/19316024/1081396 + * and https://stackoverflow.com/a/4793630/1081396 + */ + function insertBefore(reference, beforeElement, el){ + if(!isArrayOrList(el)){ + if(typeof el == 'string'){ + el = createElementFromHTML(el); + } + el = [el]; + } + + for(var i = 0; i3&&(a=a.substring(0,3)+a.substring(3).toUpperCase()),a},a.defaultLanguage=b(navigator.languages&&navigator.languages.length>0?navigator.languages[0]:navigator.language||navigator.userLanguage),a.localize=function(c,d){var e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v;return null==d&&(d={}),v=this,h={},g=d.fileExtension||"json",f=a.Deferred(),k=function(a,b,c){var e;switch(null==c&&(c=1),c){case 1:return h={},d.loadBase?(e=a+("."+g),i(e,a,b,c)):k(a,b,2);case 2:return e=""+a+"-"+b.split("-")[0]+"."+g,i(e,a,b,c);case 3:return e=""+a+"-"+b.split("-").slice(0,2).join("-")+"."+g,i(e,a,b,c);default:return f.resolve()}},i=function(b,c,e,f){var g,i,j;return null!=d.pathPrefix&&(b=""+d.pathPrefix+"/"+b),j=function(b){return a.extend(h,b),q(h),k(c,e,f+1)},i=function(){return 2===f&&e.indexOf("-")>-1?k(c,e,f+1):d.fallback&&d.fallback!==e?k(c,d.fallback):void 0},g={url:b,dataType:"json",async:!0,timeout:null!=d.timeout?d.timeout:500,success:j,error:i},"file:"===window.location.protocol&&(g.error=function(b){return j(a.parseJSON(b.responseText))}),a.ajax(g)},q=function(a){return null!=d.callback?d.callback(a,e):e(a)},e=function(b){return a.localize.data[c]=b,v.each(function(){var c,d,e;return c=a(this),d=c.data("localize"),d||(d=c.attr("rel").match(/localize\[(.*?)\]/)[1]),e=u(d,b),null!=e?l(c,d,e):void 0})},l=function(b,c,d){return b.is("input")?o(b,c,d):b.is("textarea")?o(b,c,d):b.is("img")?n(b,c,d):b.is("optgroup")?p(b,c,d):a.isPlainObject(d)||b.html(d),a.isPlainObject(d)?m(b,d):void 0},o=function(b,c,d){var e;return e=a.isPlainObject(d)?d.value:d,b.is("[placeholder]")?b.attr("placeholder",e):b.val(e)},m=function(a,b){return s(a,"title",b),s(a,"href",b),t(a,"text",b)},p=function(a,b,c){return a.attr("label",c)},n=function(a,b,c){return s(a,"alt",c),s(a,"src",c)},u=function(a,b){var c,d,e,f;for(c=a.split(/\./),d=b,e=0,f=c.length;f>e;e++)a=c[e],d=null!=d?d[a]:null;return d},s=function(a,b,c){return c=u(b,c),null!=c?a.attr(b,c):void 0},t=function(a,b,c){return c=u(b,c),null!=c?a.text(c):void 0},r=function(a){var b;return"string"==typeof a?"^"+a+"$":null!=a.length?function(){var c,d,e;for(e=[],c=0,d=a.length;d>c;c++)b=a[c],e.push(r(b));return e}().join("|"):a},j=b(d.language?d.language:a.defaultLanguage),d.skipLanguage&&j.match(r(d.skipLanguage))?f.resolve():k(c,j,1),v.localizePromise=f,v},a.fn.localize=a.localize,a.localize.data={}}(jQuery); \ No newline at end of file diff --git a/media/beaver.jpeg b/media/beaver.jpeg new file mode 100644 index 0000000..6a30d5e Binary files /dev/null and b/media/beaver.jpeg differ diff --git a/media/bg.svg b/media/bg.svg new file mode 100644 index 0000000..8efb1bb --- /dev/null +++ b/media/bg.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/media/black.ttf b/media/black.ttf new file mode 100644 index 0000000..061b1ac Binary files /dev/null and b/media/black.ttf differ diff --git a/media/h2.jpg b/media/h2.jpg new file mode 100644 index 0000000..91b4fd7 Binary files /dev/null and b/media/h2.jpg differ diff --git a/media/harambee-logo.png b/media/harambee-logo.png new file mode 100644 index 0000000..639b535 Binary files /dev/null and b/media/harambee-logo.png differ diff --git a/media/somuchfun.jpg b/media/somuchfun.jpg new file mode 100644 index 0000000..cb17054 Binary files /dev/null and b/media/somuchfun.jpg differ diff --git a/media/teampresentaties.jpg b/media/teampresentaties.jpg new file mode 100644 index 0000000..f14ece3 Binary files /dev/null and b/media/teampresentaties.jpg differ diff --git a/media/tropicalasian.ttf b/media/tropicalasian.ttf new file mode 100644 index 0000000..c968c78 Binary files /dev/null and b/media/tropicalasian.ttf differ diff --git a/media/ut-logo.png b/media/ut-logo.png new file mode 100755 index 0000000..bdbf7f9 Binary files /dev/null and b/media/ut-logo.png differ diff --git a/media/video.mp4 b/media/video.mp4 new file mode 100644 index 0000000..9f50c33 Binary files /dev/null and b/media/video.mp4 differ