jquery.fullPage.js 53 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773
  1. /**
  2. * fullPage 2.4.3
  3. * https://github.com/alvarotrigo/fullPage.js
  4. * MIT licensed
  5. *
  6. * Copyright (C) 2013 alvarotrigo.com - A project by Alvaro Trigo
  7. */
  8. (function($) {
  9. $.fn.fullpage = function(options) {
  10. // Create some defaults, extending them with any options that were provided
  11. options = $.extend({
  12. //navigation
  13. 'menu': false,
  14. 'anchors':[],
  15. 'navigation': false,
  16. 'navigationPosition': 'right',
  17. 'navigationColor': '#000',
  18. 'navigationTooltips': [],
  19. 'slidesNavigation': false,
  20. 'slidesNavPosition': 'bottom',
  21. //scrolling
  22. 'css3': false,
  23. 'scrollingSpeed': 700,
  24. 'autoScrolling': true,
  25. 'easing': 'easeInQuart',
  26. 'easingcss3': 'ease',
  27. 'loopBottom': false,
  28. 'loopTop': false,
  29. 'loopHorizontal': true,
  30. 'continuousVertical': false,
  31. 'fitSection': false,
  32. 'normalScrollElements': null,
  33. 'scrollOverflow': false,
  34. 'touchSensitivity': 5,
  35. 'normalScrollElementTouchThreshold': 5,
  36. //Accessibility
  37. 'keyboardScrolling': true,
  38. 'animateAnchor': true,
  39. //design
  40. 'controlArrowColor': '#fff',
  41. "verticalCentered": true,
  42. 'resize': true,
  43. 'sectionsColor' : [],
  44. 'paddingTop': 0,
  45. 'paddingBottom': 0,
  46. 'fixedElements': null,
  47. 'responsive': 0,
  48. //Custom selectors
  49. 'sectionSelector': '.section',
  50. 'slideSelector': '.slide',
  51. //events
  52. 'afterLoad': null,
  53. 'onLeave': null,
  54. 'afterRender': null,
  55. 'afterResize': null,
  56. 'afterReBuild': null,
  57. 'afterSlideLoad': null,
  58. 'onSlideLeave': null
  59. }, options);
  60. // Disable mutually exclusive settings
  61. if (options.continuousVertical &&
  62. (options.loopTop || options.loopBottom)) {
  63. options.continuousVertical = false;
  64. console && console.log && console.log("Option loopTop/loopBottom is mutually exclusive with continuousVertical; continuousVertical disabled");
  65. }
  66. //Defines the delay to take place before being able to scroll to the next section
  67. //BE CAREFUL! Not recommened to change it under 400 for a good behavior in laptops and
  68. //Apple devices (laptops, mouses...)
  69. var scrollDelay = 600;
  70. $.fn.fullpage.setAutoScrolling = function(value){
  71. options.autoScrolling = value;
  72. var element = $('.fp-section.active');
  73. if(options.autoScrolling){
  74. $('html, body').css({
  75. 'overflow' : 'hidden',
  76. 'height' : '100%'
  77. });
  78. //for IE touch devices
  79. container.css({
  80. '-ms-touch-action': 'none',
  81. 'touch-action': 'none'
  82. });
  83. if(element.length){
  84. //moving the container up
  85. silentScroll(element.position().top);
  86. }
  87. }else{
  88. $('html, body').css({
  89. 'overflow' : 'visible',
  90. 'height' : 'initial'
  91. });
  92. //for IE touch devices
  93. container.css({
  94. '-ms-touch-action': '',
  95. 'touch-action': ''
  96. });
  97. silentScroll(0);
  98. //scrolling the page to the section with no animation
  99. $('html, body').scrollTop(element.position().top);
  100. }
  101. };
  102. /**
  103. * Defines the scrolling speed
  104. */
  105. $.fn.fullpage.setScrollingSpeed = function(value){
  106. options.scrollingSpeed = value;
  107. };
  108. /**
  109. * Adds or remove the possiblity of scrolling through sections by using the mouse wheel or the trackpad.
  110. */
  111. $.fn.fullpage.setMouseWheelScrolling = function (value){
  112. if(value){
  113. addMouseWheelHandler();
  114. }else{
  115. removeMouseWheelHandler();
  116. }
  117. };
  118. /**
  119. * Adds or remove the possiblity of scrolling through sections by using the mouse wheel/trackpad or touch gestures.
  120. */
  121. $.fn.fullpage.setAllowScrolling = function (value){
  122. if(value){
  123. $.fn.fullpage.setMouseWheelScrolling(true);
  124. addTouchHandler();
  125. }else{
  126. $.fn.fullpage.setMouseWheelScrolling(false);
  127. removeTouchHandler();
  128. }
  129. };
  130. /**
  131. * Adds or remove the possiblity of scrolling through sections by using the keyboard arrow keys
  132. */
  133. $.fn.fullpage.setKeyboardScrolling = function (value){
  134. options.keyboardScrolling = value;
  135. };
  136. $.fn.fullpage.moveSectionUp = function(){
  137. var prev = $('.fp-section.active').prev('.fp-section');
  138. //looping to the bottom if there's no more sections above
  139. if (!prev.length && (options.loopTop || options.continuousVertical)) {
  140. prev = $('.fp-section').last();
  141. }
  142. if (prev.length) {
  143. scrollPage(prev, null, true);
  144. }
  145. };
  146. $.fn.fullpage.moveSectionDown = function (){
  147. var next = $('.fp-section.active').next('.fp-section');
  148. //looping to the top if there's no more sections below
  149. if(!next.length &&
  150. (options.loopBottom || options.continuousVertical)){
  151. next = $('.fp-section').first();
  152. }
  153. if(next.length){
  154. scrollPage(next, null, false);
  155. }
  156. };
  157. $.fn.fullpage.moveTo = function (section, slide){
  158. var destiny = '';
  159. if(isNaN(section)){
  160. destiny = $('[data-anchor="'+section+'"]');
  161. }else{
  162. destiny = $('.fp-section').eq( (section -1) );
  163. }
  164. if (typeof slide !== 'undefined'){
  165. scrollPageAndSlide(section, slide);
  166. }else if(destiny.length > 0){
  167. scrollPage(destiny);
  168. }
  169. };
  170. $.fn.fullpage.moveSlideRight = function(){
  171. moveSlide('next');
  172. };
  173. $.fn.fullpage.moveSlideLeft = function(){
  174. moveSlide('prev');
  175. };
  176. /**
  177. * When resizing is finished, we adjust the slides sizes and positions
  178. */
  179. $.fn.fullpage.reBuild = function(resizing){
  180. isResizing = true;
  181. var windowsWidth = $(window).width();
  182. windowsHeight = $(window).height();
  183. //text and images resizing
  184. if (options.resize) {
  185. resizeMe(windowsHeight, windowsWidth);
  186. }
  187. $('.fp-section').each(function(){
  188. var scrollHeight = windowsHeight - parseInt($(this).css('padding-bottom')) - parseInt($(this).css('padding-top'));
  189. //adjusting the height of the table-cell for IE and Firefox
  190. if(options.verticalCentered){
  191. $(this).find('.fp-tableCell').css('height', getTableHeight($(this)) + 'px');
  192. }
  193. $(this).css('height', windowsHeight + 'px');
  194. //resizing the scrolling divs
  195. if(options.scrollOverflow){
  196. var slides = $(this).find('.fp-slide');
  197. if(slides.length){
  198. slides.each(function(){
  199. createSlimScrolling($(this));
  200. });
  201. }else{
  202. createSlimScrolling($(this));
  203. }
  204. }
  205. //adjusting the position fo the FULL WIDTH slides...
  206. var slides = $(this).find('.fp-slides');
  207. if (slides.length) {
  208. landscapeScroll(slides, slides.find('.fp-slide.active'));
  209. }
  210. });
  211. //adjusting the position for the current section
  212. var destinyPos = $('.fp-section.active').position();
  213. var activeSection = $('.fp-section.active');
  214. //isn't it the first section?
  215. if(activeSection.index('.fp-section')){
  216. scrollPage(activeSection);
  217. }
  218. isResizing = false;
  219. $.isFunction( options.afterResize ) && resizing && options.afterResize.call( this )
  220. $.isFunction( options.afterReBuild ) && !resizing && options.afterReBuild.call( this );
  221. }
  222. //flag to avoid very fast sliding for landscape sliders
  223. var slideMoving = false;
  224. var isTouchDevice = navigator.userAgent.match(/(iPhone|iPod|iPad|Android|BlackBerry|BB10|Windows Phone|Tizen|Bada)/);
  225. var isTouch = (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0));
  226. var container = $(this);
  227. var windowsHeight = $(window).height();
  228. var isMoving = false;
  229. var isResizing = false;
  230. var lastScrolledDestiny;
  231. var lastScrolledSlide;
  232. var nav;
  233. var wrapperSelector = 'fullpage-wrapper';
  234. $.fn.fullpage.setAllowScrolling(true);
  235. //if css3 is not supported, it will use jQuery animations
  236. if(options.css3){
  237. options.css3 = support3d();
  238. }
  239. if($(this).length){
  240. container.css({
  241. 'height': '100%',
  242. 'position': 'relative'
  243. });
  244. //adding a class to recognize the container internally in the code
  245. container.addClass(wrapperSelector);
  246. }
  247. //trying to use fullpage without a selector?
  248. else{
  249. console.error("Error! Fullpage.js needs to be initialized with a selector. For example: $('#myContainer').fullpage();");
  250. }
  251. //adding internal class names to void problem with common ones
  252. $(options.sectionSelector).each(function(){
  253. $(this).addClass('fp-section');
  254. });
  255. $(options.slideSelector).each(function(){
  256. $(this).addClass('fp-slide');
  257. });
  258. //creating the navigation dots
  259. if (options.navigation) {
  260. addVerticalNavigation();
  261. }
  262. $('.fp-section').each(function(index){
  263. var that = $(this);
  264. var slides = $(this).find('.fp-slide');
  265. var numSlides = slides.length;
  266. //if no active section is defined, the 1st one will be the default one
  267. if(!index && $('.fp-section.active').length === 0) {
  268. $(this).addClass('active');
  269. }
  270. $(this).css('height', windowsHeight + 'px');
  271. if(options.paddingTop || options.paddingBottom){
  272. $(this).css('padding', options.paddingTop + ' 0 ' + options.paddingBottom + ' 0');
  273. }
  274. if (typeof options.sectionsColor[index] !== 'undefined') {
  275. $(this).css('background-color', options.sectionsColor[index]);
  276. }
  277. if (typeof options.anchors[index] !== 'undefined') {
  278. $(this).attr('data-anchor', options.anchors[index]);
  279. }
  280. // if there's any slide
  281. if (numSlides > 1) {
  282. var sliderWidth = numSlides * 100;
  283. var slideWidth = 100 / numSlides;
  284. slides.wrapAll('<div class="fp-slidesContainer" />');
  285. slides.parent().wrap('<div class="fp-slides" />');
  286. $(this).find('.fp-slidesContainer').css('width', sliderWidth + '%');
  287. $(this).find('.fp-slides').after('<div class="fp-controlArrow fp-prev"></div><div class="fp-controlArrow fp-next"></div>');
  288. if(options.controlArrowColor!='#fff'){
  289. $(this).find('.fp-controlArrow.fp-next').css('border-color', 'transparent transparent transparent '+options.controlArrowColor);
  290. $(this).find('.fp-controlArrow.fp-prev').css('border-color', 'transparent '+ options.controlArrowColor + ' transparent transparent');
  291. }
  292. if(!options.loopHorizontal){
  293. $(this).find('.fp-controlArrow.fp-prev').hide();
  294. }
  295. if(options.slidesNavigation){
  296. addSlidesNavigation($(this), numSlides);
  297. }
  298. slides.each(function(index) {
  299. $(this).css('width', slideWidth + '%');
  300. if(options.verticalCentered){
  301. addTableClass($(this));
  302. }
  303. });
  304. var startingSlide = that.find('.fp-slide.active');
  305. //if the slide won#t be an starting point, the default will be the first one
  306. if(startingSlide.length == 0){
  307. slides.eq(0).addClass('active');
  308. }
  309. //is there a starting point for a non-starting section?
  310. else{
  311. silentLandscapeScroll(startingSlide);
  312. }
  313. }else{
  314. if(options.verticalCentered){
  315. addTableClass($(this));
  316. }
  317. }
  318. }).promise().done(function(){
  319. $.fn.fullpage.setAutoScrolling(options.autoScrolling);
  320. //the starting point is a slide?
  321. var activeSlide = $('.fp-section.active').find('.fp-slide.active');
  322. //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.
  323. if( activeSlide.length && ($('.fp-section.active').index('.fp-section') != 0 || ($('.fp-section.active').index('.fp-section') == 0 && activeSlide.index() != 0))){
  324. silentLandscapeScroll(activeSlide);
  325. }
  326. //fixed elements need to be moved out of the plugin container due to problems with CSS3.
  327. if(options.fixedElements && options.css3){
  328. $(options.fixedElements).appendTo('body');
  329. }
  330. //vertical centered of the navigation + first bullet active
  331. if(options.navigation){
  332. nav.css('margin-top', '-' + (nav.height()/2) + 'px');
  333. nav.find('li').eq($('.fp-section.active').index('.fp-section')).find('a').addClass('active');
  334. }
  335. //moving the menu outside the main container if it is inside (avoid problems with fixed positions when using CSS3 tranforms)
  336. if(options.menu && options.css3 && $(options.menu).closest('.fullpage-wrapper').length){
  337. $(options.menu).appendTo('body');
  338. }
  339. if(options.scrollOverflow){
  340. if(document.readyState === "complete"){
  341. createSlimScrollingHandler();
  342. }
  343. //after DOM and images are loaded
  344. $(window).on('load', createSlimScrollingHandler);
  345. }else{
  346. $.isFunction( options.afterRender ) && options.afterRender.call( this);
  347. }
  348. responsive();
  349. //getting the anchor link in the URL and deleting the `#`
  350. var value = window.location.hash.replace('#', '').split('/');
  351. var destiny = value[0];
  352. if(destiny.length){
  353. var section = $('[data-anchor="'+destiny+'"]');
  354. if(!options.animateAnchor && section.length){
  355. if(options.autoScrolling){
  356. silentScroll(section.position().top);
  357. }
  358. else{
  359. silentScroll(0);
  360. //scrolling the page to the section with no animation
  361. $('html, body').scrollTop(section.position().top);
  362. }
  363. activateMenuAndNav(destiny, null);
  364. $.isFunction( options.afterLoad ) && options.afterLoad.call( this, destiny, (section.index('.fp-section') + 1));
  365. //updating the active class
  366. section.addClass('active').siblings().removeClass('active');
  367. }
  368. }
  369. $(window).on('load', function() {
  370. scrollToAnchor();
  371. });
  372. });
  373. /**
  374. * Creates a vertical navigation bar.
  375. */
  376. function addVerticalNavigation(){
  377. $('body').append('<div id="fp-nav"><ul></ul></div>');
  378. nav = $('#fp-nav');
  379. nav.css('color', options.navigationColor);
  380. nav.addClass(options.navigationPosition);
  381. for(var cont = 0; cont < $('.fp-section').length; cont++){
  382. var link = '';
  383. if(options.anchors.length){
  384. link = options.anchors[cont];
  385. }
  386. var tooltip = options.navigationTooltips[cont];
  387. if(typeof tooltip === 'undefined'){
  388. tooltip = '';
  389. }
  390. nav.find('ul').append('<li data-tooltip="' + tooltip + '"><a href="#' + link + '"><span></span></a></li>');
  391. }
  392. }
  393. function createSlimScrollingHandler(){
  394. $('.fp-section').each(function(){
  395. var slides = $(this).find('.fp-slide');
  396. if(slides.length){
  397. slides.each(function(){
  398. createSlimScrolling($(this));
  399. });
  400. }else{
  401. createSlimScrolling($(this));
  402. }
  403. });
  404. $.isFunction( options.afterRender ) && options.afterRender.call( this);
  405. }
  406. //stop autoScrolling when the user scrolls
  407. $("html, body").bind("scroll mousedown DOMMouseScroll mousewheel keyup", function(){
  408. if(!options.autoScrolling && options.fitSection){
  409. $('html, body').stop();
  410. isMoving = false;
  411. }
  412. });
  413. var scrollId;
  414. var scrollId2;
  415. var isScrolling = false;
  416. //when scrolling...
  417. $(window).on('scroll', scrollHandler);
  418. function scrollHandler(){
  419. if(!options.autoScrolling){
  420. var currentScroll = $(window).scrollTop();
  421. var visibleSectionIndex = 0;
  422. var initial = Math.abs(currentScroll - $('.fp-section').first().offset().top);
  423. //taking the section which is showing more content in the viewport
  424. $('.fp-section').each(function(index){
  425. var current = Math.abs(currentScroll - $(this).offset().top);
  426. if(current < initial){
  427. visibleSectionIndex = index;
  428. initial = current;
  429. }
  430. });
  431. //geting the last one, the current one on the screen
  432. var currentSection = $('.fp-section').eq(visibleSectionIndex);
  433. //executing only once the first time we reach the section
  434. if(!currentSection.hasClass('active')){
  435. isScrolling = true;
  436. var leavingSection = $('.fp-section.active').index('.fp-section') + 1;
  437. var yMovement = getYmovement(currentSection);
  438. var anchorLink = currentSection.data('anchor');
  439. currentSection.addClass('active').siblings().removeClass('active');
  440. if(!isMoving){
  441. $.isFunction( options.onLeave ) && options.onLeave.call( this, leavingSection, (currentSection.index('.fp-section') + 1), yMovement);
  442. $.isFunction( options.afterLoad ) && options.afterLoad.call( this, anchorLink, (currentSection.index('.fp-section') + 1));
  443. }
  444. activateMenuAndNav(anchorLink, 0);
  445. if(options.anchors.length && !isMoving){
  446. //needed to enter in hashChange event when using the menu with anchor links
  447. lastScrolledDestiny = anchorLink;
  448. location.hash = anchorLink;
  449. }
  450. //small timeout in order to avoid entering in hashChange event when scrolling is not finished yet
  451. clearTimeout(scrollId);
  452. scrollId = setTimeout(function(){
  453. isScrolling = false;
  454. }, 100);
  455. }
  456. if(options.fitSection){
  457. //for the auto adjust of the viewport to fit a whole section
  458. clearTimeout(scrollId2);
  459. scrollId2 = setTimeout(function(){
  460. if(!isMoving){
  461. scrollPage(currentSection);
  462. }
  463. }, 1000);
  464. }
  465. }
  466. }
  467. /**
  468. * Determines whether the active section or slide is scrollable through and scrolling bar
  469. */
  470. function isScrollable(activeSection){
  471. //if there are landscape slides, we check if the scrolling bar is in the current one or not
  472. if(activeSection.find('.fp-slides').length){
  473. scrollable= activeSection.find('.fp-slide.active').find('.fp-scrollable');
  474. }else{
  475. scrollable = activeSection.find('.fp-scrollable');
  476. }
  477. return scrollable;
  478. }
  479. /**
  480. * Determines the way of scrolling up or down:
  481. * by 'automatically' scrolling a section or by using the default and normal scrolling.
  482. */
  483. function scrolling(type, scrollable){
  484. if(type == 'down'){
  485. var check = 'bottom';
  486. var scrollSection = $.fn.fullpage.moveSectionDown;
  487. }else{
  488. var check = 'top';
  489. var scrollSection = $.fn.fullpage.moveSectionUp;
  490. }
  491. if(scrollable.length > 0 ){
  492. //is the scrollbar at the start/end of the scroll?
  493. if(isScrolled(check, scrollable)){
  494. scrollSection();
  495. }else{
  496. return true;
  497. }
  498. }else{
  499. // moved up/down
  500. scrollSection();
  501. }
  502. }
  503. var touchStartY = 0;
  504. var touchStartX = 0;
  505. var touchEndY = 0;
  506. var touchEndX = 0;
  507. /* Detecting touch events
  508. * As we are changing the top property of the page on scrolling, we can not use the traditional way to detect it.
  509. * This way, the touchstart and the touch moves shows an small difference between them which is the
  510. * used one to determine the direction.
  511. */
  512. function touchMoveHandler(event){
  513. var e = event.originalEvent;
  514. // additional: if one of the normalScrollElements isn't within options.normalScrollElementTouchThreshold hops up the DOM chain
  515. if (!checkParentForNormalScrollElement(event.target)) {
  516. if(options.autoScrolling){
  517. //preventing the easing on iOS devices
  518. event.preventDefault();
  519. }
  520. var activeSection = $('.fp-section.active');
  521. var scrollable = isScrollable(activeSection);
  522. if (!isMoving && !slideMoving) { //if theres any #
  523. var touchEvents = getEventsPage(e);
  524. touchEndY = touchEvents['y'];
  525. touchEndX = touchEvents['x'];
  526. //if movement in the X axys is greater than in the Y and the currect section has slides...
  527. if (activeSection.find('.fp-slides').length && Math.abs(touchStartX - touchEndX) > (Math.abs(touchStartY - touchEndY))) {
  528. //is the movement greater than the minimum resistance to scroll?
  529. if (Math.abs(touchStartX - touchEndX) > ($(window).width() / 100 * options.touchSensitivity)) {
  530. if (touchStartX > touchEndX) {
  531. $.fn.fullpage.moveSlideRight(); //next
  532. } else {
  533. $.fn.fullpage.moveSlideLeft(); //prev
  534. }
  535. }
  536. }
  537. //vertical scrolling (only when autoScrolling is enabled)
  538. else if(options.autoScrolling){
  539. //is the movement greater than the minimum resistance to scroll?
  540. if (Math.abs(touchStartY - touchEndY) > ($(window).height() / 100 * options.touchSensitivity)) {
  541. if (touchStartY > touchEndY) {
  542. scrolling('down', scrollable);
  543. } else if (touchEndY > touchStartY) {
  544. scrolling('up', scrollable);
  545. }
  546. }
  547. }
  548. }
  549. }
  550. }
  551. /**
  552. * recursive function to loop up the parent nodes to check if one of them exists in options.normalScrollElements
  553. * Currently works well for iOS - Android might need some testing
  554. * @param {Element} el target element / jquery selector (in subsequent nodes)
  555. * @param {int} hop current hop compared to options.normalScrollElementTouchThreshold
  556. * @return {boolean} true if there is a match to options.normalScrollElements
  557. */
  558. function checkParentForNormalScrollElement (el, hop) {
  559. hop = hop || 0;
  560. var parent = $(el).parent();
  561. if (hop < options.normalScrollElementTouchThreshold &&
  562. parent.is(options.normalScrollElements) ) {
  563. return true;
  564. } else if (hop == options.normalScrollElementTouchThreshold) {
  565. return false;
  566. } else {
  567. return checkParentForNormalScrollElement(parent, ++hop);
  568. }
  569. }
  570. function touchStartHandler(event){
  571. var e = event.originalEvent;
  572. var touchEvents = getEventsPage(e);
  573. touchStartY = touchEvents['y'];
  574. touchStartX = touchEvents['x'];
  575. }
  576. /**
  577. * Detecting mousewheel scrolling
  578. *
  579. * http://blogs.sitepointstatic.com/examples/tech/mouse-wheel/index.html
  580. * http://www.sitepoint.com/html5-javascript-mouse-wheel/
  581. */
  582. function MouseWheelHandler(e) {
  583. if(options.autoScrolling){
  584. // cross-browser wheel delta
  585. e = window.event || e;
  586. var delta = Math.max(-1, Math.min(1,
  587. (e.wheelDelta || -e.deltaY || -e.detail)));
  588. var activeSection = $('.fp-section.active');
  589. var scrollable = isScrollable(activeSection);
  590. if (!isMoving) { //if theres any #
  591. //scrolling down?
  592. if (delta < 0) {
  593. scrolling('down', scrollable);
  594. //scrolling up?
  595. }else {
  596. scrolling('up', scrollable);
  597. }
  598. }
  599. return false;
  600. }
  601. }
  602. function moveSlide(direction){
  603. var activeSection = $('.fp-section.active');
  604. var slides = activeSection.find('.fp-slides');
  605. // more than one slide needed and nothing should be sliding
  606. if (!slides.length || slideMoving) {
  607. return;
  608. }
  609. var currentSlide = slides.find('.fp-slide.active');
  610. var destiny = null;
  611. if(direction === 'prev'){
  612. destiny = currentSlide.prev('.fp-slide');
  613. }else{
  614. destiny = currentSlide.next('.fp-slide');
  615. }
  616. //isn't there a next slide in the secuence?
  617. if(!destiny.length){
  618. //respect loopHorizontal settin
  619. if (!options.loopHorizontal) return;
  620. if(direction === 'prev'){
  621. destiny = currentSlide.siblings(':last');
  622. }else{
  623. destiny = currentSlide.siblings(':first');
  624. }
  625. }
  626. slideMoving = true;
  627. landscapeScroll(slides, destiny);
  628. }
  629. /**
  630. * Maintains the active slides in the viewport
  631. * (Because he `scroll` animation might get lost with some actions, such as when using continuousVertical)
  632. */
  633. function keepSlidesPosition(){
  634. $('.fp-slide.active').each(function(){
  635. silentLandscapeScroll($(this));
  636. });
  637. }
  638. /**
  639. * Scrolls the site to the given element and scrolls to the slide if a callback is given.
  640. */
  641. function scrollPage(element, callback, isMovementUp){
  642. var dest = element.position();
  643. if(typeof dest === "undefined"){ return; } //there's no element to scroll, leaving the function
  644. //local variables
  645. var v = {
  646. element: element,
  647. callback: callback,
  648. isMovementUp: isMovementUp,
  649. dest: dest,
  650. dtop: dest.top,
  651. yMovement: getYmovement(element),
  652. anchorLink: element.data('anchor'),
  653. sectionIndex: element.index('.fp-section'),
  654. activeSlide: element.find('.fp-slide.active'),
  655. activeSection: $('.fp-section.active'),
  656. leavingSection: $('.fp-section.active').index('.fp-section') + 1,
  657. //caching the value of isResizing at the momment the function is called
  658. //because it will be checked later inside a setTimeout and the value might change
  659. localIsResizing: isResizing
  660. };
  661. //quiting when activeSection is the target element
  662. if(v.activeSection.is(element) && !isResizing){ return; }
  663. if(v.activeSlide.length){
  664. var slideAnchorLink = v.activeSlide.data('anchor');
  665. var slideIndex = v.activeSlide.index();
  666. }
  667. // If continuousVertical && we need to wrap around
  668. if (options.autoScrolling && options.continuousVertical && typeof (v.isMovementUp) !== "undefined" &&
  669. ((!v.isMovementUp && v.yMovement == 'up') || // Intending to scroll down but about to go up or
  670. (v.isMovementUp && v.yMovement == 'down'))) { // intending to scroll up but about to go down
  671. v = createInfiniteSections(v);
  672. }
  673. element.addClass('active').siblings().removeClass('active');
  674. //preventing from activating the MouseWheelHandler event
  675. //more than once if the page is scrolling
  676. isMoving = true;
  677. if(typeof v.anchorLink !== 'undefined'){
  678. setURLHash(slideIndex, slideAnchorLink, v.anchorLink);
  679. }
  680. //callback (onLeave) if the site is not just resizing and readjusting the slides
  681. $.isFunction(options.onLeave) && !v.localIsResizing && options.onLeave.call(this, v.leavingSection, (v.sectionIndex + 1), v.yMovement);
  682. performMovement(v);
  683. //flag to avoid callingn `scrollPage()` twice in case of using anchor links
  684. lastScrolledDestiny = v.anchorLink;
  685. //avoid firing it twice (as it does also on scroll)
  686. if(options.autoScrolling){
  687. activateMenuAndNav(v.anchorLink, v.sectionIndex)
  688. }
  689. }
  690. /**
  691. * Performs the movement (by CSS3 or by jQuery)
  692. */
  693. function performMovement(v){
  694. // using CSS3 translate functionality
  695. if (options.css3 && options.autoScrolling) {
  696. var translate3d = 'translate3d(0px, -' + v.dtop + 'px, 0px)';
  697. transformContainer(translate3d, true);
  698. setTimeout(function () {
  699. afterSectionLoads(v);
  700. }, options.scrollingSpeed);
  701. }
  702. // using jQuery animate
  703. else {
  704. var scrollSettings = getScrollSettings(v);
  705. $(scrollSettings.element).animate(
  706. scrollSettings.options
  707. , options.scrollingSpeed, options.easing).promise().done(function () { //only one single callback in case of animating `html, body`
  708. afterSectionLoads(v);
  709. });
  710. }
  711. }
  712. /**
  713. * Gets the scrolling settings depending on the plugin autoScrolling option
  714. */
  715. function getScrollSettings(v){
  716. var scroll = {};
  717. if(options.autoScrolling){
  718. scroll.options = { 'top': -v.dtop};
  719. scroll.element = '.'+wrapperSelector;
  720. }else{
  721. scroll.options = { 'scrollTop': v.dtop};
  722. scroll.element = 'html, body';
  723. }
  724. return scroll;
  725. }
  726. /**
  727. * Adds sections before or after the current one to create the infinite effect.
  728. */
  729. function createInfiniteSections(v){
  730. // Scrolling down
  731. if (!v.isMovementUp) {
  732. // Move all previous sections to after the active section
  733. $(".fp-section.active").after(v.activeSection.prevAll(".fp-section").get().reverse());
  734. }
  735. else { // Scrolling up
  736. // Move all next sections to before the active section
  737. $(".fp-section.active").before(v.activeSection.nextAll(".fp-section"));
  738. }
  739. // Maintain the displayed position (now that we changed the element order)
  740. silentScroll($('.fp-section.active').position().top);
  741. // Maintain the active slides visible in the viewport
  742. keepSlidesPosition();
  743. // save for later the elements that still need to be reordered
  744. v.wrapAroundElements = v.activeSection;
  745. // Recalculate animation variables
  746. v.dest = v.element.position();
  747. v.dtop = v.dest.top;
  748. v.yMovement = getYmovement(v.element);
  749. return v;
  750. }
  751. /**
  752. * Fix section order after continuousVertical changes have been animated
  753. */
  754. function continuousVerticalFixSectionOrder (v) {
  755. // If continuousVertical is in effect (and autoScrolling would also be in effect then),
  756. // finish moving the elements around so the direct navigation will function more simply
  757. if (!v.wrapAroundElements || !v.wrapAroundElements.length) {
  758. return;
  759. }
  760. if (v.isMovementUp) {
  761. $('.fp-section:first').before(v.wrapAroundElements);
  762. }
  763. else {
  764. $('.fp-section:last').after(v.wrapAroundElements);
  765. }
  766. silentScroll($('.fp-section.active').position().top);
  767. // Maintain the active slides visible in the viewport
  768. keepSlidesPosition();
  769. };
  770. /**
  771. * Actions to do once the section is loaded
  772. */
  773. function afterSectionLoads (v){
  774. continuousVerticalFixSectionOrder(v);
  775. //callback (afterLoad) if the site is not just resizing and readjusting the slides
  776. $.isFunction(options.afterLoad) && !v.localIsResizing && options.afterLoad.call(this, v.anchorLink, (v.sectionIndex + 1));
  777. setTimeout(function () {
  778. isMoving = false;
  779. $.isFunction(v.callback) && v.callback.call(this);
  780. }, scrollDelay);
  781. }
  782. /**
  783. * Scrolls to the anchor in the URL when loading the site
  784. */
  785. function scrollToAnchor(){
  786. //getting the anchor link in the URL and deleting the `#`
  787. var value = window.location.hash.replace('#', '').split('/');
  788. var section = value[0];
  789. var slide = value[1];
  790. if(section){ //if theres any #
  791. scrollPageAndSlide(section, slide);
  792. }
  793. }
  794. //detecting any change on the URL to scroll to the given anchor link
  795. //(a way to detect back history button as we play with the hashes on the URL)
  796. $(window).on('hashchange', hashChangeHandler);
  797. function hashChangeHandler(){
  798. if(!isScrolling){
  799. var value = window.location.hash.replace('#', '').split('/');
  800. var section = value[0];
  801. var slide = value[1];
  802. if(section.length){
  803. //when moving to a slide in the first section for the first time (first time to add an anchor to the URL)
  804. var isFirstSlideMove = (typeof lastScrolledDestiny === 'undefined');
  805. var isFirstScrollMove = (typeof lastScrolledDestiny === 'undefined' && typeof slide === 'undefined' && !slideMoving);
  806. /*in order to call scrollpage() only once for each destination at a time
  807. It is called twice for each scroll otherwise, as in case of using anchorlinks `hashChange`
  808. event is fired on every scroll too.*/
  809. if ((section && section !== lastScrolledDestiny) && !isFirstSlideMove || isFirstScrollMove || (!slideMoving && lastScrolledSlide != slide )) {
  810. scrollPageAndSlide(section, slide);
  811. }
  812. }
  813. }
  814. }
  815. /**
  816. * Sliding with arrow keys, both, vertical and horizontal
  817. */
  818. $(document).keydown(function(e) {
  819. //Moving the main page with the keyboard arrows if keyboard scrolling is enabled
  820. if (options.keyboardScrolling && !isMoving) {
  821. switch (e.which) {
  822. //up
  823. case 38:
  824. case 33:
  825. $.fn.fullpage.moveSectionUp();
  826. break;
  827. //down
  828. case 40:
  829. case 34:
  830. $.fn.fullpage.moveSectionDown();
  831. break;
  832. //Home
  833. case 36:
  834. $.fn.fullpage.moveTo(1);
  835. break;
  836. //End
  837. case 35:
  838. $.fn.fullpage.moveTo( $('.fp-section').length );
  839. break;
  840. //left
  841. case 37:
  842. $.fn.fullpage.moveSlideLeft();
  843. break;
  844. //right
  845. case 39:
  846. $.fn.fullpage.moveSlideRight();
  847. break;
  848. default:
  849. return; // exit this handler for other keys
  850. }
  851. }
  852. });
  853. /**
  854. * Scrolls to the section when clicking the navigation bullet
  855. */
  856. $(document).on('click touchstart', '#fp-nav a', function(e){
  857. e.preventDefault();
  858. var index = $(this).parent().index();
  859. scrollPage($('.fp-section').eq(index));
  860. });
  861. /**
  862. * Scrolls the slider to the given slide destination for the given section
  863. */
  864. $(document).on('click touchstart', '.fp-slidesNav a', function(e){
  865. e.preventDefault();
  866. var slides = $(this).closest('.fp-section').find('.fp-slides');
  867. var destiny = slides.find('.fp-slide').eq($(this).closest('li').index());
  868. landscapeScroll(slides, destiny);
  869. });
  870. //navigation tooltips
  871. $(document).on({
  872. mouseenter: function(){
  873. var tooltip = $(this).data('tooltip');
  874. $('<div class="fp-tooltip ' + options.navigationPosition +'">' + tooltip + '</div>').hide().appendTo($(this)).fadeIn(200);
  875. },
  876. mouseleave: function(){
  877. $(this).find('.fp-tooltip').fadeOut(200, function() {
  878. $(this).remove();
  879. });
  880. }
  881. }, '#fp-nav li');
  882. if(options.normalScrollElements){
  883. $(document).on('mouseenter', options.normalScrollElements, function () {
  884. $.fn.fullpage.setMouseWheelScrolling(false);
  885. });
  886. $(document).on('mouseleave', options.normalScrollElements, function(){
  887. $.fn.fullpage.setMouseWheelScrolling(true);
  888. });
  889. }
  890. /**
  891. * Scrolling horizontally when clicking on the slider controls.
  892. */
  893. $('.fp-section').on('click touchstart', '.fp-controlArrow', function() {
  894. if ($(this).hasClass('fp-prev')) {
  895. $.fn.fullpage.moveSlideLeft();
  896. } else {
  897. $.fn.fullpage.moveSlideRight();
  898. }
  899. });
  900. /**
  901. * Scrolls horizontal sliders.
  902. */
  903. function landscapeScroll(slides, destiny){
  904. var destinyPos = destiny.position();
  905. var slidesContainer = slides.find('.fp-slidesContainer').parent();
  906. var slideIndex = destiny.index();
  907. var section = slides.closest('.fp-section');
  908. var sectionIndex = section.index('.fp-section');
  909. var anchorLink = section.data('anchor');
  910. var slidesNav = section.find('.fp-slidesNav');
  911. var slideAnchor = destiny.data('anchor');
  912. //caching the value of isResizing at the momment the function is called
  913. //because it will be checked later inside a setTimeout and the value might change
  914. var localIsResizing = isResizing;
  915. if(options.onSlideLeave){
  916. var prevSlideIndex = section.find('.fp-slide.active').index();
  917. var xMovement = getXmovement(prevSlideIndex, slideIndex);
  918. //if the site is not just resizing and readjusting the slides
  919. if(!localIsResizing && xMovement!=='none'){
  920. $.isFunction( options.onSlideLeave ) && options.onSlideLeave.call( this, anchorLink, (sectionIndex + 1), prevSlideIndex, xMovement);
  921. }
  922. }
  923. destiny.addClass('active').siblings().removeClass('active');
  924. if(typeof slideAnchor === 'undefined'){
  925. slideAnchor = slideIndex;
  926. }
  927. if(!options.loopHorizontal){
  928. //hidding it for the fist slide, showing for the rest
  929. section.find('.fp-controlArrow.fp-prev').toggle(slideIndex!=0);
  930. //hidding it for the last slide, showing for the rest
  931. section.find('.fp-controlArrow.fp-next').toggle(!destiny.is(':last-child'));
  932. }
  933. //only changing the URL if the slides are in the current section (not for resize re-adjusting)
  934. if(section.hasClass('active')){
  935. setURLHash(slideIndex, slideAnchor, anchorLink);
  936. }
  937. var afterSlideLoads = function(){
  938. //if the site is not just resizing and readjusting the slides
  939. if(!localIsResizing){
  940. $.isFunction( options.afterSlideLoad ) && options.afterSlideLoad.call( this, anchorLink, (sectionIndex + 1), slideAnchor, slideIndex);
  941. }
  942. //letting them slide again
  943. slideMoving = false;
  944. };
  945. if(options.css3){
  946. var translate3d = 'translate3d(-' + destinyPos.left + 'px, 0px, 0px)';
  947. addAnimation(slides.find('.fp-slidesContainer'), options.scrollingSpeed>0).css(getTransforms(translate3d));
  948. setTimeout(function(){
  949. afterSlideLoads();
  950. }, options.scrollingSpeed, options.easing);
  951. }else{
  952. slidesContainer.animate({
  953. scrollLeft : destinyPos.left
  954. }, options.scrollingSpeed, options.easing, function() {
  955. afterSlideLoads();
  956. });
  957. }
  958. slidesNav.find('.active').removeClass('active');
  959. slidesNav.find('li').eq(slideIndex).find('a').addClass('active');
  960. }
  961. //when resizing the site, we adjust the heights of the sections, slimScroll...
  962. $(window).resize(resizeHandler);
  963. var resizeId;
  964. function resizeHandler(){
  965. //checking if it needs to get responsive
  966. responsive();
  967. // rebuild immediately on touch devices
  968. if (isTouchDevice) {
  969. //if the keyboard is visible
  970. if ($(document.activeElement).attr('type') !== 'text') {
  971. $.fn.fullpage.reBuild(true);
  972. }
  973. }else{
  974. //in order to call the functions only when the resize is finished
  975. //http://stackoverflow.com/questions/4298612/jquery-how-to-call-resize-event-only-once-its-finished-resizing
  976. clearTimeout(resizeId);
  977. resizeId = setTimeout(function(){
  978. $.fn.fullpage.reBuild(true);
  979. }, 500);
  980. }
  981. }
  982. /**
  983. * Checks if the site needs to get responsive and disables autoScrolling if so.
  984. * A class `fp-responsive` is added to the plugin's container in case the user wants to use it for his own responsive CSS.
  985. */
  986. function responsive(){
  987. if(options.responsive){
  988. var isResponsive = container.hasClass('fp-responsive');
  989. if ($(window).width() < options.responsive ){
  990. if(!isResponsive){
  991. $.fn.fullpage.setAutoScrolling(false);
  992. $('#fp-nav').hide();
  993. container.addClass('fp-responsive');
  994. }
  995. }else if(isResponsive){
  996. $.fn.fullpage.setAutoScrolling(true);
  997. $('#fp-nav').show();
  998. container.removeClass('fp-responsive');
  999. }
  1000. }
  1001. }
  1002. /**
  1003. * Toogles transition animations for the given element
  1004. */
  1005. function addAnimation(element, adding){
  1006. var transition = 'all ' + options.scrollingSpeed + 'ms ' + options.easingcss3;
  1007. if(adding){
  1008. element.removeClass('fp-notransition');
  1009. return element.css({
  1010. '-webkit-transition': transition,
  1011. 'transition': transition
  1012. });
  1013. }
  1014. //removing the animation
  1015. return removeAnimation(element);
  1016. }
  1017. /**
  1018. * Remove transition animations for the given element
  1019. */
  1020. function removeAnimation(element){
  1021. return element.addClass('fp-notransition');
  1022. }
  1023. /**
  1024. * Resizing of the font size depending on the window size as well as some of the images on the site.
  1025. */
  1026. function resizeMe(displayHeight, displayWidth) {
  1027. //Standard dimensions, for which the body font size is correct
  1028. var preferredHeight = 825;
  1029. var preferredWidth = 900;
  1030. if (displayHeight < preferredHeight || displayWidth < preferredWidth) {
  1031. var heightPercentage = (displayHeight * 100) / preferredHeight;
  1032. var widthPercentage = (displayWidth * 100) / preferredWidth;
  1033. var percentage = Math.min(heightPercentage, widthPercentage);
  1034. var newFontSize = percentage.toFixed(2);
  1035. $("body").css("font-size", newFontSize + '%');
  1036. } else {
  1037. $("body").css("font-size", '100%');
  1038. }
  1039. }
  1040. /**
  1041. * Activating the website navigation dots according to the given slide name.
  1042. */
  1043. function activateNavDots(name, sectionIndex){
  1044. if(options.navigation){
  1045. $('#fp-nav').find('.active').removeClass('active');
  1046. if(name){
  1047. $('#fp-nav').find('a[href="#' + name + '"]').addClass('active');
  1048. }else{
  1049. $('#fp-nav').find('li').eq(sectionIndex).find('a').addClass('active');
  1050. }
  1051. }
  1052. }
  1053. /**
  1054. * Activating the website main menu elements according to the given slide name.
  1055. */
  1056. function activateMenuElement(name){
  1057. if(options.menu){
  1058. $(options.menu).find('.active').removeClass('active');
  1059. $(options.menu).find('[data-menuanchor="'+name+'"]').addClass('active');
  1060. }
  1061. }
  1062. function activateMenuAndNav(anchor, index){
  1063. activateMenuElement(anchor);
  1064. activateNavDots(anchor, index);
  1065. }
  1066. /**
  1067. * Return a boolean depending on whether the scrollable element is at the end or at the start of the scrolling
  1068. * depending on the given type.
  1069. */
  1070. function isScrolled(type, scrollable){
  1071. if(type === 'top'){
  1072. return !scrollable.scrollTop();
  1073. }else if(type === 'bottom'){
  1074. return scrollable.scrollTop() + 1 + scrollable.innerHeight() >= scrollable[0].scrollHeight;
  1075. }
  1076. }
  1077. /**
  1078. * Retuns `up` or `down` depending on the scrolling movement to reach its destination
  1079. * from the current section.
  1080. */
  1081. function getYmovement(destiny){
  1082. var fromIndex = $('.fp-section.active').index('.fp-section');
  1083. var toIndex = destiny.index('.fp-section');
  1084. if(fromIndex > toIndex){
  1085. return 'up';
  1086. }
  1087. return 'down';
  1088. }
  1089. /**
  1090. * Retuns `right` or `left` depending on the scrolling movement to reach its destination
  1091. * from the current slide.
  1092. */
  1093. function getXmovement(fromIndex, toIndex){
  1094. if( fromIndex == toIndex){
  1095. return 'none'
  1096. }
  1097. if(fromIndex > toIndex){
  1098. return 'left';
  1099. }
  1100. return 'right';
  1101. }
  1102. function createSlimScrolling(element){
  1103. //needed to make `scrollHeight` work under Opera 12
  1104. element.css('overflow', 'hidden');
  1105. //in case element is a slide
  1106. var section = element.closest('.fp-section');
  1107. var scrollable = element.find('.fp-scrollable');
  1108. //if there was scroll, the contentHeight will be the one in the scrollable section
  1109. if(scrollable.length){
  1110. var contentHeight = scrollable.get(0).scrollHeight;
  1111. }else{
  1112. var contentHeight = element.get(0).scrollHeight;
  1113. if(options.verticalCentered){
  1114. contentHeight = element.find('.fp-tableCell').get(0).scrollHeight;
  1115. }
  1116. }
  1117. var scrollHeight = windowsHeight - parseInt(section.css('padding-bottom')) - parseInt(section.css('padding-top'));
  1118. //needs scroll?
  1119. if ( contentHeight > scrollHeight) {
  1120. //was there already an scroll ? Updating it
  1121. if(scrollable.length){
  1122. scrollable.css('height', scrollHeight + 'px').parent().css('height', scrollHeight + 'px');
  1123. }
  1124. //creating the scrolling
  1125. else{
  1126. if(options.verticalCentered){
  1127. element.find('.fp-tableCell').wrapInner('<div class="fp-scrollable" />');
  1128. }else{
  1129. element.wrapInner('<div class="fp-scrollable" />');
  1130. }
  1131. element.find('.fp-scrollable').slimScroll({
  1132. allowPageScroll: true,
  1133. height: scrollHeight + 'px',
  1134. size: '10px',
  1135. alwaysVisible: true
  1136. });
  1137. }
  1138. }
  1139. //removing the scrolling when it is not necessary anymore
  1140. else{
  1141. removeSlimScroll(element);
  1142. }
  1143. //undo
  1144. element.css('overflow', '');
  1145. }
  1146. function removeSlimScroll(element){
  1147. element.find('.fp-scrollable').children().first().unwrap().unwrap();
  1148. element.find('.slimScrollBar').remove();
  1149. element.find('.slimScrollRail').remove();
  1150. }
  1151. function addTableClass(element){
  1152. element.addClass('fp-table').wrapInner('<div class="fp-tableCell" style="height:' + getTableHeight(element) + 'px;" />');
  1153. }
  1154. function getTableHeight(element){
  1155. var sectionHeight = windowsHeight;
  1156. if(options.paddingTop || options.paddingBottom){
  1157. var section = element;
  1158. if(!section.hasClass('fp-section')){
  1159. section = element.closest('.fp-section');
  1160. }
  1161. var paddings = parseInt(section.css('padding-top')) + parseInt(section.css('padding-bottom'));
  1162. sectionHeight = (windowsHeight - paddings);
  1163. }
  1164. return sectionHeight;
  1165. }
  1166. /**
  1167. * Adds a css3 transform property to the container class with or without animation depending on the animated param.
  1168. */
  1169. function transformContainer(translate3d, animated){
  1170. addAnimation(container, animated);
  1171. container.css(getTransforms(translate3d));
  1172. }
  1173. /**
  1174. * Scrolls to the given section and slide
  1175. */
  1176. function scrollPageAndSlide(destiny, slide){
  1177. if (typeof slide === 'undefined') {
  1178. slide = 0;
  1179. }
  1180. if(isNaN(destiny)){
  1181. var section = $('[data-anchor="'+destiny+'"]');
  1182. }else{
  1183. var section = $('.fp-section').eq( (destiny -1) );
  1184. }
  1185. //we need to scroll to the section and then to the slide
  1186. if (destiny !== lastScrolledDestiny && !section.hasClass('active')){
  1187. scrollPage(section, function(){
  1188. scrollSlider(section, slide)
  1189. });
  1190. }
  1191. //if we were already in the section
  1192. else{
  1193. scrollSlider(section, slide);
  1194. }
  1195. }
  1196. /**
  1197. * Scrolls the slider to the given slide destination for the given section
  1198. */
  1199. function scrollSlider(section, slide){
  1200. if(typeof slide != 'undefined'){
  1201. var slides = section.find('.fp-slides');
  1202. var destiny = slides.find('[data-anchor="'+slide+'"]');
  1203. if(!destiny.length){
  1204. destiny = slides.find('.fp-slide').eq(slide);
  1205. }
  1206. if(destiny.length){
  1207. landscapeScroll(slides, destiny);
  1208. }
  1209. }
  1210. }
  1211. /**
  1212. * Creates a landscape navigation bar with dots for horizontal sliders.
  1213. */
  1214. function addSlidesNavigation(section, numSlides){
  1215. section.append('<div class="fp-slidesNav"><ul></ul></div>');
  1216. var nav = section.find('.fp-slidesNav');
  1217. //top or bottom
  1218. nav.addClass(options.slidesNavPosition);
  1219. for(var i=0; i< numSlides; i++){
  1220. nav.find('ul').append('<li><a href="#"><span></span></a></li>');
  1221. }
  1222. //centering it
  1223. nav.css('margin-left', '-' + (nav.width()/2) + 'px');
  1224. nav.find('li').first().find('a').addClass('active');
  1225. }
  1226. /**
  1227. * Sets the URL hash for a section with slides
  1228. */
  1229. function setURLHash(slideIndex, slideAnchor, anchorLink){
  1230. var sectionHash = '';
  1231. if(options.anchors.length){
  1232. //isn't it the first slide?
  1233. if(slideIndex){
  1234. if(typeof anchorLink !== 'undefined'){
  1235. sectionHash = anchorLink;
  1236. }
  1237. //slide without anchor link? We take the index instead.
  1238. if(typeof slideAnchor === 'undefined'){
  1239. slideAnchor = slideIndex;
  1240. }
  1241. lastScrolledSlide = slideAnchor;
  1242. location.hash = sectionHash + '/' + slideAnchor;
  1243. //first slide won't have slide anchor, just the section one
  1244. }else if(typeof slideIndex !== 'undefined'){
  1245. lastScrolledSlide = slideAnchor;
  1246. location.hash = anchorLink;
  1247. }
  1248. //section without slides
  1249. else{
  1250. location.hash = anchorLink;
  1251. }
  1252. }
  1253. }
  1254. /**
  1255. * Checks for translate3d support
  1256. * @return boolean
  1257. * http://stackoverflow.com/questions/5661671/detecting-transform-translate3d-support
  1258. */
  1259. function support3d() {
  1260. var el = document.createElement('p'),
  1261. has3d,
  1262. transforms = {
  1263. 'webkitTransform':'-webkit-transform',
  1264. 'OTransform':'-o-transform',
  1265. 'msTransform':'-ms-transform',
  1266. 'MozTransform':'-moz-transform',
  1267. 'transform':'transform'
  1268. };
  1269. // Add it to the body to get the computed style.
  1270. document.body.insertBefore(el, null);
  1271. for (var t in transforms) {
  1272. if (el.style[t] !== undefined) {
  1273. el.style[t] = "translate3d(1px,1px,1px)";
  1274. has3d = window.getComputedStyle(el).getPropertyValue(transforms[t]);
  1275. }
  1276. }
  1277. document.body.removeChild(el);
  1278. return (has3d !== undefined && has3d.length > 0 && has3d !== "none");
  1279. }
  1280. /**
  1281. * Removes the auto scrolling action fired by the mouse wheel and tackpad.
  1282. * After this function is called, the mousewheel and trackpad movements won't scroll through sections.
  1283. */
  1284. function removeMouseWheelHandler(){
  1285. if (document.addEventListener) {
  1286. document.removeEventListener('mousewheel', MouseWheelHandler, false); //IE9, Chrome, Safari, Oper
  1287. document.removeEventListener('wheel', MouseWheelHandler, false); //Firefox
  1288. } else {
  1289. document.detachEvent("onmousewheel", MouseWheelHandler); //IE 6/7/8
  1290. }
  1291. }
  1292. /**
  1293. * Adds the auto scrolling action for the mouse wheel and tackpad.
  1294. * After this function is called, the mousewheel and trackpad movements will scroll through sections
  1295. */
  1296. function addMouseWheelHandler(){
  1297. if (document.addEventListener) {
  1298. document.addEventListener("mousewheel", MouseWheelHandler, false); //IE9, Chrome, Safari, Oper
  1299. document.addEventListener("wheel", MouseWheelHandler, false); //Firefox
  1300. } else {
  1301. document.attachEvent("onmousewheel", MouseWheelHandler); //IE 6/7/8
  1302. }
  1303. }
  1304. /**
  1305. * Adds the possibility to auto scroll through sections on touch devices.
  1306. */
  1307. function addTouchHandler(){
  1308. if(isTouchDevice || isTouch){
  1309. //Microsoft pointers
  1310. MSPointer = getMSPointer();
  1311. $(document).off('touchstart ' + MSPointer.down).on('touchstart ' + MSPointer.down, touchStartHandler);
  1312. $(document).off('touchmove ' + MSPointer.move).on('touchmove ' + MSPointer.move, touchMoveHandler);
  1313. }
  1314. }
  1315. /**
  1316. * Removes the auto scrolling for touch devices.
  1317. */
  1318. function removeTouchHandler(){
  1319. if(isTouchDevice || isTouch){
  1320. //Microsoft pointers
  1321. MSPointer = getMSPointer();
  1322. $(document).off('touchstart ' + MSPointer.down);
  1323. $(document).off('touchmove ' + MSPointer.move);
  1324. }
  1325. }
  1326. /*
  1327. * Returns and object with Microsoft pointers (for IE<11 and for IE >= 11)
  1328. * http://msdn.microsoft.com/en-us/library/ie/dn304886(v=vs.85).aspx
  1329. */
  1330. function getMSPointer(){
  1331. var pointer;
  1332. //IE >= 11
  1333. if(window.PointerEvent){
  1334. pointer = { down: "pointerdown", move: "pointermove"};
  1335. }
  1336. //IE < 11
  1337. else{
  1338. pointer = { down: "MSPointerDown", move: "MSPointerMove"};
  1339. }
  1340. return pointer;
  1341. }
  1342. /**
  1343. * Gets the pageX and pageY properties depending on the browser.
  1344. * https://github.com/alvarotrigo/fullPage.js/issues/194#issuecomment-34069854
  1345. */
  1346. function getEventsPage(e){
  1347. var events = new Array();
  1348. if (window.navigator.msPointerEnabled){
  1349. events['y'] = e.pageY;
  1350. events['x'] = e.pageX;
  1351. }else{
  1352. events['y'] = e.touches[0].pageY;
  1353. events['x'] = e.touches[0].pageX;
  1354. }
  1355. return events;
  1356. }
  1357. function silentLandscapeScroll(activeSlide){
  1358. var prevScrollingSpeepd = options.scrollingSpeed;
  1359. $.fn.fullpage.setScrollingSpeed (0);
  1360. landscapeScroll(activeSlide.closest('.fp-slides'), activeSlide);
  1361. $.fn.fullpage.setScrollingSpeed(prevScrollingSpeepd);
  1362. }
  1363. function silentScroll(top){
  1364. if (options.css3) {
  1365. var translate3d = 'translate3d(0px, -' + top + 'px, 0px)';
  1366. transformContainer(translate3d, false);
  1367. }
  1368. else {
  1369. container.css("top", -top);
  1370. }
  1371. }
  1372. function getTransforms(translate3d){
  1373. return {
  1374. '-webkit-transform': translate3d,
  1375. '-moz-transform': translate3d,
  1376. '-ms-transform':translate3d,
  1377. 'transform': translate3d
  1378. };
  1379. }
  1380. /*
  1381. * Destroys fullpage.js plugin events and optinally its html markup and styles
  1382. */
  1383. $.fn.fullpage.destroy = function(all){
  1384. $.fn.fullpage.setAutoScrolling(false);
  1385. $.fn.fullpage.setAllowScrolling(false);
  1386. $.fn.fullpage.setKeyboardScrolling(false);
  1387. $(window)
  1388. .off('scroll', scrollHandler)
  1389. .off('hashchange', hashChangeHandler)
  1390. .off('resize', resizeHandler);
  1391. $(document)
  1392. .off('click', '#fp-nav a')
  1393. .off('mouseenter', '#fp-nav li')
  1394. .off('mouseleave', '#fp-nav li')
  1395. .off('click', '.fp-slidesNav a')
  1396. .off('mouseover', options.normalScrollElements)
  1397. .off('mouseout', options.normalScrollElements);
  1398. $('.fp-section')
  1399. .off('click', '.fp-controlArrow');
  1400. //lets make a mess!
  1401. if(all){
  1402. destroyStructure();
  1403. }
  1404. };
  1405. /*
  1406. * Removes inline styles added by fullpage.js
  1407. */
  1408. function destroyStructure(){
  1409. //reseting the `top` or `translate` properties to 0
  1410. silentScroll(0);
  1411. $('#fp-nav, .fp-slidesNav, .fp-controlArrow').remove();
  1412. //removing inline styles
  1413. $('.fp-section').css( {
  1414. 'height': '',
  1415. 'background-color' : '',
  1416. 'padding': ''
  1417. });
  1418. $('.fp-slide').css( {
  1419. 'width': ''
  1420. });
  1421. container.css({
  1422. 'height': '',
  1423. 'position': '',
  1424. '-ms-touch-action': '',
  1425. 'touch-action': ''
  1426. });
  1427. //removing added classes
  1428. $('.fp-section, .fp-slide').each(function(){
  1429. removeSlimScroll($(this));
  1430. $(this).removeClass('fp-table active');
  1431. })
  1432. removeAnimation(container);
  1433. removeAnimation(container.find('.fp-easing'));
  1434. //Unwrapping content
  1435. container.find('.fp-tableCell, .fp-slidesContainer, .fp-slides').each(function(){
  1436. //unwrap not being use in case there's no child element inside and its just text
  1437. $(this).replaceWith(this.childNodes);
  1438. });
  1439. //scrolling the page to the top with no animation
  1440. $('html, body').scrollTop(0);
  1441. }
  1442. };
  1443. })(jQuery);