slimscroll
Version:
slimscroll is a small commonjs module with no library dependencies (sans jquery) that transforms any div into a scrollable area with a nice scrollbar - similar to the one Facebook and Google started using in their products recently. slimScroll doesn't occ
1,601 lines (1,381 loc) • 112 kB
JavaScript
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
'use strict';
// console.log("example test wepps!!s");
var linotype = require('../../../index');
window.onload =function(){
window.Linotype = new linotype({
slidesColor: ['#1bbc9b', '#4BBFC3', '#7BAABE', 'whitesmoke', '#ccddff'],
anchors: ['firstPage', 'secondPage', '3rdPage', '4thpage', 'lastPage'],
menu: '#menu',
afterLoad: function(anchorLink, index){
//section 2
if(index === 2){
//moving the image
document.querySelector('#section1').querySelector('img').style.left= '0%';
document.querySelector('#section1').querySelectorAll('p')[0].style.opacity = 1;
setTimeout(function(){
document.querySelector('#section1').querySelectorAll('p')[1].style.opacity=1;
},1800);
}
//section 3
if(anchorLink === '3rdPage'){
//moving the image
document.querySelector('#section2').querySelector('.intro').style.left= '0%';
}
}
});
window.Linotype.init();
};
},{"../../../index":2}],2:[function(require,module,exports){
/*
* linotype
* http://github.amexpub.com/modules/linotype
*
* Copyright (c) 2013 AmexPub. All rights reserved.
*/
module.exports = require('./lib/linotype');
},{"./lib/linotype":4}],3:[function(require,module,exports){
/*
* linotype
* https://github.com/typesettin/linotype
* @author yaw joseph etse
* Copyright (c) 2014 Typesettin. All rights reserved.
*/
'use strict';
var classie = require('classie');
// extend = require('util-extend'),
// events = require('events'),
// util = require('util');
/**
* A module that adds simple dom utility functionality.
* @author yaw joseph etse
* @constructor
*/
var domhelper = {
/**
* toggles class across nodelist/elementcollection
* @param {object} elementCollection - html dom element
* @param {object} element - html dom element
* @param {string} name of class!
* @public
*/
removeAllClassAndToggle: function(element,elementCollection,toggleClass){
//updating the active class
for(var h =0; h <elementCollection.length; h++){
classie.removeClass(elementCollection[h],toggleClass);
}
classie.addClass(element,toggleClass);
},
/**
* removes element from dom
* @param {object} elementCollection - html dom element
* @public
*/
removeElement: function(element){
//updating the active class
element.parentNode.removeChild(element);
},
/**
* converts idnex of node in nodelist
* @param {object} nodelist - html dom element
* @param {object} element - html dom element
* @return {number} index of element in nodelist
* @method
*/
nodeIndexOfNodeList: function(nodelist,element){
return domhelper.nodelistToArray(nodelist,true).indexOf(element.outerHTML);
},
/**
* converts nodelists to arrays
* @param {node} nl - html dom element
* @return { array} array of html nodes
* @method
*/
nodelistToArray: function(nl,useStrings){
var arr = [];
for (var i = 0, ref = arr.length = nl.length; i < ref; i++) {
arr[i] = (useStrings) ? nl[i].outerHTML : nl[i];
}
return arr;
},
/**
* Returns cloaset DOM element.
* @param {node} element - html dom element
* @return {node} - closet node element
* @method
*/
closetElement: function(element){
if(typeof element.length === 'number'){
return undefined;
}
var matches = domhelper.nodelistToArray(document.querySelectorAll(element.nodeName+'.'+element.className.trim().split(" ").join("."))),
cleanMatches = [];
// console.log("matches",matches.length,matches);
for (var x =0; x < matches.length; x++){
// console.log('x',x,'element',element,'matches[x]',matches[x],'isEqualNode',matches[x].isEqualNode(element),'compareDocumentPosition',element.compareDocumentPosition(matches[x]));
if(element.compareDocumentPosition(matches[x])<4 && !matches[x].isEqualNode(element)){
cleanMatches.push(matches[x]);
}
}
function compareNumbers(a, b) {
return a.compareDocumentPosition( b ) - b.compareDocumentPosition( a );
}
// console.log("matches cleaned",cleanMatches.length,cleanMatches);
// console.log("matches sorted",cleanMatches.sort(compareNumbers));
return cleanMatches[0];
},
/**
* Hides DOM elements.
* @method
* @param {node} element - html dom element
*/
elementHideCss: function(element){
element.style.display="none";
},
/**
* Shows DOM elements.
* @method
* @param {node} element - html dom element
*/
elementShowCss: function(element){
element.setAttribute('style',element.getAttribute('style').replace("display: none;"));
},
/**
* Wraps inner elements
* @method
* @param {node} element - html dom element
* @param {node} innerElement - element to wrap html dom element
*/
elementContentWrapInner: function(element,innerElement){
var wrapper = element,
w = innerElement,
len = element.childElementCount,
wrapper_clone = wrapper.cloneNode(true);
wrapper.innerHTML='';
wrapper.appendChild(w);
var newFirstChild = wrapper.firstChild;
newFirstChild.innerHTML=wrapper_clone.innerHTML;
},
/**
* Wraps element with wrapper
* @method
* @param {node} element - html dom element
* @param {node} wrapperElement - element to wrap html dom element
*/
elementWrap: function(element,wrapperElement){
var elementParent =element.parentNode,
element_clone = element.cloneNode(true);
elementParent.replaceChild(wrapperElement,element);
wrapperElement.appendChild(element);
},
/**
* get scroll position of element
* @method
* @param {node} element - html dom element
* @return {number} position of scroll
*/
getScrollTop: function(element){
// console.log(typeof element);
if(element === window && typeof window.pageYOffset!== 'undefined'){
//most browsers except IE before #9
return window.pageYOffset;
}
else if(typeof element ==="object"){
return element.scrollTop;
}
else {
var B= document.body; //IE 'quirks'
var D= document.documentElement; //IE with doctype
D= (D.clientHeight)? D: B;
return D.scrollTop;
}
},
/**
* get scroll position of element
* @method
* @param {node} element - html dom element
* @return {object} position element
*/
getPosition: function(element) {
var xPosition = 0;
var yPosition = 0;
while(element) {
xPosition += (element.offsetLeft - element.scrollLeft + element.clientLeft);
yPosition += (element.offsetTop - element.scrollTop + element.clientTop);
element = element.offsetParent;
}
return { x: xPosition, y: yPosition, left: xPosition, top: yPosition };
},
/**
* get element selector
* @method
* @param {node} element - html dom element
* @return {string} query selector string
*/
getElementSelector: function(element){
var tagSelector = (element.tagName) ? element.tagName:'',
idSelector = (element.id) ? '#'+element.id+'':'',
classSelector='';
if(element.classList){
for(var x=0; x < element.classList.length; x++){
classSelector+='.'+element.classList[x]+"";
}
}
return tagSelector+idSelector+classSelector;
},
/**
* get parent element
* @method
* @param {node} element - html dom element
* @param {string} selector - selector
* @param {string} selectorType - selector type (id or class)
*/
getParentElement: function(element,selector,selectorType){
if(element.tagName==='BODY' || element.tagName==='HTML' || selector==='body' || selector==='html' || selector===undefined){
// console.log('body selected');
return undefined;
}
else if( (selectorType==='id' && element.parentNode.id === selector) || element.parentNode.className.match(new RegExp(selector,'g'))){
// console.log("parent node");
return element.parentNode;
//new RegExp(pattern,modifiers)
}
else {
// console.log("look up higher");
return domhelper.getParentElement(element.parentNode,selector,selectorType);
}
},
getPreviousElements: function(element,returnArray){
if(element.previousElementSibling){
returnArray.push(element.previousElementSibling);
return domhelper.getPreviousElements(element.previousElementSibling,returnArray);
}
else{
return returnArray;
}
},
getNextElements: function(element,returnArray){
if(element.nextElementSibling){
returnArray.push(element.nextElementSibling);
return domhelper.getNextElements(element.nextElementSibling,returnArray);
}
else{
return returnArray;
}
},
insertAllBefore: function(element,elementsToInsert){
var parentElement = element.parentNode;
// console.log("parentElement",parentElement,"element",element,"elementsToInsert",elementsToInsert);
if(elementsToInsert.length){
for(var x =0; x<elementsToInsert.length; x++){
// console.log(x,"elementsToInsert[x]",elementsToInsert[x])
parentElement.insertBefore(elementsToInsert[x],element);
}
}
else{
parentElement.insertBefore(elementsToInsert,element);
}
},
insertAllAfter: function(element,elementsToInsert){
var parentElement = element.parentNode;
var nextSibling = element.nextSibling;
// console.log("parentElement",parentElement,"element",element,"elementsToInsert",elementsToInsert);
if(elementsToInsert.length){
for(var x =0; x<elementsToInsert.length; x++){
// console.log(x,"elementsToInsert[x]",elementsToInsert[x])
// elementsToInsert[x].style.background="green";
parentElement.insertBefore(elementsToInsert[x],nextSibling);
}
}
else{
parentElement.insertBefore(elementsToInsert,nextSibling);
}
},
unwrapElement: function(element){
var parentNodeElem = element.parentNode;
if(parentNodeElem.nodeName !== "BODY"){
var parentParentNodeElem = parentNodeElem.parentNode;
parentParentNodeElem.innerHTML='';
parentParentNodeElem.appendChild(element);
}
},
onWindowLoaded: function(callback){
var readyStateCheckInterval = setInterval(function() {
if (document.readyState === "complete") {
callback();
clearInterval(readyStateCheckInterval);
}
}, 10);
}
};
module.exports = domhelper;
// If there is a window object, that at least has a document property,
// define linotype
if ( typeof window === "object" && typeof window.document === "object" ) {
window.domhelper = domhelper;
}
},{"classie":11}],4:[function(require,module,exports){
/**
* @title linotype
* @{@link https://github.com/typesettin/linotype}
* @author Yaw Joseph Etse
* @copyright Copyright (c) 2014 Typesettin. All rights reserved.
* @license MIT
*/
'use strict';
var classie = require('classie'),
extend = require('util-extend'),
events = require('events'),
domhelper = require('./domhelper'),
Slimscroll = require('./slimscroll'),
util = require('util');
/**
* A module that represents a linotype object, a linotyper is a page composition tool.
* @{@link https://github.com/typesettin/linotype}
* @author Yaw Joseph Etse
* @copyright Copyright (c) 2014 Typesettin. All rights reserved.
* @license MIT
* @module linotype
* @requires module:classie
* @requires module:util-extent
* @requires module:util
* @requires module:events
* @todo need to finish the .closet implementation for @linotype.getTableHeight method
* @todo need @linotype~checkParentForNormalScrollElement to fix parent.isEqualNode to loop through selector of normalscrollelements called from @linotype~touchMoveHandler
* @todo fix resizeme text sizing
* @throws {ConfigurationError} If conflicting scrolling options are set
*/
var linotype = function(config_options){
/** module default configuration */
var options,
linotypeElement,
defaults = {
'verticalCentered' : true,
'resize' : true,
'slidesColor' : [],
'anchors':[],
'scrollingSpeed': 700,
'easing': 'easeInQuart',
'menu': false,
'navigation': false,
'navigationPosition': 'right',
'navigationColor': '#000',
'navigationTooltips': [],
'slidesNavigation': false,
'slidesNavPosition': 'bottom',
'controlArrowColor': '#fff',
'loopBottom': false,
'loopTop': false,
'loopHorizontal': true,
'autoScrolling': true,
'scrollOverflow': false,
'css3': true,
'paddingTop': 0,
'paddingBottom': 0,
'fixedElements': null,
'normalScrollElements': null,
'keyboardScrolling': true,
'touchSensitivity': 5,
'continuousVertical': false,
'animateAnchor': true,
'idSelector' : 'fullpage',
'normalScrollElementTouchThreshold': 5,
//events
'afterLoad': null,
'onLeave': null,
'afterRender': null,
'afterResize': null,
'afterSlideLoad': null,
'onSlideLeave': null
},
ConfigurationError = function(message){
this.name = "ConfigurationError";
this.message = message || "Linotype Configuration Error";
},
scrollDelay = (typeof config_options === "object" && typeof config_options.scrollDelay === "number") ? config_options.scrollDelay : 600,
container,
slideMoving = false,
isTablet = navigator.userAgent.match(/(iPhone|iPod|iPad|Android|BlackBerry|Windows Phone)/),
windowsHeight,
isMoving = false,
isResizing = false,
resizeTimeout = false,
lastScrolledDestiny,
lastScrolledSlide,
scrollId,
isScrolling = false,
touchStartY = 0,
touchStartX = 0,
touchEndY = 0,
touchEndX = 0;
//extend default options
options = extend( defaults,config_options );
/**
* @exception {ConfigurationError} If conflicting scrolling options are set
*/
ConfigurationError.prototype = new Error();
ConfigurationError.prototype.constructor = ConfigurationError;
if (options.continuousVertical &&
(options.loopTop || options.loopBottom)) {
options.continuousVertical = false;
throw new ConfigurationError("Option loopTop/loopBottom is mutually exclusive with continuousVertical; continuousVertical disabled");
}
/** @throws Disable mutually exclusive settings */
if (scrollDelay < 400) {
options.continuousVertical = false;
throw new RangeError("BE CAREFUL! Not recommened to change it under 400 for a good behavior in laptops and Apple devices (laptops, mouses...)");
}
/** The current module configuration */
this.config = function(){
return options;
};
/** The current scroll delay setting */
this.scrollDelay = function(){
return scrollDelay;
};
/**
* set the scrolling behaviour
* @param {number} value
*/
this.setAutoScrolling = function(value){
options.autoScrolling = value; //el = document.getElementById( options.idSelector ), //sections = el.getElementsByClassName( options.sectionClass );
var element = document.getElementsByClassName('section active')[0],
docElemHTML = document.getElementsByTagName("html")[0],
docElemBody = document.getElementsByTagName("body")[0],
elementPosition = getPosition(element);
if(options.autoScrolling){
docElemHTML.style.overflow = 'hidden';
docElemHTML.style.height = '100%';
docElemBody.style.overflow = 'hidden';
docElemBody.style.height = '100%';
if(element.length){
//moving the container up
silentScroll(elementPosition.top);
}
}
else{
docElemHTML.style.overflow = 'auto';
docElemHTML.style.height = 'auto';
docElemBody.style.overflow = 'auto';
docElemBody.style.height = 'auto';
silentScroll(0);
//scrolling the page to the section with no animation
docElemHTML.scrollTop = elementPosition.top;
docElemBody.scrollTop = elementPosition.top;
}
};
/**
* Defines the scrolling speed
* @param {number} value - set the scrolling speed
*/
this.setScrollingSpeed = function(value){
options.scrollingSpeed = value;
};
/**
* Adds or remove the possiblity of scrolling through sections by using the keyboard arrow keys
* @param {number} value
*/
this.setKeyboardScrolling = function (value){
options.keyboardScrolling = value;
};
/**
* Adds or remove the possiblity of scrolling through sections by using the mouse wheel or the trackpad.
* @param {number} value
*/
this.setMouseWheelScrolling = function (value){
console.log('setMouseWheelScrolling',value);
if(value){
addMouseWheelHandler();
}else{
removeMouseWheelHandler();
}
};
/**
* Adds or remove the possiblity of scrolling through sections by using the mouse wheel/trackpad or touch gestures.
* @param {number} value
*/
this.setAllowScrolling = function (value){
if(value){
this.setMouseWheelScrolling(true);
addTouchHandler();
}
else{
this.setMouseWheelScrolling(false);
removeTouchHandler();
}
};
/**
* Moves to previous section
*/
this.moveSectionUp = function(){
// console.log("moveSectionUp");
var prev = document.querySelector('.section.active').previousElementSibling;
// console.log("prev",prev);
if(prev && classie.hasClass(prev,'section')){
//looping to the bottom if there's no more sections above
if (!prev && (options.loopTop || options.continuousVertical)) {
prev = document.getElementsByClassName('section')[document.getElementsByClassName('section').length - 1];
}
if (prev) {
scrollPage(prev, null, true);
}
}
};
/**
* Moves to next section
*/
this.moveSectionDown = function (){
var next = document.querySelector('.section.active').nextElementSibling;
if(next && classie.hasClass(next,'section')){
//looping to the top if there's no more sections below
if(!next &&
(options.loopBottom || options.continuousVertical)){
next = document.getElementsByClassName('section')[0];//$('.section').first();
}
if(next){
scrollPage(next, null, false);
}
}
};
/**
* Moves to specific section
* @param {number} section - number of section
* @param {number} slide - numder of slide
*/
this.moveTo = function (section, slide){
var destiny = '';
if(isNaN(section)){
destiny = document.querySelector('[data-anchor="'+section+'"]');
}else{
destiny = document.getElementsByClassName('section')[ (section -1) ];
}
if (typeof slide !== 'undefined'){
scrollPageAndSlide(section, slide);
}else if(destiny){
scrollPage(destiny);
}
};
/**
* moves slide right
*/
this.moveSlideRight = function(){
moveSlide('next');
};
/**
* moves slide left
*/
this.moveSlideLeft = function(){
moveSlide('prev');
};
/**
* intialize a new linotype
*/
this.init = function(){
var docElemBody = document.getElementsByTagName('body')[0];
windowsHeight = document.documentElement.clientHeight;
linotypeElement = document.getElementById(options.idSelector);
container = linotypeElement;
//activate touch events
this.setAllowScrolling(true);
if(options.css3){
options.css3 = support3d();
}
if(linotypeElement){
container.style.height='100%';
container.style.position='relative';
container.style['-ms-touch-action']='none';
}
else{
var oldBodyHTML = document.getElementsByTagName('body')[0].innerHTML;
document.getElementsByTagName('body')[0].innerHTML='<div id="superContainer">'+oldBodyHTML+'</div>';
container = document.getElementById('superContainer');
}
//creating the navigation dots
if (options.navigation) {
var navHTML = document.createElement('div');
navHTML.innerHTML = "<ul></ul>";
navHTML.setAttribute("id", "fullPage-nav");
docElemBody.appendChild(navHTML);
var nav = document.getElementById("fullPage-nav");
nav.style.color = options.navigationColor;
classie.addClass(nav,options.navigationPosition);
}
var sections = container.getElementsByClassName('section');
for(var index = 0; index < sections.length; index++){
var that = sections[index];
var $this = sections[index];
var slides = ($this !== 'undefined') ? $this.getElementsByClassName('slide') : 0;
var numSlides = slides.length;
//if no active section is defined, the 1st one will be the default one
if(!index && document.getElementsByClassName('section active').length === 0) {
classie.addClass($this,'active');
}
if($this.style !== undefined){
$this.style.height = windowsHeight + 'px';
if(options.paddingTop || options.paddingBottom){
$this.style.padding = options.paddingTop + ' 0 ' + options.paddingBottom + ' 0';
}
if (typeof options.slidesColor[index] !== 'undefined') {
$this.style['background-color'] = options.slidesColor[index];
}
}
if (typeof options.anchors[index] !== 'undefined' && typeof $this === 'object' ) {
$this.setAttribute('data-anchor', options.anchors[index]);
}
if (options.navigation) {
var link = (options.anchors.length)? options.anchors[index]:'',
tooltip = (typeof options.navigationTooltips[index] !== 'undefined')? options.navigationTooltips[index] : '',
navToSetHTML = document.getElementById("fullPage-nav"),
navUL = navToSetHTML.getElementsByTagName('ul')[0],
newLIToAdd = document.createElement('li');
newLIToAdd.innerHTML='<a href="#' + link + '"><span></span></a></li>';
if(tooltip){
newLIToAdd.setAttribute('data-tooltip',tooltip);
}
navUL.appendChild(newLIToAdd);
}
// if there's any slide
if (numSlides > 0) {
var sliderWidth = numSlides * 100;
var slideWidth = 100 / numSlides;
var slidesContainerEl = document.createElement("div");
var slidesContainerForControlsEl = document.createElement("div");
slidesContainerEl.setAttribute('class','slidesContainer');
slidesContainerForControlsEl.setAttribute('class','slides');
elementContentWrapInner($this,slidesContainerEl);
elementContentWrapInner($this,slidesContainerForControlsEl);
$this.getElementsByClassName('slidesContainer')[0].style.width = sliderWidth + '%';
$this.innerHTML += '<div class="controlArrow prev"></div><div class="controlArrow next"></div>';
if(options.controlArrowColor!=='#fff'){
$this.getElementsByClassName('controlArrow next')[0].style['border-color'] = 'transparent transparent transparent '+options.controlArrowColor;
$this.getElementsByClassName('controlArrow prev')[0].style['border-color'] = 'transparent transparent transparent '+options.controlArrowColor;
}
if(!options.loopHorizontal){
elementHideCss($this.getElementsByClassName('controlArrow prev')[0]);
}
if(options.slidesNavigation){
addSlidesNavigation($this, numSlides);
}
for(var i = 0; i< numSlides;i++){
//if the slide won#t be an starting point, the default will be the first one
if(!i && $this.getElementsByClassName('slide active').length ===0){
classie.addClass($this.getElementsByClassName('slide')[0],'active');
}
$this.getElementsByClassName('slide')[i].style.width=slideWidth + '%';
if(options.verticalCentered){
addTableClass($this.getElementsByClassName('slide')[i]);
}
}
}
else{
if(options.verticalCentered){
addTableClass($this);
}
}
}
this.setup();
}.bind(this);
/**
* finalizing the module for events
*/
this.setup = function(){
this.setAutoScrolling(options.autoScrolling);
var nav = document.getElementById("fullPage-nav");
//the starting point is a slide?
var activeSlide = document.getElementsByClassName('section active')[0].getElementsByClassName(' slide active')[0];
// console.log("activeSlide",activeSlide);
if( typeof activeSlide !== 'undefined' && activeSlide.length &&
( nodelistToArray(document.getElementsByClassName('section'),true).indexOf(activeSlide.outerHTML)/* $('.section.active').index('.section')*/ !== 0 ||
( nodelistToArray(document.getElementsByClassName('section'),true).indexOf(activeSlide.outerHTML) /* $('.section.active').index('.section')*/ === 0 )/*&& activeSlide.index() !== 0 */)
){
var prevScrollingSpeepd = options.scrollingSpeed;
this.setScrollingSpeed(0);
landscapeScroll(document.getElementsByClassName('section active').getElementsByClassName('slides') , activeSlide);
this.setScrollingSpeed(prevScrollingSpeepd);
}
// //fixed elements need to be moved out of the plugin container due to problems with CSS3.
if(options.fixedElements && options.css3){
document.getElementsByTagName('body')[0].appendChild(document.querySelector(options.fixedElements));
}
//vertical centered of the navigation + first bullet active
if(options.navigation){
nav.style['margin-top'] = '-' + (nav.offsetHeight/2) + 'px';
var activeSection = nodelistToArray(document.getElementsByClassName('section'),true).indexOf(document.getElementsByClassName('section active')[0].outerHTML);
var navigationATag = nav.getElementsByTagName('li')[activeSection].getElementsByTagName('a')[0];
classie.addClass(navigationATag,'active');
}
//moving the menu outside the main container (avoid problems with fixed positions when using CSS3 tranforms)
if(options.menu && options.css3){
document.getElementsByTagName('body')[0].appendChild(document.querySelector(options.menu));
}
if(options.scrollOverflow){
//after DOM and images are loaded
// if (document.readyState === "complete") { init(); }
onWindowLoaded(function(){
var sections = document.getElementsByClassName('section');
for(var x=0; x < sections.length; x++){
var slides = sections[x].getElementsByClassName('slide');
var $this = sections[x];
if(slides.length){
for(var y=0; y< slides.length; y++){
// console.log(x,y,' slides');
createSlimScrolling(slides[y]);
}
}
else{
// console.log(x,'no slides');
createSlimScrolling($this);
}
}
if(typeof options.afterRender === "function"){
options.afterRender();
}
});
}
else{
if(typeof options.afterRender === "function"){
options.afterRender();
}
}
//getting the anchor link in the URL and deleting the `#`
var value = window.location.hash.replace('#', '').split('/');
var destiny = value[0];
if(destiny.length){
var section = document.querySelector('[data-anchor="'+destiny+'"]');
if(!options.animateAnchor && section.length){
silentScroll( getPosition(section).top);
if(typeof options.afterLoad === "function"){
options.afterLoad( destiny, (nodelistToArray(document.getElementsByClassName('section'),true).indexOf(section.outerHTML) + 1));
}
//updating the active class
var sectionColllection = document.getElementsByClassName('section');
for(var h =0; h <sectionColllection.length; h++){
classie.removeClass(sectionColllection[h],'active');
}
classie.addClass(section,'active');
}
}
onWindowLoaded(function() {
scrollToAnchor();
});
this.setupEventHandlers();
}.bind(this);
/**
* The current scroll delay setting
*/
this.setupEventHandlers = function(){
window.addEventListener("hashchange", windowOnHashChangeEvent, false);
window.addEventListener("scroll",windowScrollEvent, false);
window.addEventListener("onorientationchange",browserOnOrientationChange, false);
window.addEventListener("resize",windowResizeEvent, false);
document.addEventListener("keydown",keydownEvent,false);
var sections = document.querySelectorAll('.section');
for(var t =0; t<sections.length;t++){
sections[t].addEventListener("click",sectionClickEvent,false);
}
var navlinks = document.querySelectorAll('#fullPage-nav a');
for(var x =0; x<navlinks.length;x++){
navlinks[x].addEventListener("click",navigationClickEvent,false);
}
if(options.slidesNavigation){
document.querySelector('.fullPage-slidesNav').addEventListener('click',slideNavClickEvent,false);
}
};
/**
* Adds the possibility to auto scroll through sections on touch devices.
*/
function addTouchHandler(){
document.removeEventListener('touchstart');
document.removeEventListener('MSPointerDown');
document.addEventListener('touchstart',touchStartHandler,false);
document.addEventListener('MSPointerDown',touchStartHandler,false);
document.removeEventListener('touchmove');
document.removeEventListener('MSPointerMove');
document.addEventListener('touchmove',touchMoveHandler,false);
document.addEventListener('MSPointerMove',touchMoveHandler,false);
}
/**
* Removes the auto scrolling for touch devices.
*/
function removeTouchHandler(){
document.removeEventListener('touchmove MSPointerMove');
}
var elementHideCss = domhelper.elementHideCss;
var elementShowCss = domhelper.elementShowCss;
var elementContentWrapInner = domhelper.elementContentWrapInner;
var unwrapElement = domhelper.unwrapElement;
var onWindowLoaded = domhelper.onWindowLoaded;
var nodelistToArray = domhelper.nodelistToArray;
var closetElement = domhelper.closetElement;
var getParentElement = domhelper.getParentElement;
var insertAllBefore = domhelper.insertAllBefore;
var insertAllAfter = domhelper.insertAllAfter;
var getNextElements = domhelper.getNextElements;
var getPreviousElements = domhelper.getPreviousElements;
var nodeIndexOfNodeList = domhelper.nodeIndexOfNodeList;
var getScrollTop = domhelper.getScrollTop;
var removeAllClassAndToggle = domhelper.removeAllClassAndToggle;
var getElementSelector = domhelper.getElementSelector;
var getPosition = domhelper.getPosition;
function touchStartHandler(e){
var touchEvents = getEventsPage(e);
touchStartY = touchEvents.y;
touchStartX = touchEvents.x;
}
/**
* 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 = [];
if (window.navigator.msPointerEnabled){
events.y = e.pageY;
events.x = e.pageX;
}else{
events.y = e.touches[0].pageY;
events.x = e.touches[0].pageX;
}
return events;
}
/* 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.
*/
var touchMoveHandler = function(e){
// var e = event;
if(options.autoScrolling){
//preventing the easing on iOS devices
e.preventDefault();
}
// additional: if one of the normalScrollElements isn't within options.normalScrollElementTouchThreshold hops up the DOM chain
if (!checkParentForNormalScrollElement(e.target)) {
var touchMoved = false;
var activeSection = document.querySelector('.section.active');
var scrollable;
if (!isMoving && !slideMoving) { //if theres any #
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 (activeSection.getElementsByClassName('slide').length && Math.abs(touchStartX - touchEndX) > (Math.abs(touchStartY - touchEndY))) {
//is the movement greater than the minimum resistance to scroll?
if (Math.abs(touchStartX - touchEndX) > (window.innerWidth / 100 * options.touchSensitivity)) {
if (touchStartX > touchEndX) {
this.moveSlideRight(); //next
} else {
this.moveSlideLeft(); //prev
}
}
}
//vertical scrolling (only when autoScrolling is enabled)
else if(options.autoScrolling){
//if there are landscape slides, we check if the scrolling bar is in the current one or not
if(activeSection.getElementsByClassName('slide').length){
scrollable= activeSection.querySelector('.slide.active').querySelector('.scrollable');
}else{
scrollable = activeSection.querySelector('.scrollable');
}
//is the movement greater than the minimum resistance to scroll?
if (Math.abs(touchStartY - touchEndY) > (window.innerHeight / 100 * options.touchSensitivity)) {
if (touchStartY > touchEndY) {
if(scrollable && scrollable.length > 0 ){
//is the scrollbar at the end of the scroll?
if(isScrolled('bottom', scrollable)){
this.moveSectionDown();
}else{
return true;
}
}else{
// moved down
this.moveSectionDown();
}
} else if (touchEndY > touchStartY) {
if(scrollable && scrollable.length > 0){
//is the scrollbar at the start of the scroll?
if(isScrolled('top', scrollable)){
this.moveSectionUp();
}
else{
return true;
}
}else{
// moved up
this.moveSectionUp();
}
}
}
}
}
}
}.bind(this);
/**
* recursive function to loop up the parent nodes to check if one of them exists in options.normalScrollElements
* Currently works well for iOS - Android might need some testing
* @param {Element} el target element / jquery selector (in subsequent nodes)
* @param {int} hop current hop compared to options.normalScrollElementTouchThreshold
* @return {boolean} true if there is a match to options.normalScrollElements
* @todo need to fix parent.isEqualNode to loop through selector of normalscrollelements called from @linotype~touchMoveHandler
*/
function checkParentForNormalScrollElement (el, hop) {
hop = hop || 0;
var parent = el.parentNode;
if (hop < options.normalScrollElementTouchThreshold &&
parent.isEqualNode(document.querySelector(options.normalScrollElements)) ) {
return true;
} else if (hop === options.normalScrollElementTouchThreshold) {
return false;
} else {
return checkParentForNormalScrollElement(parent, ++hop);
}
}
/**
* Retuns `up` or `down` depending on the scrolling movement to reach its destination
* from the current section.
*/
function getYmovement(destiny){
var fromIndex = nodeIndexOfNodeList(document.getElementsByClassName('section'),document.getElementsByClassName('section active')[0]); //$('.section.active').index('.section');
var toIndex = nodeIndexOfNodeList(document.getElementsByClassName('section'),destiny);//destiny.index('.section');
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';
}
/**
* Sliding with arrow keys, both, vertical and horizontal
*/
var keydownEvent = function(e){
console.log("keydownEvent",isMoving);
if (options.keyboardScrolling && !isMoving) {
switch (e.which) {
//up
case 38:
case 33:
this.moveSectionUp();
break;
//down
case 40:
case 34:
this.moveSectionDown();
break;
//left
case 37:
this.moveSlideLeft();
break;
//right
case 39:
this.moveSlideRight();
break;
default:
return; // exit this handler for other keys
}
}
}.bind(this);
/**
* Removes the auto scrolling action fired by the mouse wheel and tackpad.
* 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
} else {
document.detachEvent("onmousewheel", MouseWheelHandler); //IE 6/7/8
}
}
/**
* Adds the auto scrolling action for the mouse wheel and tackpad.
* After this function is called, the mousewheel and trackpad movements will scroll through sections
*/
function addMouseWheelHandler(){
if (document.addEventListener) {
document.addEventListener("mousewheel", MouseWheelHandler, false); //IE9, Chrome, Safari, Oper
document.addEventListener("wheel", MouseWheelHandler, false); //Firefox
} else {
document.attachEvent("onmousewheel", MouseWheelHandler); //IE 6/7/8
}
}
/**
* Detecting mousewheel scrolling
*
* http://blogs.sitepointstatic.com/examples/tech/mouse-wheel/index.html
* http://www.sitepoint.com/html5-javascript-mouse-wheel/
*/
var MouseWheelHandler = function (e){
/* jshint debug:true */
// debugger;
if(options.autoScrolling){
// cross-browser wheel delta
e = window.event || e;
var delta = Math.max(-1, Math.min(1,
(e.wheelDelta || -e.deltaY || -e.detail)));
var scrollable;
var activeSection = document.querySelector('.section.active');
if (!isMoving) { //if theres any #
//if there are landscape slides, we check if the scrolling bar is in the current one or not
if(activeSection.querySelectorAll('.slides').length){
console.log("has slides");
scrollable= activeSection.querySelector('.slide.active').querySelector('.scrollable');
}else{
console.log("on section");
scrollable = activeSection.querySelector('.scrollable');
// console.log("scrollable.length",(typeof scrollable.length));
}
//scrolling down?
if (delta < 0) {
if(scrollable){
//is the scrollbar at the end of the scroll?
if(isScrolled('bottom', scrollable)){
this.moveSectionDown();
}else{
return true; //normal scroll
}
}else{
this.moveSectionDown();
}
}
//scrolling up?
else {
if(scrollable){
//is the scrollbar at the start of the scroll?
if(isScrolled('top', scrollable)){
this.moveSectionUp();
}else{
return true; //normal scroll
}
}else{
this.moveSectionUp();
}
}
}
return false;
}
}.bind(this);
/** handle updating window hash location */
function windowOnHashChangeEvent(e){
if(!isScrolling){
var value = window.location.hash.replace('#', '').split('/');
var section = value[0];
var slide = value[1];
//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 slide === 'undefined');
/*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 ((section && section !== lastScrolledDestiny) && !isFirstSlideMove || isFirstScrollMove || (!slideMoving && lastScrolledSlide !== slide )) {
scrollPageAndSlide(section, slide);
}
}
}
//window scroll event
function windowScrollEvent(e){
// console.log("window scroll");
var allSections = document.getElementsByClassName('section');
if(!options.autoScrolling){
var currentScroll = getScrollTop(window);
var scrolledSections = [];
nodelistToArray(document.querySelectorAll('.section')).map(function(mapIndex,index,arr){
var $this = mapIndex;
if ($this.offsetTop< (currentScroll + 100)){
if($this){scrolledSections.push($this);}
}
});
//geting the last one, the current one on the screen
var currentSectionIndex = scrolledSections.length-1;
var currentSection = scrolledSections[currentSectionIndex];
// console.log("currentSection",currentSection);
//executing only once the first time we reach the section
if(!classie.hasClass(currentSection,'active')){
var leavingSection =nodeIndexOfNodeList(document.getElementsByClassName('section'),document.querySelector('.section.active')) +1;
isScrolling = true;
var yMovement = getYmovement(currentSection);
removeAllClassAndToggle(currentSection,allSections,'active');
var anchorLink = currentSection.getAttribute('data-anchor');
if(typeof options.onLeave ==='function'){
options.onLeave.call(leavingSection, (currentSectionIndex + 1), yMovement);
}
activateMenuElement(anchorLink);
activateNavDots(anchorLink, 0);
if(options.anchors.length && !isMoving){
//needed to enter in hashChange event when using the menu with anchor links
lastScrolledDestiny = anchorLink;
location.hash = anchorLink;
}
//small timeout in order to avoid entering in hashChange event when scrolling is not finished yet
clearTimeout(scrollId);
scrollId = setTimeout(function(){
isScrolling = false;
}, 100);
}
}
}
//navigation action
function navigationClickEvent(e){
e.preventDefault();
var atarget = e.target.parentNode.parentNode;
var allNavTargets = e.target.parentNode.parentNode.parentNode.children;
var index = nodeIndexOfNodeList(allNavTargets,atarget);
scrollPage(document.getElementsByClassName('section')[index]);
}
//slidenav click event
function slideNavClickEvent(e){
e.preventDefault();
var etarget = e.target;
if(etarget.tagName==='SPAN'){
var slides = document.querySelector('.section.active').querySelectorAll('.slide'),
destiny;
var slideLI = etarget.parentNode.parentNode;
var allSlidesLI = etarget.parentNode.parentNode.parentNode.children;
classie.addClass(slideLI,'clickedTarget');
destiny = slides[nodeIndexOfNodeList(allSlidesLI,slideLI)];
classie.removeClass(slideLI,'clickedTarget');
landscapeScroll(slides,destiny);
}
}
//click events
var sectionClickEvent = function(e){
var eventTarget = e.target;
if(classie.hasClass(eventTarget,'controlArrow')){
if(classie.hasClass(eventTarget,'prev')){
this.moveSlideLeft();
}
else{
this.moveSlideRight();
}
}
else if(classie.hasClass(eventTarget,'toSlide')){
e.preventDefault();
console.log("toSlide");
// var slides = $(this).closest('.section').find('.slides');
// var currentSlide = slides.find('.slide.active');
// var destiny = null;
// destiny = slides.find('.slide').eq( ($(this).data('index') -1) );
// if(destiny.length > 0){
// landscapeScroll(slides, destiny);
// }
}
}.bind(this);
//window resize event
function windowResizeEvent(e){
clearTimeout(resizeTimeout);
resizeTimeout = setTimeout(doneResizing, 500);
}
//mobile orientation change
function browserOnOrientationChange(e){
console.log("browserOnOrientationChange");
doneResizing();
}
/**
* When resizing is finished, we adjust the slides sizes and positions
*/
function doneResizing() {
isResizing = true;
var windowsWidth = window.innerWidth;
windowsHeight = window.innerHeight;
//text and images resizing
if (options.resize) {
resizeMe(windowsHeight, windowsWidth);
}
var allSections = document.getElementsByClassName('section');
for(var x = 0; x <allSections.length; x++){
var $this = allSections[x],
scrollHeight = getScrollHeight($this),
slides = $this.querySelectorAll('.slide');
//adjusting the height of the table-cell for IE and Firefox
if(options.verticalCentered){
$this.querySelector('.tableCell').style.height = getTableHeight($this) + 'px';
}
$this.style.height = windowsHeight + 'px';
//resizing the scrolling divs
if(options.scrollOverflow){
if(slides.length){
for(var y=0; y< slides.length; y++){
// console.log(x,y,' slides');
createSlimScrolling(slides[y]);
}
}else{
createSlimScrolling($this);
}
}
//adjusting the position fo the FULL WIDTH slides...
if (slides.length) {
landscapeScroll(slides, $this.querySelector('.slide.active'));
}
}
//adjusting the position for the current section
var activeSection = document.querySelector('.section.active');
var destinyPos = getPosition(activeSection);
//isn't it the first section?
if(nodeIndexOfNodeList(allSections,activeSection)){
scrollPage(activeSection);
}
isResizing = false;
if(typeof options.afterResize ==='function') {options.afterResize.call();}
}
/**
* Resizing of the font size depending on the window size as well as some of the images on the site.
*/
function resizeMe(displayHeight, displayWidth) {
//Standard height, for which the body font size is correct
var preferredHeight = 825;
var windowSize = displayHeight;
/* Problem to be solved
if (displayHeight < 825) {
var percentage = (windowSize * 100) / preferredHeight;
var newFontSize = percentage.toFixed(2);
$("img").each(function() {
var newWidth = ((80 * percentage) / 100).toFixed(2);
$(this).css("width", newWidth + '%');
});
} else {
$("img").each(function() {
$(this).css("width", '');
});
}*/
if (displayHeight < 825 || displayWidth < 900) {
// console.log("displayHeight",displayHeight);
// console.log("displayWidth",displayWidth);
if (displayWidth < 900) {
windowSize = displayWidth;
preferredHeight = 900;
}
var percentage = (windowSize * 100) / preferredHeight;
var newFontSize = percentage.toFixed(2);
// console.log("percentage",percentage);
// console.log("newFontSize",newFontSize);
document.getElementsByTagName("body")[0].style["font-size"] = newFontSize + '%';
} else {
// console.log("displayHeight",displayHeight);
// console.log("displayWidth",displayWidth);
document.getElementsByTagName("body")[0].style["font-size"] = '100%';
}
}
function scrollToAnchor(){
//getting the anchor link in the URL and deleting the `#`
var value = window.location.hash.replace('#', '').split('/');
var section = value[0];
var slide = value[1];
if(section){ //if theres any #
scrollPageAndSlide(section, slide);
}
}
/**
* Scrolls to the given section and slide
*/
function scrollPageAndSlide(destiny, slide){
// console.log("scrollPageAndSlide");
var section;
if (typeof slide === 'undefined') {
slide = 0;
}
if(isNaN(destiny)){
section = document.querySelector('[data-anchor="'+destiny+'"]');
}
else{
section = document.getElementsByClassName('section')[(destiny -1)];
}
if(section){
//we need to scroll to the section and then to the slide
if (destiny !== lastScrolledDestiny && !classie.hasClass(section,'active')){
scrollPage(section, function(){
scrollSlider(section, slide);
});
}
//if we were already in the section
else{
scrollSlider(section, slide);
}
}
}
/**
* Scrolls the slider to the given slide destination for the given section
*/
function scrollSlider(section, slide){
if(typeof slide !== 'undefined' && slide !== 0){
var slides = section.querySelectorAll('.slide');
var destiny = section.querySelector('.slides').querySelector('[data-anchor="'+slide+'"]');
if(!destiny){
destiny = section.querySelectorAll('.slide')[slide];
}
if(destiny){
landscapeScroll(slides, destiny);
}
}
}
function moveSlide(direction){
var activeSection = document.querySelector('.section.active');
var slides = activeSection.getElementsByClassName('slide');
// more than one slide needed and nothing should be sliding
if (!slides.length || slideMoving) {
return;
}
var currentSlide = activeSection.querySelector('.slide.active');
var destiny = null;
if(direction === 'prev'){
destiny = currentSlide.previousElementSibling;
}else{
destiny = currentSlide.nextElementSibling;
}
//isn't there a next slide in the secuence?
if(!destiny){
//respect loopHorizontal settin
if (!options.loopHorizontal) {return;}
if(direction === 'prev'){
destiny = currentSlide.parentNode.lastElementChild;// currentSlide.siblings(':last');
}else{
destiny = currentSlide.parentNode.firstElementChild;//currentSlide.siblings(':first');
}
}
slideMoving = true;
landscapeScroll(slides, destiny);
}
function scrollPage(element, callback, isMovementUp){
var scrollOptions = {}, scrolledElement,
dest = getPosition(element);
if(typeof dest === "undefined"){ return; } //there's no element to scroll, leaving the function
/** @todo TODO: why does dest.bottom === jquery.position().top */
var dtop = dest.top,
yMovement = getYmovement(element),
anchorLink = element.getAttribute('data-anchor'),
sectionIndex = nodelistToArray(document.getElementsByClassName('section'),true).indexOf(element.outerHTML), ///element.index('.section');
activeSlide = element.querySelector('.slide.active'),
activeSection = document.querySelector('.section.active'),
leavingSection = nodelistToArray(document.getElementsByClassName('section'),true).indexOf(activeSection.outerHTML) +1,//activeSection.index('.section') + 1;
slideAnchorLink = null,
slideIndex = null,
localIsResizing = isResizing;//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
if(activeSlide !== null){
slideAnchorLink = activeSlide.getAttribute('data-anchor');
slideIndex = nodelistToArray(element.getElementsByClassName('slide'),true).indexOf(activeSlide.outerHTML);//activeSlide.index();
}
// console.log("slideIndex",slideIndex);
// If continuousVertical && we need to wrap around
if (options.autoScrolling && options.continuousVertical && typeof (isMovementUp) !== "undefined" &&
((!isMovementUp && yMovement === 'up') || // Intending to scroll down but about to go up or
(isMovementUp && yMovement === 'down'))) { // intending to scroll up but about to go down
// Scrolling down
if (!isMovementUp) {
// Move all previous sections to after the active section
var muarray =[];
insertAllAfter(activeSection,getPreviousElements(activeSection,muarray).reverse());
// $(".section.active").after(activeSection.prevAll(".section").get().reverse());
}
else { // Scrolling up
// Move all next sections to before the active section
var mdarray =[];
insertAllBefore(activeSection,getNextElements(activeSection,mdarray));