1/*! 2* Customized version of iScroll.js 0.0.5 3* It fixes bugs affecting its integration with fullpage.js 4*/ 5/*! iScroll v5.2.0 ~ (c) 2008-2016 Matteo Spinelli ~ http://cubiq.org/license */ 6(function (window, document, Math) { 7var rAF = window.requestAnimationFrame || 8 window.webkitRequestAnimationFrame || 9 window.mozRequestAnimationFrame || 10 window.oRequestAnimationFrame || 11 window.msRequestAnimationFrame || 12 function (callback) { window.setTimeout(callback, 1000 / 60); }; 13 14var utils = (function () { 15 var me = {}; 16 17 var _elementStyle = document.createElement('div').style; 18 var _vendor = (function () { 19 var vendors = ['t', 'webkitT', 'MozT', 'msT', 'OT'], 20 transform, 21 i = 0, 22 l = vendors.length; 23 24 for ( ; i < l; i++ ) { 25 transform = vendors[i] + 'ransform'; 26 if ( transform in _elementStyle ) return vendors[i].substr(0, vendors[i].length-1); 27 } 28 29 return false; 30 })(); 31 32 function _prefixStyle (style) { 33 if ( _vendor === false ) return false; 34 if ( _vendor === '' ) return style; 35 return _vendor + style.charAt(0).toUpperCase() + style.substr(1); 36 } 37 38 me.getTime = Date.now || function getTime () { return new Date().getTime(); }; 39 40 me.extend = function (target, obj) { 41 for ( var i in obj ) { 42 target[i] = obj[i]; 43 } 44 }; 45 46 me.addEvent = function (el, type, fn, capture) { 47 el.addEventListener(type, fn, !!capture); 48 }; 49 50 me.removeEvent = function (el, type, fn, capture) { 51 el.removeEventListener(type, fn, !!capture); 52 }; 53 54 me.prefixPointerEvent = function (pointerEvent) { 55 return window.MSPointerEvent ? 56 'MSPointer' + pointerEvent.charAt(7).toUpperCase() + pointerEvent.substr(8): 57 pointerEvent; 58 }; 59 60 me.momentum = function (current, start, time, lowerMargin, wrapperSize, deceleration) { 61 var distance = current - start, 62 speed = Math.abs(distance) / time, 63 destination, 64 duration; 65 66 deceleration = deceleration === undefined ? 0.0006 : deceleration; 67 68 destination = current + ( speed * speed ) / ( 2 * deceleration ) * ( distance < 0 ? -1 : 1 ); 69 duration = speed / deceleration; 70 71 if ( destination < lowerMargin ) { 72 destination = wrapperSize ? lowerMargin - ( wrapperSize / 2.5 * ( speed / 8 ) ) : lowerMargin; 73 distance = Math.abs(destination - current); 74 duration = distance / speed; 75 } else if ( destination > 0 ) { 76 destination = wrapperSize ? wrapperSize / 2.5 * ( speed / 8 ) : 0; 77 distance = Math.abs(current) + destination; 78 duration = distance / speed; 79 } 80 81 return { 82 destination: Math.round(destination), 83 duration: duration 84 }; 85 }; 86 87 var _transform = _prefixStyle('transform'); 88 89 me.extend(me, { 90 hasTransform: _transform !== false, 91 hasPerspective: _prefixStyle('perspective') in _elementStyle, 92 hasTouch: 'ontouchstart' in window, 93 hasPointer: !!(window.PointerEvent || window.MSPointerEvent), // IE10 is prefixed 94 hasTransition: _prefixStyle('transition') in _elementStyle 95 }); 96 97 /* 98 This should find all Android browsers lower than build 535.19 (both stock browser and webview) 99 - galaxy S2 is ok 100 - 2.3.6 : `AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1` 101 - 4.0.4 : `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30` 102 - galaxy S3 is badAndroid (stock brower, webview) 103 `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30` 104 - galaxy S4 is badAndroid (stock brower, webview) 105 `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30` 106 - galaxy S5 is OK 107 `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)` 108 - galaxy S6 is OK 109 `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)` 110 */ 111 me.isBadAndroid = (function() { 112 var appVersion = window.navigator.appVersion; 113 // Android browser is not a chrome browser. 114 if (/Android/.test(appVersion) && !(/Chrome\/\d/.test(appVersion))) { 115 var safariVersion = appVersion.match(/Safari\/(\d+.\d)/); 116 if(safariVersion && typeof safariVersion === "object" && safariVersion.length >= 2) { 117 return parseFloat(safariVersion[1]) < 535.19; 118 } else { 119 return true; 120 } 121 } else { 122 return false;
123 } 124 })(); 125 126 me.extend(me.style = {}, { 127 transform: _transform, 128 transitionTimingFunction: _prefixStyle('transitionTimingFunction'), 129 transitionDuration: _prefixStyle('transitionDuration'), 130 transitionDelay: _prefixStyle('transitionDelay'), 131 transformOrigin: _prefixStyle('transformOrigin') 132 }); 133 134 me.hasClass = function (e, c) { 135 var re = new RegExp("(^|\\s)" + c + "(\\s|$)"); 136 return re.test(e.className); 137 }; 138 139 me.addClass = function (e, c) { 140 if ( me.hasClass(e, c) ) { 141 return; 142 } 143 144 var newclass = e.className.split(' '); 145 newclass.push(c); 146 e.className = newclass.join(' '); 147 }; 148 149 me.removeClass = function (e, c) { 150 if ( !me.hasClass(e, c) ) { 151 return; 152 } 153 154 var re = new RegExp("(^|\\s)" + c + "(\\s|$)", 'g'); 155 e.className = e.className.replace(re, ' '); 156 }; 157 158 me.offset = function (el) { 159 var left = -el.offsetLeft, 160 top = -el.offsetTop; 161 162 // jshint -W084 163 while (el = el.offsetParent) { 164 left -= el.offsetLeft; 165 top -= el.offsetTop; 166 } 167 // jshint +W084 168 169 return { 170 left: left, 171 top: top 172 }; 173 }; 174 175 me.preventDefaultException = function (el, exceptions) { 176 for ( var i in exceptions ) { 177 if ( exceptions[i].test(el[i]) ) { 178 return true; 179 } 180 } 181 182 return false; 183 }; 184 185 me.extend(me.eventType = {}, { 186 touchstart: 1, 187 touchmove: 1, 188 touchend: 1, 189 190 mousedown: 2, 191 mousemove: 2, 192 mouseup: 2, 193 194 pointerdown: 3, 195 pointermove: 3, 196 pointerup: 3, 197 198 MSPointerDown: 3, 199 MSPointerMove: 3, 200 MSPointerUp: 3 201 }); 202 203 me.extend(me.ease = {}, { 204 quadratic: { 205 style: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)', 206 fn: function (k) { 207 return k * ( 2 - k ); 208 } 209 }, 210 circular: { 211 style: 'cubic-bezier(0.1, 0.57, 0.1, 1)', // Not properly "circular" but this looks better, it should be (0.075, 0.82, 0.165, 1) 212 fn: function (k) { 213 return Math.sqrt( 1 - ( --k * k ) ); 214 } 215 }, 216 back: { 217 style: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)', 218 fn: function (k) { 219 var b = 4; 220 return ( k = k - 1 ) * k * ( ( b + 1 ) * k + b ) + 1; 221 } 222 }, 223 bounce: { 224 style: '', 225 fn: function (k) { 226 if ( ( k /= 1 ) < ( 1 / 2.75 ) ) { 227 return 7.5625 * k * k; 228 } else if ( k < ( 2 / 2.75 ) ) { 229 return 7.5625 * ( k -= ( 1.5 / 2.75 ) ) * k + 0.75; 230 } else if ( k < ( 2.5 / 2.75 ) ) { 231 return 7.5625 * ( k -= ( 2.25 / 2.75 ) ) * k + 0.9375; 232 } else { 233 return 7.5625 * ( k -= ( 2.625 / 2.75 ) ) * k + 0.984375; 234 } 235 } 236 }, 237 elastic: { 238 style: '', 239 fn: function (k) { 240 var f = 0.22, 241 e = 0.4; 242 243 if ( k === 0 ) { return 0; } 244 if ( k == 1 ) { return 1; } 245 246 return ( e * Math.pow( 2, - 10 * k ) * Math.sin( ( k - f / 4 ) * ( 2 * Math.PI ) / f ) + 1 ); 247 } 248 } 249 }); 250 251 me.tap = function (e, eventName) { 252 var ev = document.createEvent('Event'); 253 ev.initEvent(eventName, true, true); 254 ev.pageX = e.pageX; 255 ev.pageY = e.pageY; 256 e.target.dispatchEvent(ev); 257 }; 258 259 me.click = function (e) { 260 var target = e.target, 261 ev; 262 263 if ( !(/(SELECT|INPUT|TEXTAREA)/i).test(target.tagName) ) { 264 // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/initMouseEvent 265 // initMouseEvent is deprecated. 266 ev = document.createEvent(window.MouseEvent ? 'MouseEvents' : 'Event'); 267 ev.initEvent('click', true, true); 268 ev.view = e.view || window; 269 ev.detail = 1; 270 ev.screenX = target.screenX || 0; 271 ev.screenY = target.screenY || 0; 272 ev.clientX = target.clientX || 0; 273 ev.clientY = target.clientY || 0; 274 ev.ctrlKey = !!e.ctrlKey; 275 ev.altKey = !!e.altKey; 276 ev.shiftKey = !!e.shiftKey; 277 ev.metaKey = !!e.metaKey; 278 ev.button = 0; 279 ev.relatedTarget = null; 280 ev._constructed = true; 281 target.dispatchEvent(ev); 282 } 283 }; 284 285 return me; 286})(); 287function IScroll (el, options) { 288 this.wrapper = typeof el == 'string' ? document.querySelector(el) : el; 289 this.scroller = this.wrapper.children[0]; 290 this.scrollerStyle = this.scroller.style; // cache style for better performance 291 292 this.options = { 293 294 resizeScrollbars: true, 295 296 mouseWheelSpeed: 20, 297 298 snapThreshold: 0.334, 299 300// INSERT POINT: OPTIONS 301 disablePointer : !utils.hasPointer, 302 disableTouch : utils.hasPointer || !utils.hasTouch, 303 disableMouse : utils.hasPointer || utils.hasTouch, 304 startX: 0, 305 startY: 0, 306 scrollY: true, 307 directionLockThreshold: 5, 308 momentum: true, 309 310 bounce: true, 311 bounceTime: 600, 312 bounceEasing: '', 313 314 preventDefault: true, 315 preventDefaultException: { tagName: /^(INPUT|TEXTAREA|BUTTON|
315SELECT|LABEL)$/ }, 316 317 HWCompositing: true, 318 useTransition: true, 319 useTransform: true, 320 bindToWrapper: typeof window.onmousedown === "undefined" 321 }; 322 323 for ( var i in options ) { 324 this.options[i] = options[i]; 325 } 326 327 // Normalize options 328 this.translateZ = this.options.HWCompositing && utils.hasPerspective ? ' translateZ(0)' : ''; 329 330 this.options.useTransition = utils.hasTransition && this.options.useTransition; 331 this.options.useTransform = utils.hasTransform && this.options.useTransform; 332 333 this.options.eventPassthrough = this.options.eventPassthrough === true ? 'vertical' : this.options.eventPassthrough; 334 this.options.preventDefault = !this.options.eventPassthrough && this.options.preventDefault; 335 336 // If you want eventPassthrough I have to lock one of the axes 337 this.options.scrollY = this.options.eventPassthrough == 'vertical' ? false : this.options.scrollY; 338 this.options.scrollX = this.options.eventPassthrough == 'horizontal' ? false : this.options.scrollX; 339 340 // With eventPassthrough we also need lockDirection mechanism 341 this.options.freeScroll = this.options.freeScroll && !this.options.eventPassthrough; 342 this.options.directionLockThreshold = this.options.eventPassthrough ? 0 : this.options.directionLockThreshold; 343 344 this.options.bounceEasing = typeof this.options.bounceEasing == 'string' ? utils.ease[this.options.bounceEasing] || utils.ease.circular : this.options.bounceEasing; 345 346 this.options.resizePolling = this.options.resizePolling === undefined ? 60 : this.options.resizePolling; 347 348 if ( this.options.tap === true ) { 349 this.options.tap = 'tap'; 350 } 351 352 // https://github.com/cubiq/iscroll/issues/1029 353 if (!this.options.useTransition && !this.options.useTransform) { 354 if(!(/relative|absolute/i).test(this.scrollerStyle.position)) { 355 this.scrollerStyle.position = "relative"; 356 } 357 } 358 359 if ( this.options.shrinkScrollbars == 'scale' ) { 360 this.options.useTransition = false; 361 } 362 363 this.options.invertWheelDirection = this.options.invertWheelDirection ? -1 : 1; 364 365// INSERT POINT: NORMALIZATION 366 367 // Some defaults 368 this.x = 0; 369 this.y = 0; 370 this.directionX = 0; 371 this.directionY = 0; 372 this._events = {}; 373 374// INSERT POINT: DEFAULTS 375 376 this._init(); 377 this.refresh(); 378 379 this.scrollTo(this.options.startX, this.options.startY); 380 this.enable(); 381} 382 383IScroll.prototype = { 384 version: '5.2.0', 385 386 _init: function () { 387 this._initEvents(); 388 389 if ( this.options.scrollbars || this.options.indicators ) { 390 this._initIndicators(); 391 } 392 393 if ( this.options.mouseWheel ) { 394 this._initWheel(); 395 } 396 397 if ( this.options.snap ) { 398 this._initSnap(); 399 } 400 401 if ( this.options.keyBindings ) { 402 this._initKeys(); 403 } 404 405// INSERT POINT: _init 406 407 }, 408 409 destroy: function () { 410 this._initEvents(true); 411 clearTimeout(this.resizeTimeout); 412 this.resizeTimeout = null; 413 this._execEvent('destroy'); 414 }, 415 416 _transitionEnd: function (e) { 417 if ( e.target != this.scroller || !this.isInTransition ) { 418 return; 419 } 420 421 this._transitionTime(); 422 if ( !this.resetPosition(this.options.bounceTime) ) { 423 this.isInTransition = false; 424 this._execEvent('scrollEnd'); 425 } 426 }, 427 428 _start: function (e) { 429 // React to left mouse button only 430 if ( utils.eventType[e.type] != 1 ) { 431 // for button property 432 // http://unixpapa.com/js/mouse.html 433 var button; 434 if (!e.which) { 435 /* IE case */ 436 button = (e.button < 2) ? 0 : 437 ((e.button == 4) ? 1 : 2); 438 } else { 439 /* All others */ 440 button = e.button; 441 } 442 if ( button !== 0 ) { 443 return; 444 } 445 } 446 447 if ( !this.enabled || (this.initiated && utils.eventType[e.type] !== this.initiated) ) { 448 return; 449 } 450 451 if ( this.options.preventDefault && !utils.isBadAndroid && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) { 452 e.preventDefault(); 453 } 454 455 var point = e.touches ? e.touches[0] : e, 456 pos; 457 458 this.initiated = utils.eventType[e.type]; 459 this.moved = false;
460 this.distX = 0; 461 this.distY = 0; 462 this.directionX = 0; 463 this.directionY = 0; 464 this.directionLocked = 0; 465 466 this.startTime = utils.getTime(); 467 468 if ( this.options.useTransition && this.isInTransition ) { 469 this._transitionTime(); 470 this.isInTransition = false; 471 pos = this.getComputedPosition(); 472 this._translate(Math.round(pos.x), Math.round(pos.y)); 473 this._execEvent('scrollEnd'); 474 } else if ( !this.options.useTransition && this.isAnimating ) { 475 this.isAnimating = false; 476 this._execEvent('scrollEnd'); 477 } 478 479 this.startX = this.x; 480 this.startY = this.y; 481 this.absStartX = this.x; 482 this.absStartY = this.y; 483 this.pointX = point.pageX; 484 this.pointY = point.pageY; 485 486 this._execEvent('beforeScrollStart'); 487 }, 488 489 _move: function (e) { 490 if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) { 491 return; 492 } 493 494 if ( this.options.preventDefault ) { // increases performance on Android? TODO: check! 495 e.preventDefault(); 496 } 497 498 var point = e.touches ? e.touches[0] : e, 499 deltaX = point.pageX - this.pointX, 500 deltaY = point.pageY - this.pointY, 501 timestamp = utils.getTime(), 502 newX, newY, 503 absDistX, absDistY; 504 505 this.pointX = point.pageX; 506 this.pointY = point.pageY; 507 508 this.distX += deltaX; 509 this.distY += deltaY; 510 absDistX = Math.abs(this.distX); 511 absDistY = Math.abs(this.distY); 512 513 // We need to move at least 10 pixels for the scrolling to initiate 514 if ( timestamp - this.endTime > 300 && (absDistX < 10 && absDistY < 10) ) { 515 return; 516 } 517 518 // If you are scrolling in one direction lock the other 519 if ( !this.directionLocked && !this.options.freeScroll ) { 520 if ( absDistX > absDistY + this.options.directionLockThreshold ) { 521 this.directionLocked = 'h'; // lock horizontally 522 } else if ( absDistY >= absDistX + this.options.directionLockThreshold ) { 523 this.directionLocked = 'v'; // lock vertically 524 } else { 525 this.directionLocked = 'n'; // no lock 526 } 527 } 528 529 if ( this.directionLocked == 'h' ) { 530 if ( this.options.eventPassthrough == 'vertical' ) { 531 e.preventDefault(); 532 } else if ( this.options.eventPassthrough == 'horizontal' ) { 533 this.initiated = false; 534 return; 535 } 536 537 deltaY = 0; 538 } else if ( this.directionLocked == 'v' ) { 539 if ( this.options.eventPassthrough == 'horizontal' ) { 540 e.preventDefault(); 541 } else if ( this.options.eventPassthrough == 'vertical' ) { 542 this.initiated = false; 543 return; 544 } 545 546 deltaX = 0; 547 } 548 549 deltaX = this.hasHorizontalScroll ? deltaX : 0; 550 deltaY = this.hasVerticalScroll ? deltaY : 0; 551 552 newX = this.x + deltaX; 553 newY = this.y + deltaY; 554 555 // Slow down if outside of the boundaries 556 if ( newX > 0 || newX < this.maxScrollX ) { 557 newX = this.options.bounce ? this.x + deltaX / 3 : newX > 0 ? 0 : this.maxScrollX; 558 } 559 if ( newY > 0 || newY < this.maxScrollY ) { 560 newY = this.options.bounce ? this.y + deltaY / 3 : newY > 0 ? 0 : this.maxScrollY; 561 } 562 563 this.directionX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0; 564 this.directionY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0; 565 566 if ( !this.moved ) { 567 this._execEvent('scrollStart'); 568 } 569 570 this.moved = true; 571 572 this._translate(newX, newY); 573 574/* REPLACE START: _move */ 575 576 if ( timestamp - this.startTime > 300 ) { 577 this.startTime = timestamp; 578 this.startX = this.x; 579 this.startY = this.y; 580 } 581 582/* REPLACE END: _move */ 583 584 }, 585 586 _end: function (e) { 587 if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) { 588 return; 589 } 590 591 if ( this.options.preventDefault && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) { 592 e.preventDefault(); 593 } 594 595 var point = e.changedTouches ? e.changedTouches[0] : e, 596 momentumX, 597 momentumY, 598 duration = utils.getTime() - this.startTime, 599 newX = Math.round(this.x), 600 newY = Math.round(this.y), 601 distanceX = Math.abs(newX - this.startX), 602 distanceY = Math.abs(newY - this.startY), 603 time = 0, 604 easing = ''; 605 606 this.isInTransition = 0; 607 this.initiated = 0; 608 this.endTime = utils.getTime(); 609 610 // reset if we are outside of the boundaries 611 if ( this.resetPosition(this.options.bounceTime) ) { 612 return; 613 } 614 615 this.scrollTo(newX, newY); // ensures that the last position is rounded 616 617 // we scrolled less than 10 pixels 618 if ( !this.moved ) { 619 if ( this.options.tap ) { 620 utils.tap(e, this.options.tap); 621 } 622 623 if ( this.options.click ) { 624 utils.click(e); 625 } 626 627 this._execEvent('scrollCancel'); 628 return; 629 } 630 631 if ( this._events.flick && duration < 200 && distanceX < 100 && distanceY < 100 ) { 632 this._execEvent('flick'); 633 return; 634 } 635 636 // start momentum animation if needed 637 if ( this.options.momentum && duration < 300 ) { 638 momentumX = this.hasHorizontalScroll ? utils.momentum(this.x, this.startX, duration, this.maxScrollX, this.options.bounce ? this.wrapperW
638idth : 0, this.options.deceleration) : { destination: newX, duration: 0 }; 639 momentumY = this.hasVerticalScroll ? utils.momentum(this.y, this.startY, duration, this.maxScrollY, this.options.bounce ? this.wrapperHeight : 0, this.options.deceleration) : { destination: newY, duration: 0 }; 640 newX = momentumX.destination; 641 newY = momentumY.destination; 642 time = Math.max(momentumX.duration, momentumY.duration); 643 this.isInTransition = 1; 644 } 645 646 647 if ( this.options.snap ) { 648 var snap = this._nearestSnap(newX, newY); 649 this.currentPage = snap; 650 time = this.options.snapSpeed || Math.max( 651 Math.max( 652 Math.min(Math.abs(newX - snap.x), 1000), 653 Math.min(Math.abs(newY - snap.y), 1000) 654 ), 300); 655 newX = snap.x; 656 newY = snap.y; 657 658 this.directionX = 0; 659 this.directionY = 0; 660 easing = this.options.bounceEasing; 661 } 662 663// INSERT POINT: _end 664 665 if ( newX != this.x || newY != this.y ) { 666 // change easing function when scroller goes out of the boundaries 667 if ( newX > 0 || newX < this.maxScrollX || newY > 0 || newY < this.maxScrollY ) { 668 easing = utils.ease.quadratic; 669 } 670 671 this.scrollTo(newX, newY, time, easing); 672 return; 673 } 674 675 this._execEvent('scrollEnd'); 676 }, 677 678 _resize: function () { 679 var that = this; 680 681 clearTimeout(this.resizeTimeout); 682 683 this.resizeTimeout = setTimeout(function () { 684 that.refresh(); 685 }, this.options.resizePolling); 686 }, 687 688 resetPosition: function (time) { 689 var x = this.x, 690 y = this.y; 691 692 time = time || 0; 693 694 if ( !this.hasHorizontalScroll || this.x > 0 ) { 695 x = 0; 696 } else if ( this.x < this.maxScrollX ) { 697 x = this.maxScrollX; 698 } 699 700 if ( !this.hasVerticalScroll || this.y > 0 ) { 701 y = 0; 702 } else if ( this.y < this.maxScrollY ) { 703 y = this.maxScrollY; 704 } 705 706 if ( x == this.x && y == this.y ) { 707 return false; 708 } 709 710 this.scrollTo(x, y, time, this.options.bounceEasing); 711 712 return true; 713 }, 714 715 disable: function () { 716 this.enabled = false; 717 }, 718 719 enable: function () { 720 this.enabled = true; 721 }, 722 723 refresh: function () { 724 var rf = this.wrapper.offsetHeight; // Force reflow 725 726 this.wrapperWidth = this.wrapper.clientWidth; 727 this.wrapperHeight = this.wrapper.clientHeight; 728 729/* REPLACE START: refresh */ 730 731 this.scrollerWidth = this.scroller.offsetWidth; 732 this.scrollerHeight = this.scroller.offsetHeight; 733 734 this.maxScrollX = this.wrapperWidth - this.scrollerWidth; 735 this.maxScrollY = this.wrapperHeight - this.scrollerHeight; 736 737/* REPLACE END: refresh */ 738 739 this.hasHorizontalScroll = this.options.scrollX && this.maxScrollX < 0; 740 this.hasVerticalScroll = this.options.scrollY && this.maxScrollY < 0; 741 742 if ( !this.hasHorizontalScroll ) { 743 this.maxScrollX = 0; 744 this.scrollerWidth = this.wrapperWidth; 745 } 746 747 if ( !this.hasVerticalScroll ) { 748 this.maxScrollY = 0; 749 this.scrollerHeight = this.wrapperHeight; 750 } 751 752 this.endTime = 0; 753 this.directionX = 0; 754 this.directionY = 0; 755 756 this.wrapperOffset = utils.offset(this.wrapper); 757 758 this._execEvent('refresh'); 759 760 this.resetPosition(); 761 762// INSERT POINT: _refresh 763 764 }, 765 766 on: function (type, fn) { 767 if ( !this._events[type] ) { 768 this._events[type] = []; 769 } 770 771 this._events[type].push(fn); 772 }, 773 774 off: function (type, fn) { 775 if ( !this._events[type] ) { 776 return; 777 } 778 779 var index = this._events[type].indexOf(fn); 780 781 if ( index > -1 ) { 782 this._events[type].splice(index, 1); 783 } 784 }, 785 786 _execEvent: function (type) { 787 if ( !this._events[type] ) { 788 return; 789 } 790 791 var i = 0, 792 l = this._events[type].length; 793 794 if ( !l ) { 795 return; 796 } 797 798 for ( ; i < l; i++ ) { 799 this._events[type][i].apply(this, [].slice.call(arguments, 1)); 800 } 801 }, 802 803 scrollBy: function (x, y, time, easing) { 804 x = this.x + x; 805 y = this.y + y; 806 time = time || 0; 807 808 this.scrollTo(x, y, time, easing); 809 }, 810 811 scrollTo: function (x, y, time, easing) { 812 easing = easing || utils.ease.circular; 813 814 this.isInTransition = this.options.useTransition && time > 0; 815 var transitionType = this.options.useTransition && easing.style; 816 if ( !time || transitionType ) { 817 if(transitionType) { 818 this._transitionTimingFunction(easing.style); 819 this._transitionTime(time); 820 } 821 this._translate(x, y); 822 } else { 823 this._animate(x, y, time, easing.fn); 824 } 825 }, 826 827 scrollToElement: function (el, time, offsetX, offsetY, easing) { 828 el = el.nodeType ? el : this.scroller.querySelector(el); 829 830 if ( !el ) { 831 return; 832 } 833 834 var pos = utils.offset(el); 835 836 pos.left -= this.wrapperOffset.left; 837 pos.top -= this.wrapperOffset.top; 838 839 // if offsetX/Y are true we center the element to the screen 840 if ( offsetX === true ) { 841 offsetX = Math.round(el.offsetWidth / 2 - this.wrapper.offsetWidth / 2); 842 } 843 if ( offsetY === true ) { 844 offsetY = Math.round(el.offsetHeight / 2 - this.wrapper.offsetHeight / 2); 845 } 846 847 pos.left -= offsetX || 0; 848 pos.top -= offsetY || 0; 849 850 pos.left = pos.left > 0 ? 0 : pos.left < this.maxScrollX ? this.maxScrollX : pos.left; 851 pos.top = pos.top > 0 ? 0 : pos.top < this.maxScrollY ? this.maxScrollY : pos.top; 852 853 time = time === undefined || time === null || time === 'auto' ? Math.max(Math.abs(this.x-pos.left), Math.abs(this.y-pos.top)) : time; 854 855 this.scrollTo(pos.left, pos.top, time, easing); 856 }, 857 858 _transitionTime: function (time) { 859 if (!this.options.useTransition) { 860 return; 861 } 862 time = time || 0; 863 var durationProp = utils.style.transitionDuration; 864 if(!durationProp) { 865 return; 866 } 867 868 this.scrollerStyle[durationProp] = time + 'ms'; 869 870 if ( !time && utils.isBadAndroid ) { 871 this.scrollerStyle[durationProp] = '0.0001ms'; 872 // remove 0.0001ms 873 var self = this; 874 rAF(function() { 875 if(self.scrollerStyle[durationProp] === '0.0001ms') { 876 self.scrollerStyle[durationProp] = '0s'; 877 } 878 }); 879 } 880 881 882 if ( this.indicators ) { 883 for ( var i = this.indicators.length; i--; ) { 884 this.indicators[i].transitionTime(time); 885 } 886 } 887 888 889// INSERT POINT: _transitionTime 890 891 }, 892 893 _transitionTimingFunction: function (easing) { 894 this.scrollerStyle[utils.style.transitionTimingFunction] = easing; 895 896 897 if ( this.indicators ) { 898 for ( var i = this.indicators.length; i--; ) { 899 this.indicators[i].transitionTimingFunction(easing); 900 } 901 } 902 903 904// INSERT POINT: _transitionTimingFunction 905 906 }, 907 908 _translate: function (x, y) { 909 if ( this.options.useTransform ) { 910 911/* REPLACE START: _translate */ 912 913 this.scrollerStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.translateZ; 914 915/* REPLACE END: _translate */ 916 917 } else { 918 x = Math.round(x); 919 y = Math.round(y); 920 this.scrollerStyle.left = x + 'px'; 921 this.scrollerStyle.top = y + 'px'; 922 } 923 924 this.x = x; 925 this.y = y; 926 927 928 if ( this.indicators ) { 929 for ( var i = this.indicators.length; i--; ) { 930 this.indicators[i].updatePosition(); 931 } 932 } 933 934 935// INSERT POINT: _translate 936 937 }, 938 939 _initEvents: function (remove) { 940 var eventType = remove ? utils.removeEvent : utils.addEvent, 941 target = this.options.bindToWrapper ? this.wrapper : window; 942 943 eventType(window, 'orientationchange', this); 944 eventType(window, 'resize', this); 945 946 if ( this.options.click ) { 947 eventType(this.wrapper, 'click', this, true); 948 } 949 950 if ( !this.options.disableMouse ) { 951 eventType(this.wrapper, 'mousedown', this); 952 eventType(target, 'mousemove', this); 953 eventType(target, 'mousecancel', this); 954 eventType(target, 'mouseup', this); 955 } 956 957 if ( utils.hasPointer && !this.options.disablePointer ) { 958 eventType(this.wrapper, utils.prefixPointerEvent('pointerdown'), this); 959 eventType(target, utils.prefixPointerEvent('pointermove'), this); 960 eventType(target, utils.prefixPointerEvent('pointercancel'), this); 961 eventType(target, utils.prefixPointerEvent('pointerup'), this); 962 } 963 964 if ( utils.hasTouch && !this.options.disableTouch ) { 965 eventType(this.wrapper, 'touchstart', this); 966 eventType(target, 'touchmove', this); 967 eventType(target, 'touchcancel', this); 968 eventType(target, 'touchend', this); 969 } 970 971 eventType(this.scroller, 'transitionend', this); 972 eventType(this.scroller, 'webkitTransitionEnd', this); 973 eventType(this.scroller, 'oTransitionEnd', this); 974 eventType(this.scroller, 'MSTransitionEnd', this); 975 }, 976 977 getComputedPosition: function () { 978 var matrix = window.getComputedStyle(this.scroller, null), 979 x, y; 980 981 if ( this.options.useTransform ) { 982 matrix = matrix[utils.style.transform].split(')')[0].split(', '); 983 x = +(matrix[12] || matrix[4]); 984 y = +(matrix[13] || matrix[5]); 985 } else { 986 x = +matrix.left.replace(/[^-\d.]/g, ''); 987 y = +matrix.top.replace(/[^-\d.]/g, ''); 988 } 989 990 return { x: x, y: y }; 991 }, 992 _initIndicators: function () { 993 var interactive = this.options.interactiveScrollbars, 994 customStyle = typeof this.options.scrollbars != 'string', 995 indicators = [], 996 indicator; 997 998 var that = this; 999 1000 this.indicators = []; 1001 1002 if ( this.options.scrollbars ) { 1003 // Vertical scrollbar 1004 if ( this.options.scrollY ) { 1005 indicator = { 1006 el: createDefaultScrollbar('v', interactive, this.options.scrollbars), 1007 interactive: interactive, 1008 defaultScrollbars: true, 1009 customStyle: customStyle, 1010 resize: this.options.resizeScrollbars, 1011 shrink: this.options.shrinkScrollbars, 1012 fade: this.options.fadeScrollbars, 1013 listenX: false 1014 }; 1015 1016 this.wrapper.appendChild(indicator.el); 1017 indicators.push(indicator); 1018 } 1019 1020 // Horizontal scrollbar 1021 if ( this.options.scrollX ) { 1022 indicator = { 1023 el: createDefaultScrollbar('h', interactive, this.options.scrollbars), 1024 interactive: interactive, 1025 defaultScrollbars: true, 1026 customStyle: customStyle, 1027 resize: this.options.resizeScrollbars, 1028 shrink: this.options.shrinkScrollbars, 1029 fade: this.options.fadeScrollbars, 1030 listenY: false 1031 }; 1032 1033 this.wrapper.appendChild(indicator.el); 1034 indicators.push(indicator); 1035 } 1036 } 1037 1038 if ( this.options.indicators ) { 1039 // TODO: check concat compatibility 1040 indicators = indicators.concat(this.options.indicators); 1041 } 1042 1043 for ( var i = indicators.length; i--; ) { 1044 this.indicators.push( new Indicator(this, indicators[i]) ); 1045 } 1046 1047 // TODO: check if we can use array.map (wide compatibility and performance issues) 1048 function _indicatorsMap (fn) { 1049 if (that.indicators) { 1050 for ( var i = that.indicators.length; i--; ) { 1051 fn.call(that.indicators[i]); 1052 } 1053 } 1054 } 1055 1056 if ( this.options.fadeScrollbars ) { 1057 this.on('scrollEnd', function () { 1058 _indicatorsMap(function () { 1059 this.fade(); 1060 }); 1061 }); 1062 1063 this.on('scrollCancel', function () { 1064 _indicatorsMap(function () { 1065 this.fade(); 1066 }); 1067 }); 1068 1069 this.on('scrollStart', function () { 1070 _indicatorsMap(function () { 1071 this.fade(1); 1072 }); 1073 }); 1074 1075 this.on('beforeScrollStart', function () { 1076 _indicatorsMap(function () { 1077 this.fade(1, true); 1078 }); 1079 }); 1080 } 1081 1082 1083 this.on('refresh', function () { 1084 _indicatorsMap(function () { 1085 this.refresh(); 1086 }); 1087 }); 1088 1089 this.on('destroy', function () { 1090 _indicatorsMap(function () { 1091 this.destroy(); 1092 }); 1093 1094 delete this.indicators; 1095 }); 1096 }, 1097 1098 _initWheel: function () { 1099 utils.addEvent(this.wrapper, 'wheel', this); 1100 utils.addEvent(this.wrapper, 'mousewheel', this); 1101 utils.addEvent(this.wrapper, 'DOMMouseScroll', this); 1102 1103 this.on('destroy', function () { 1104 clearTimeout(this.wheelTimeout); 1105 this.wheelTimeout = null; 1106 utils.removeEvent(this.wrapper, 'wheel', this); 1107 utils.removeEvent(this.wrapper, 'mousewheel', this); 1108 utils.removeEvent(this.wrapper, 'DOMMouseScroll', this); 1109 }); 1110 }, 1111 1112 _wheel: function (e) { 1113 if ( !this.enabled ) { 1114 return; 1115 } 1116 1117 var wheelDeltaX, wheelDeltaY, 1118 newX, newY, 1119 that = this; 1120 1121 if ( this.wheelTimeout === undefined ) { 1122 that._execEvent('scrollStart'); 1123 } 1124 1125 // Execute the scrollEnd event after 400ms the wheel stopped scrolling 1126 clearTimeout(this.wheelTimeout); 1127 this.wheelTimeout = setTimeout(function () { 1128 if(!that.options.snap) { 1129 that._execEvent('scrollEnd'); 1130 } 1131 that.wheelTimeout = undefined; 1132 }, 400); 1133 1134 if ( 'deltaX' in e ) { 1135 if (e.deltaMode === 1) { 1136 wheelDeltaX = -e.deltaX * this.options.mouseWheelSpeed; 1137 wheelDeltaY = -e.deltaY * this.options.mouseWheelSpeed; 1138 } else { 1139 wheelDeltaX = -e.deltaX; 1140 wheelDeltaY = -e.deltaY; 1141 } 1142 } else if ( 'wheelDeltaX' in e ) { 1143 wheelDeltaX = e.wheelDeltaX / 120 * this.options.mouseWheelSpeed; 1144 wheelDeltaY = e.wheelDeltaY / 120 * this.options.mouseWheelSpeed; 1145 } else if ( 'wheelDelta' in e ) { 1146 wheelDeltaX = wheelDeltaY = e.wheelDelta / 120 * this.options.mouseWheelSpeed; 1147 } else if ( 'detail' in e ) { 1148 wheelDeltaX = wheelDeltaY = -e.detail / 3 * this.options.mouseWheelSpeed; 1149 } else { 1150 return; 1151 } 1152 1153 wheelDeltaX *= this.options.invertWheelDirection; 1154 wheelDeltaY *= this.options.invertWheelDirection; 1155 1156 if ( !this.hasVerticalScroll ) { 1157 wheelDeltaX = wheelDeltaY; 1158 wheelDeltaY = 0; 1159 } 1160 1161 if ( this.options.snap ) { 1162 newX = this.currentPage.pageX; 1163 newY = this.currentPage.pageY; 1164 1165 if ( wheelDeltaX > 0 ) { 1166 newX--; 1167 } else if ( wheelDeltaX < 0 ) { 1168 newX++; 1169 } 1170 1171 if ( wheelDeltaY > 0 ) { 1172 newY--; 1173 } else if ( wheelDeltaY < 0 ) { 1174 newY++; 1175 } 1176 1177 this.goToPage(newX, newY); 1178 1179 return; 1180 } 1181 1182 newX = this.x + Math.round
1182(this.hasHorizontalScroll ? wheelDeltaX : 0); 1183 newY = this.y + Math.round(this.hasVerticalScroll ? wheelDeltaY : 0); 1184 1185 this.directionX = wheelDeltaX > 0 ? -1 : wheelDeltaX < 0 ? 1 : 0; 1186 this.directionY = wheelDeltaY > 0 ? -1 : wheelDeltaY < 0 ? 1 : 0; 1187 1188 if ( newX > 0 ) { 1189 newX = 0; 1190 } else if ( newX < this.maxScrollX ) { 1191 newX = this.maxScrollX; 1192 } 1193 1194 if ( newY > 0 ) { 1195 newY = 0; 1196 } else if ( newY < this.maxScrollY ) { 1197 newY = this.maxScrollY; 1198 } 1199 1200 this.scrollTo(newX, newY, 0); 1201 1202// INSERT POINT: _wheel 1203 }, 1204 1205 _initSnap: function () { 1206 this.currentPage = {}; 1207 1208 if ( typeof this.options.snap == 'string' ) { 1209 this.options.snap = this.scroller.querySelectorAll(this.options.snap); 1210 } 1211 1212 this.on('refresh', function () { 1213 var i = 0, l, 1214 m = 0, n, 1215 cx, cy, 1216 x = 0, y, 1217 stepX = this.options.snapStepX || this.wrapperWidth, 1218 stepY = this.options.snapStepY || this.wrapperHeight, 1219 el; 1220 1221 this.pages = []; 1222 1223 if ( !this.wrapperWidth || !this.wrapperHeight || !this.scrollerWidth || !this.scrollerHeight ) { 1224 return; 1225 } 1226 1227 if ( this.options.snap === true ) { 1228 cx = Math.round( stepX / 2 ); 1229 cy = Math.round( stepY / 2 ); 1230 1231 while ( x > -this.scrollerWidth ) { 1232 this.pages[i] = []; 1233 l = 0; 1234 y = 0; 1235 1236 while ( y > -this.scrollerHeight ) { 1237 this.pages[i][l] = { 1238 x: Math.max(x, this.maxScrollX), 1239 y: Math.max(y, this.maxScrollY), 1240 width: stepX, 1241 height: stepY, 1242 cx: x - cx, 1243 cy: y - cy 1244 }; 1245 1246 y -= stepY; 1247 l++; 1248 } 1249 1250 x -= stepX; 1251 i++; 1252 } 1253 } else { 1254 el = this.options.snap; 1255 l = el.length; 1256 n = -1; 1257 1258 for ( ; i < l; i++ ) { 1259 if ( i === 0 || el[i].offsetLeft <= el[i-1].offsetLeft ) { 1260 m = 0; 1261 n++; 1262 } 1263 1264 if ( !this.pages[m] ) { 1265 this.pages[m] = []; 1266 } 1267 1268 x = Math.max(-el[i].offsetLeft, this.maxScrollX); 1269 y = Math.max(-el[i].offsetTop, this.maxScrollY); 1270 cx = x - Math.round(el[i].offsetWidth / 2); 1271 cy = y - Math.round(el[i].offsetHeight / 2); 1272 1273 this.pages[m][n] = { 1274 x: x, 1275 y: y, 1276 width: el[i].offsetWidth, 1277 height: el[i].offsetHeight, 1278 cx: cx, 1279 cy: cy 1280 }; 1281 1282 if ( x > this.maxScrollX ) { 1283 m++; 1284 } 1285 } 1286 } 1287 1288 this.goToPage(this.currentPage.pageX || 0, this.currentPage.pageY || 0, 0); 1289 1290 // Update snap threshold if needed 1291 if ( this.options.snapThreshold % 1 === 0 ) { 1292 this.snapThresholdX = this.options.snapThreshold; 1293 this.snapThresholdY = this.options.snapThreshold; 1294 } else { 1295 this.snapThresholdX = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].width * this.options.snapThreshold); 1296 this.snapThresholdY = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].height * this.options.snapThreshold); 1297 } 1298 }); 1299 1300 this.on('flick', function () { 1301 var time = this.options.snapSpeed || Math.max( 1302 Math.max( 1303 Math.min(Math.abs(this.x - this.startX), 1000), 1304 Math.min(Math.abs(this.y - this.startY), 1000) 1305 ), 300); 1306 1307 this.goToPage( 1308 this.currentPage.pageX + this.directionX, 1309 this.currentPage.pageY + this.directionY, 1310 time 1311 ); 1312 }); 1313 }, 1314 1315 _nearestSnap: function (x, y) { 1316 if ( !this.pages.length ) { 1317 return { x: 0, y: 0, pageX: 0, pageY: 0 }; 1318 } 1319 1320 var i = 0, 1321 l = this.pages.length, 1322 m = 0; 1323 1324 // Check if we exceeded the snap threshold 1325 if ( Math.abs(x - this.absStartX) < this.snapThresholdX && 1326 Math.abs(y - this.absStartY) < this.snapThresholdY ) { 1327 return this.currentPage; 1328 } 1329 1330 if ( x > 0 ) { 1331 x = 0; 1332 } else if ( x < this.maxScrollX ) { 1333 x = this.maxScrollX; 1334 } 1335 1336 if ( y > 0 ) { 1337 y = 0; 1338 } else if ( y < this.maxScrollY ) { 1339 y = this.maxScrollY; 1340 } 1341 1342 for ( ; i < l; i++ ) { 1343 if ( x >= this.pages[i][0].cx ) { 1344 x = this.pages[i][0].x; 1345 break; 1346 } 1347 } 1348 1349 l = this.pages[i].length; 1350 1351 for ( ; m < l; m++ ) { 1352 if ( y >= this.pages[0][m].cy ) { 1353 y = this.pages[0][m].y; 1354 break; 1355 } 1356 } 1357 1358 if ( i == this.currentPage.pageX ) { 1359 i += this.directionX; 1360 1361 if ( i < 0 ) { 1362 i = 0; 1363 } else if ( i >= this.pages.length ) { 1364 i = this.pages.length - 1; 1365 } 1366 1367 x = this.pages[i][0].x; 1368 } 1369 1370 if ( m == this.currentPage.pageY ) { 1371 m += this.directionY; 1372 1373 if ( m < 0 ) { 1374 m = 0; 1375 } else if ( m >= this.pages[0].length ) { 1376 m = this.pages[0].length - 1; 1377 } 1378 1379 y = this.pages[0][m].y; 1380 } 1381 1382 return { 1383 x: x, 1384 y: y, 1385 pageX: i, 1386 pageY: m 1387 }; 1388 }, 1389 1390 goToPage: function (x, y, time, easing) { 1391 easing = easing || this.options.bounceEasing; 1392 1393 if ( x >= this.pages.length ) { 1394 x = this.pages.length - 1; 1395 } else if ( x < 0 ) { 1396 x = 0; 1397 } 1398 1399 if ( y >= this.pages[x].length ) { 1400 y = this.pages[x].length - 1; 1401 } else if ( y < 0 ) { 1402 y = 0; 1403 } 1404 1405 var posX = this.pages[x][y].x, 1406 posY = this.pages[x][y].y; 1407 1408 time = time === undefined ? this.options.snapSpeed || Math.max( 1409 Math.max( 1410 Math.min(Math.abs(posX - this.x), 1000), 1411 Math.min(Math.abs(posY - this.y), 1000) 1412 ), 300) : time; 1413 1414 this.currentPage = { 1415 x: posX, 1416 y: posY, 1417 pageX: x, 1418 pageY: y 1419 }; 1420 1421 this.scrollTo(posX, posY, time, easing); 1422 }, 1423 1424 next: function (time, easing) { 1425 var x = this.currentPage.pageX, 1426 y = this.currentPage.pageY; 1427 1428 x++; 1429 1430 if ( x >= this.pages.length && this.hasVerticalScroll ) { 1431 x = 0; 1432 y++; 1433 } 1434 1435 this.goToPage(x, y, time, easing); 1436 }, 1437 1438 prev: function (time, easing) { 1439 var x = this.currentPage.pageX, 1440 y = this.currentPage.pageY; 1441 1442 x--; 1443 1444 if ( x < 0 && this.hasVerticalScroll ) { 1445 x = 0; 1446 y--; 1447 } 1448 1449 this.goToPage(x, y, time, easing); 1450 }, 1451 1452 _initKeys: function (e) { 1453 // default key bindings 1454 var keys = { 1455 pageUp: 33, 1456 pageDown: 34, 1457 end: 35, 1458 home: 36, 1459 left: 37, 1460 up: 38, 1461 right: 39, 1462 down: 40 1463 }; 1464 var i; 1465 1466 // if you give me characters I give you keycode 1467 if ( typeof this.options.keyBindings == 'object' ) { 1468 for ( i in this.options.keyBindings ) { 1469 if ( typeof this.options.keyBindings[i] == 'string' ) { 1470 this.options.keyBindings[i] = this.options.keyBindings[i].toUpperCase().charCo
1470deAt(0); 1471 } 1472 } 1473 } else { 1474 this.options.keyBindings = {}; 1475 } 1476 1477 for ( i in keys ) { 1478 this.options.keyBindings[i] = this.options.keyBindings[i] || keys[i]; 1479 } 1480 1481 utils.addEvent(window, 'keydown', this); 1482 1483 this.on('destroy', function () { 1484 utils.removeEvent(window, 'keydown', this); 1485 }); 1486 }, 1487 1488 _key: function (e) { 1489 if ( !this.enabled ) { 1490 return; 1491 } 1492 1493 var snap = this.options.snap, // we are using this alot, better to cache it 1494 newX = snap ? this.currentPage.pageX : this.x, 1495 newY = snap ? this.currentPage.pageY : this.y, 1496 now = utils.getTime(), 1497 prevTime = this.keyTime || 0, 1498 acceleration = 0.250, 1499 pos; 1500 1501 if ( this.options.useTransition && this.isInTransition ) { 1502 pos = this.getComputedPosition(); 1503 1504 this._translate(Math.round(pos.x), Math.round(pos.y)); 1505 this.isInTransition = false; 1506 } 1507 1508 this.keyAcceleration = now - prevTime < 200 ? Math.min(this.keyAcceleration + acceleration, 50) : 0; 1509 1510 switch ( e.keyCode ) { 1511 case this.options.keyBindings.pageUp: 1512 if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) { 1513 newX += snap ? 1 : this.wrapperWidth; 1514 } else { 1515 newY += snap ? 1 : this.wrapperHeight; 1516 } 1517 break; 1518 case this.options.keyBindings.pageDown: 1519 if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) { 1520 newX -= snap ? 1 : this.wrapperWidth; 1521 } else { 1522 newY -= snap ? 1 : this.wrapperHeight; 1523 } 1524 break; 1525 case this.options.keyBindings.end: 1526 newX = snap ? this.pages.length-1 : this.maxScrollX; 1527 newY = snap ? this.pages[0].length-1 : this.maxScrollY; 1528 break; 1529 case this.options.keyBindings.home: 1530 newX = 0; 1531 newY = 0; 1532 break; 1533 case this.options.keyBindings.left: 1534 newX += snap ? -1 : 5 + this.keyAcceleration>>0; 1535 break; 1536 case this.options.keyBindings.up: 1537 newY += snap ? 1 : 5 + this.keyAcceleration>>0; 1538 break; 1539 case this.options.keyBindings.right: 1540 newX -= snap ? -1 : 5 + this.keyAcceleration>>0; 1541 break; 1542 case this.options.keyBindings.down: 1543 newY -= snap ? 1 : 5 + this.keyAcceleration>>0; 1544 break; 1545 default: 1546 return; 1547 } 1548 1549 if ( snap ) { 1550 this.goToPage(newX, newY); 1551 return; 1552 } 1553 1554 if ( newX > 0 ) { 1555 newX = 0; 1556 this.keyAcceleration = 0; 1557 } else if ( newX < this.maxScrollX ) { 1558 newX = this.maxScrollX; 1559 this.keyAcceleration = 0; 1560 } 1561 1562 if ( newY > 0 ) { 1563 newY = 0; 1564 this.keyAcceleration = 0; 1565 } else if ( newY < this.maxScrollY ) { 1566 newY = this.maxScrollY; 1567 this.keyAcceleration = 0; 1568 } 1569 1570 this.scrollTo(newX, newY, 0); 1571 1572 this.keyTime = now; 1573 }, 1574 1575 _animate: function (destX, destY, duration, easingFn) { 1576 var that = this, 1577 startX = this.x, 1578 startY = this.y, 1579 startTime = utils.getTime(), 1580 destTime = startTime + duration; 1581 1582 function step () { 1583 var now = utils.getTime(), 1584 newX, newY, 1585 easing; 1586 1587 if ( now >= destTime ) { 1588 that.isAnimating = false; 1589 that._translate(destX, destY); 1590 1591 if ( !that.resetPosition(that.options.bounceTime) ) { 1592 that._execEvent('scrollEnd'); 1593 } 1594 1595 return; 1596 } 1597 1598 now = ( now - startTime ) / duration; 1599 easing = easingFn(now); 1600 newX = ( destX - startX ) * easing + startX; 1601 newY = ( destY - startY ) * easing + startY; 1602 that._translate(newX, newY); 1603 1604 if ( that.isAnimating ) { 1605 rAF(step); 1606 } 1607 } 1608 1609 this.isAnimating = true; 1610 step(); 1611 }, 1612 handleEvent: function (e) { 1613 switch ( e.type ) { 1614 case 'touchstart': 1615 case 'pointerdown': 1616 case 'MSPointerDown': 1617 case 'mousedown': 1618 this._start(e); 1619 break; 1620 case 'touchmove': 1621 case 'pointermove': 1622 case 'MSPointerMove': 1623 case 'mousemove': 1624 this._move(e); 1625 break; 1626 case 'touchend': 1627 case 'pointerup': 1628 case 'MSPointerUp': 1629 case 'mouseup': 1630 case 'touchcancel': 1631 case 'pointercancel': 1632 case 'MSPointerCancel': 1633 case 'mousecancel': 1634 this._end(e); 1635 break; 1636 case 'orientationchange': 1637 case 'resize': 1638 this._resize(); 1639 break; 1640 case 'transitionend': 1641 case 'webkitTransitionEnd': 1642 case 'oTransitionEnd': 1643 case 'MSTransitionEnd': 1644 this._transitionEnd(e); 1645 break; 1646 case 'wheel': 1647 case 'DOMMouseScroll': 1648 case 'mousewheel': 1649 this._wheel(e); 1650 break; 1651 case 'keydown': 1652 this._key(e); 1653 break; 1654 case 'click': 1655 if ( this.enabled && !e._constructed ) { 1656 e.preventDefault(); 1657 e.stopPropagation(); 1658 } 1659 break; 1660 } 1661 } 1662}; 1663function createDefaultScrollbar (direction, interactive, type) { 1664 var scrollbar = document.createElement('div'), 1665 indicator = document.createElement('div'); 1666 1667 if ( type === true ) { 1668 scrollbar.style.cssText = 'position:absolute;z-index:9999'; 1669 indicator.style.cssText = '-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;position:absolute;background:rgba(0,0,0,0.5);border:1px solid rgba(255,255,255,0.9);border-radius:3px'; 1670 } 1671 1672 indicator.className = 'iScrollIndicator'; 1673 1674 if ( direction == 'h' ) { 1675 if ( type === true ) { 1676 scrollbar.style.cssText += ';height:7px;left:2px;right:2px;bottom:0'; 1677 indicator.style.height = '100%'; 1678 } 1679 scrollbar.className = 'iScrollHorizontalScrollbar'; 1680 } else { 1681 if ( type === true ) { 1682 scrollbar.style.cssText += ';width:7px;bottom:2px;top:2px;right:1px'; 1683 indicator.style.width = '100%'; 1684 } 1685 scrollbar.className = 'iScrollVerticalScrollbar'; 1686 } 1687 1688 scrollbar.style.cssText += ';overflow:hidden'; 1689 1690 if ( !interactive ) { 1691 scrollbar.style.pointerEvents = 'none'; 1692 } 1693 1694 scrollbar.appendChild(indicator); 1695 1696 return scrollbar; 1697} 1698 1699function Indicator (scroller, options) { 1700 this.wrapper = typeof options.el == 'string' ? document.querySelector(options.el) : options.el; 1701 this.wrapperStyle = this.wrapper.style; 1702 this.indicator = this.wrapper.children[0]; 1703 this.indicatorStyle = this.indicator.style; 1704 this.scroller = scroller; 1705 1706 this.options = { 1707 listenX: true, 1708 listenY: true, 1709 interactive: false, 1710 resize: true, 1711 defaultScrollbars: false, 1712 shrink: false, 1713 fade: false, 1714 speedRatioX: 0, 1715 speedRatioY: 0 1716 }; 1717 1718 for ( var i in options ) { 1719 this.options[i] = options[i]; 1720 } 1721 1722 this.sizeRatioX = 1; 1723 this.sizeRatioY = 1; 1724 this.maxPosX = 0; 1725 this.maxPosY = 0; 1726 1727 if ( this.options.interactive ) { 1728 if ( !this.options.disableTouch ) { 1729 utils.addEvent(this.indicator, 'touchstart', this); 1730 utils.addEvent(window, 'touchend', this); 1731 } 1732 if ( !this.options.disablePointer ) { 1733 utils.addEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this); 1734 utils.addEvent(window, utils.prefixPointerEvent('pointerup'), this); 1735 } 1736 if ( !this.options.disableMouse ) { 1737 utils.addEvent(this.indicator, 'mousedown', this); 1738 utils.addEvent(window, 'mouseup', this); 1739 } 1740 } 1741 1742 if ( this.options.fade ) { 1743 this.wrapperStyle[utils.style.transform] = this.scroller.translateZ; 1744 var durationProp = utils.style.transitionDuration; 1745 if(!durationProp) { 1746 return; 1747 } 1748 this.wrapperStyle[durationProp] = utils.isBadAndroid ? '0.0001ms' : '0ms'; 1749 // remove 0.0001ms 1750 var self = this; 1751 if(utils.isBadAndroid) { 1752 rAF(function() { 1753 if(self.wrapperStyle[durationProp] === '0.0001ms') { 1754 self.wrapperStyle[durationProp] = '0s'; 1755 } 1756 }); 1757 } 1758 this.wrapperStyle.opacity = '0'; 1759 } 1760} 1761 1762Indicator.prototype = { 1763 handleEvent: function (e) { 1764 switch ( e.type ) { 1765 case 'touchstart': 1766 case 'pointerdown': 1767 case 'MSPointerDown': 1768 case 'mousedown': 1769 this._start(e); 1770 break; 1771 case 'touchmove': 1772 case 'pointermove': 1773 case 'MSPointerMove': 1774 case 'mousemove': 1775 this._move(e); 1776 break; 1777 case 'touchend': 1778 case 'pointerup': 1779 case 'MSPointerUp': 1780 case 'mouseup': 1781 case 'touchcancel': 1782 case 'pointercancel': 1783 case 'MSPointerCancel': 1784 case 'mousecancel': 1785 this._end(e); 1786 break; 1787 } 1788 }, 1789 1790 destroy: function () { 1791 if ( this.options.fadeScrollbars ) { 1792 clearTimeout(this.fadeTimeout); 1793 this.fadeTimeout = null; 1794 } 1795 if ( this.options.interactive ) { 1796 utils.removeEvent(this.indicator, 'touchstart', this); 1797 utils.removeEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this); 1798 utils.removeEvent(this.indicator, 'mousedown', this); 1799 1800 utils.removeEvent(window, 'touchmove', this); 1801 utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this); 1802 utils.removeEvent(window, 'mousemove', this); 1803 1804 utils.removeEvent(window, 'touchend', this); 1805 utils.removeEvent(window, utils.prefixPointerEvent('pointerup'), this); 1806 utils.removeEvent(window, 'mouseup', this); 1807 } 1808 1809 if ( this.options.defaultScrollbars ) { 1810 this.wrapper.parentNode.removeChild(this.wrapper); 1811 } 1812 }, 1813 1814 _start: function (e) { 1815 var point = e.touches ? e.touches[0] : e; 1816 1817 e.preventDefault(); 1818 e.stopPropagation(); 1819 1820 this.transitionTime(); 1821 1822 this.initiated = true; 1823 this.moved = false;
1824 this.lastPointX = point.pageX; 1825 this.lastPointY = point.pageY; 1826 1827 this.startTime = utils.getTime(); 1828 1829 if ( !this.options.disableTouch ) { 1830 utils.addEvent(window, 'touchmove', this); 1831 } 1832 if ( !this.options.disablePointer ) { 1833 utils.addEvent(window, utils.prefixPointerEvent('pointermove'), this); 1834 } 1835 if ( !this.options.disableMouse ) { 1836 utils.addEvent(window, 'mousemove', this); 1837 } 1838 1839 this.scroller._execEvent('beforeScrollStart'); 1840 }, 1841 1842 _move: function (e) { 1843 var point = e.touches ? e.touches[0] : e, 1844 deltaX, deltaY, 1845 newX, newY, 1846 timestamp = utils.getTime(); 1847 1848 if ( !this.moved ) { 1849 this.scroller._execEvent('scrollStart'); 1850 } 1851 1852 this.moved = true; 1853 1854 deltaX = point.pageX - this.lastPointX; 1855 this.lastPointX = point.pageX; 1856 1857 deltaY = point.pageY - this.lastPointY; 1858 this.lastPointY = point.pageY; 1859 1860 newX = this.x + deltaX; 1861 newY = this.y + deltaY; 1862 1863 this._pos(newX, newY); 1864 1865// INSERT POINT: indicator._move 1866 1867 e.preventDefault(); 1868 e.stopPropagation(); 1869 }, 1870 1871 _end: function (e) { 1872 if ( !this.initiated ) { 1873 return; 1874 } 1875 1876 this.initiated = false; 1877 1878 e.preventDefault(); 1879 e.stopPropagation(); 1880 1881 utils.removeEvent(window, 'touchmove', this); 1882 utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this); 1883 utils.removeEvent(window, 'mousemove', this); 1884 1885 if ( this.scroller.options.snap ) { 1886 var snap = this.scroller._nearestSnap(this.scroller.x, this.scroller.y); 1887 1888 var time = this.options.snapSpeed || Math.max( 1889 Math.max( 1890 Math.min(Math.abs(this.scroller.x - snap.x), 1000), 1891 Math.min(Math.abs(this.scroller.y - snap.y), 1000) 1892 ), 300); 1893 1894 if ( this.scroller.x != snap.x || this.scroller.y != snap.y ) { 1895 this.scroller.directionX = 0; 1896 this.scroller.directionY = 0; 1897 this.scroller.currentPage = snap; 1898 this.scroller.scrollTo(snap.x, snap.y, time, this.scroller.options.bounceEasing); 1899 } 1900 } 1901 1902 if ( this.moved ) { 1903 this.scroller._execEvent('scrollEnd'); 1904 } 1905 }, 1906 1907 transitionTime: function (time) { 1908 time = time || 0; 1909 var durationProp = utils.style.transitionDuration; 1910 if(!durationProp) { 1911 return; 1912 } 1913 1914 this.indicatorStyle[durationProp] = time + 'ms'; 1915 1916 if ( !time && utils.isBadAndroid ) { 1917 this.indicatorStyle[durationProp] = '0.0001ms'; 1918 // remove 0.0001ms 1919 var self = this; 1920 rAF(function() { 1921 if(self.indicatorStyle[durationProp] === '0.0001ms') { 1922 self.indicatorStyle[durationProp] = '0s'; 1923 } 1924 }); 1925 } 1926 }, 1927 1928 transitionTimingFunction: function (easing) { 1929 this.indicatorStyle[utils.style.transitionTimingFunction] = easing; 1930 }, 1931 1932 refresh: function () { 1933 this.transitionTime(); 1934 1935 if ( this.options.listenX && !this.options.listenY ) { 1936 this.indicatorStyle.display = this.scroller.hasHorizontalScroll ? 'block' : 'none'; 1937 } else if ( this.options.listenY && !this.options.listenX ) { 1938 this.indicatorStyle.display = this.scroller.hasVerticalScroll ? 'block' : 'none'; 1939 } else { 1940 this.indicatorStyle.display = this.scroller.hasHorizontalScroll || this.scroller.hasVerticalScroll ? 'block' : 'none'; 1941 } 1942 1943 if ( this.scroller.hasHorizontalScroll && this.scroller.hasVerticalScroll ) { 1944 utils.addClass(this.wrapper, 'iScrollBothScrollbars'); 1945 utils.removeClass(this.wrapper, 'iScrollLoneScrollbar'); 1946 1947 if ( this.options.defaultScrollbars && this.options.customStyle ) { 1948 if ( this.options.listenX ) { 1949 this.wrapper.style.right = '8px'; 1950 } else { 1951 this.wrapper.style.bottom = '8px'; 1952 } 1953 } 1954 } else { 1955 utils.removeClass(this.wrapper, 'iScrollBothScrollbars'); 1956 utils.addClass(this.wrapper, 'iScrollLoneScrollbar'); 1957 1958 if ( this.options.defaultScrollbars && this.options.customStyle ) { 1959 if ( this.options.listenX ) { 1960 this.wrapper.style.right = '2px'; 1961 } else { 1962 this.wrapper.style.bottom = '2px'; 1963 } 1964 } 1965 } 1966 1967 var r = this.wrapper.offsetHeight; // force refresh 1968 1969 if ( this.options.listenX ) {
1970 this.wrapperWidth = this.wrapper.clientWidth; 1971 if ( this.options.resize ) { 1972 this.indicatorWidth = Math.max(Math.round(this.wrapperWidth * this.wrapperWidth / (this.scroller.scrollerWidth || this.wrapperWidth || 1)), 8); 1973 this.indicatorStyle.width = this.indicatorWidth + 'px'; 1974 } else { 1975 this.indicatorWidth = this.indicator.clientWidth; 1976 } 1977 1978 this.maxPosX = this.wrapperWidth - this.indicatorWidth; 1979 1980 if ( this.options.shrink == 'clip' ) { 1981 this.minBoundaryX = -this.indicatorWidth + 8; 1982 this.maxBoundaryX = this.wrapperWidth - 8; 1983 } else { 1984 this.minBoundaryX = 0; 1985 this.maxBoundaryX = this.maxPosX; 1986 } 1987 1988 this.sizeRatioX = this.options.speedRatioX || (this.scroller.maxScrollX && (this.maxPosX / this.scroller.maxScrollX)); 1989 } 1990 1991 if ( this.options.listenY ) { 1992 this.wrapperHeight = this.wrapper.clientHeight; 1993 if ( this.options.resize ) { 1994 this.indicatorHeight = Math.max(Math.round(this.wrapperHeight * this.wrapperHeight / (this.scroller.scrollerHeight || this.wrapperHeight || 1)), 8); 1995 this.indicatorStyle.height = this.indicatorHeight + 'px'; 1996 } else { 1997 this.indicatorHeight = this.indicator.clientHeight; 1998 } 1999 2000 this.maxPosY = this.wrapperHeight - this.indicatorHeight; 2001 2002 if ( this.options.shrink == 'clip' ) { 2003 this.minBoundaryY = -this.indicatorHeight + 8; 2004 this.maxBoundaryY = this.wrapperHeight - 8; 2005 } else { 2006 this.minBoundaryY = 0; 2007 this.maxBoundaryY = this.maxPosY; 2008 } 2009 2010 this.maxPosY = this.wrapperHeight - this.indicatorHeight; 2011 this.sizeRatioY = this.options.speedRatioY || (this.scroller.maxScrollY && (this.maxPosY / this.scroller.maxScrollY)); 2012 } 2013 2014 this.updatePosition(); 2015 }, 2016 2017 updatePosition: function () { 2018 var x = this.options.listenX && Math.round(this.sizeRatioX * this.scroller.x) || 0, 2019 y = this.options.listenY && Math.round(this.sizeRatioY * this.scroller.y) || 0; 2020 2021 if ( !this.options.ignoreBoundaries ) { 2022 if ( x < this.minBoundaryX ) { 2023 if ( this.options.shrink == 'scale' ) { 2024 this.width = Math.max(this.indicatorWidth + x, 8); 2025 this.indicatorStyle.width = this.width + 'px'; 2026 } 2027 x = this.minBoundaryX; 2028 } else if ( x > this.maxBoundaryX ) { 2029 if ( this.options.shrink == 'scale' ) { 2030 this.width = Math.max(this.indicatorWidth - (x - this.maxPosX), 8); 2031 this.indicatorStyle.width = this.width + 'px'; 2032 x = this.maxPosX + this.indicatorWidth - this.width; 2033 } else { 2034 x = this.maxBoundaryX; 2035 } 2036 } else if ( this.options.shrink == 'scale' && this.width != this.indicatorWidth ) { 2037 this.width = this.indicatorWidth; 2038 this.indicatorStyle.width = this.width + 'px'; 2039 } 2040 2041 if ( y < this.minBoundaryY ) { 2042 if ( this.options.shrink == 'scale' ) { 2043 this.height = Math.max(this.indicatorHeight + y * 3, 8); 2044 this.indicatorStyle.height = this.height + 'px'; 2045 } 2046 y = this.minBoundaryY; 2047 } else if ( y > this.maxBoundaryY ) { 2048 if ( this.options.shrink == 'scale' ) { 2049 this.height = Math.max(this.indicatorHeight - (y - this.maxPosY) * 3, 8); 2050 this.indicatorStyle.height = this.height + 'px'; 2051 y = this.maxPosY + this.indicatorHeight - this.height; 2052 } else { 2053 y = this.maxBoundaryY; 2054 } 2055 } else if ( this.options.shrink == 'scale' && this.height != this.indicatorHeight ) { 2056 this.height = this.indicatorHeight; 2057 this.indicatorStyle.height = this.height + 'px'; 2058 } 2059 } 2060 2061 this.x = x; 2062 this.y = y; 2063 2064 if ( this.scroller.options.useTransform ) { 2065 this.indicatorStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.scroller.translateZ; 2066 } else { 2067 this.indicatorStyle.left = x + 'px'; 2068 this.indicatorStyle.top = y + 'px'; 2069 } 2070 }, 2071 2072 _pos: function (x, y) { 2073 if ( x < 0 ) { 2074 x = 0; 2075 } else if ( x > this.maxPosX ) { 2076 x = this.maxPosX; 2077 } 2078 2079 if ( y < 0 ) { 2080 y = 0; 2081 } else if ( y > this.maxPosY ) { 2082 y = this.maxPosY;
2083 } 2084 2085 x = this.options.listenX ? Math.round(x / this.sizeRatioX) : this.scroller.x; 2086 y = this.options.listenY ? Math.round(y / this.sizeRatioY) : this.scroller.y; 2087 2088 this.scroller.scrollTo(x, y); 2089 }, 2090 2091 fade: function (val, hold) { 2092 if ( hold && !this.visible ) { 2093 return; 2094 } 2095 2096 clearTimeout(this.fadeTimeout); 2097 this.fadeTimeout = null; 2098 2099 var time = val ? 250 : 500, 2100 delay = val ? 0 : 300; 2101 2102 val = val ? '1' : '0'; 2103 2104 this.wrapperStyle[utils.style.transitionDuration] = time + 'ms'; 2105 2106 this.fadeTimeout = setTimeout((function (val) { 2107 this.wrapperStyle.opacity = val; 2108 this.visible = +val; 2109 }).bind(this, val), delay); 2110 } 2111}; 2112 2113IScroll.utils = utils; 2114 2115if ( typeof module != 'undefined' && module.exports ) { 2116 module.exports = IScroll; 2117} else if ( typeof define == 'function' && define.amd ) { 2118 define( function () { return IScroll; } ); 2119} else { 2120 window.IScroll = IScroll; 2121} 2122 2123})(window, document, Math); 2124 2125/*! 2126 * fullPage ScrollOverflow 2127 * https://github.com/alvarotrigo/fullPage.js 2128 * @license MIT licensed 2129 * 2130 * Copyright (C) 2015 alvarotrigo.com - A project by Alvaro Trigo 2131 */ 2132(function(window, $) { 2133 var ACTIVE = 'active'; 2134 var ACTIVE_SEL = '.' + ACTIVE; 2135 2136 var SECTION = 'fp-section'; 2137 var SECTION_SEL = '.' + SECTION; 2138 var SECTION_ACTIVE_SEL = SECTION_SEL + ACTIVE_SEL; 2139 2140 var SLIDE = 'fp-slide'; 2141 var SLIDE_SEL = '.' + SLIDE; 2142 var SLIDE_ACTIVE_SEL = SLIDE_SEL + ACTIVE_SEL; 2143 var SLIDES_WRAPPER = 'fp-slides'; 2144 var SLIDES_WRAPPER_SEL = '.' + SLIDES_WRAPPER; 2145 2146 // scrolloverflow 2147 var SCROLLABLE = 'fp-scrollable'; 2148 var SCROLLABLE_SEL = '.' + SCROLLABLE; 2149 2150 if(typeof IScroll !== 'undefined'){ 2151 /* 2152 * Turns iScroll `mousewheel` option off dynamically 2153 * https://github.com/cubiq/iscroll/issues/1036 2154 */ 2155 IScroll.prototype.wheelOn = function () { 2156 this.wrapper.addEventListener('wheel', this); 2157 this.wrapper.addEventListener('mousewheel', this); 2158 this.wrapper.addEventListener('DOMMouseScroll', this); 2159 }; 2160 2161 /* 2162 * Turns iScroll `mousewheel` option on dynamically 2163 * https://github.com/cubiq/iscroll/issues/1036 2164 */ 2165 IScroll.prototype.wheelOff = function () { 2166 this.wrapper.removeEventListener('wheel', this); 2167 this.wrapper.removeEventListener('mousewheel', this); 2168 this.wrapper.removeEventListener('DOMMouseScroll', this); 2169 }; 2170 } 2171 2172 /** 2173 * An object to handle overflow scrolling. 2174 * This uses jquery.slimScroll to accomplish overflow scrolling. 2175 * It is possible to pass in an alternate scrollOverflowHandler 2176 * to the fullpage.js option that implements the same functions 2177 * as this handler. 2178 * 2179 * @type {Object} 2180 */ 2181 window.iscrollHandler = { 2182 refreshId: null, 2183 iScrollInstances: [], 2184 2185 // Enables or disables the mouse wheel for the active section or all slides in it 2186 toggleWheel: function(value){ 2187 var scrollable = $(SECTION_ACTIVE_SEL).find(SCROLLABLE_SEL); 2188 scrollable.each(function(){ 2189 var iScrollInstance = $(this).data('iscrollInstance'); 2190 if(typeof iScrollInstance !== 'undefined' && iScrollInstance){ 2191 if(value){ 2192 iScrollInstance.wheelOn(); 2193 } 2194 else{ 2195 iScrollInstance.wheelOff(); 2196 } 2197 } 2198 }); 2199 }, 2200 2201 /** 2202 * Turns off iScroll for the destination section. 2203 * When scrolling very fast on some trackpads (and Apple laptops) the inertial scrolling would 2204 * scroll the destination section/slide before the sections animations ends. 2205 */ 2206 onLeave: function(){ 2207 iscrollHandler.toggleWheel(false); 2208 }, 2209 2210 // Turns off iScroll for the leaving section 2211 beforeLeave: function(){ 2212 iscrollHandler.onLeave() 2213 }, 2214 2215 // Turns on iScroll on section load 2216 afterLoad: function(){ 2217 iscrollHandler.toggleWheel(true); 2218 }, 2219 2220 /** 2221 * Called when overflow scrolling is needed for a section. 2222 * 2223 * @param {Object}
2223 element jQuery object containing current section 2224 * @param {Number} scrollHeight Current window height in pixels 2225 */ 2226 create: function(element, scrollHeight, scrollOverflowOptions) { 2227 var scrollable = element.find(SCROLLABLE_SEL); 2228 2229 scrollable.height(scrollHeight); 2230 scrollable.each(function() { 2231 var $this = $(this); 2232 var iScrollInstance = $this.data('iscrollInstance'); 2233 if (iScrollInstance) { 2234 $.each(iscrollHandler.iScrollInstances, function(){ 2235 $(this).destroy(); 2236 }); 2237 } 2238 2239 iScrollInstance = new IScroll($this.get(0), scrollOverflowOptions); 2240 2241 iScrollInstance.on('scrollEnd', function() { 2242 this['fp_isAtTop'] = this.y > -30; 2243 this['fp_isAtEnd'] = this.y - this.maxScrollY < 30; 2244 }); 2245 2246 iscrollHandler.iScrollInstances.push(iScrollInstance); 2247 2248 //off by default until the section gets active 2249 iScrollInstance.wheelOff(); 2250 2251 $this.data('iscrollInstance', iScrollInstance); 2252 }); 2253 }, 2254 2255 /** 2256 * Return a boolean depending on whether the scrollable element is a 2257 * the end or at the start of the scrolling depending on the given type. 2258 * 2259 * @param {String} type Either 'top' or 'bottom' 2260 * @param {Object} scrollable jQuery object for the scrollable element 2261 * @return {Boolean} 2262 */ 2263 isScrolled: function(type, scrollable) { 2264 var scroller = scrollable.data('iscrollInstance'); 2265 2266 //no scroller? 2267 if (!scroller) { 2268 return true; 2269 } 2270 2271 if (type === 'top') { 2272 return scroller.y >= 0 && !scrollable.scrollTop(); 2273 } else if (type === 'bottom') { 2274 return (0 - scroller.y) + scrollable.scrollTop() + 1 + scrollable.innerHeight() >= scrollable[0].scrollHeight; 2275 } 2276 }, 2277 2278 /** 2279 * Returns the scrollable element for the given section. 2280 * If there are landscape slides, will only return a scrollable element 2281 * if it is in the active slide. 2282 * 2283 * @param {Object} activeSection jQuery object containing current section 2284 * @return {Boolean} 2285 */ 2286 scrollable: function(activeSection){ 2287 // if there are landscape slides, we check if the scrolling bar is in the current one or not 2288 if (activeSection.find(SLIDES_WRAPPER_SEL).length) { 2289 return activeSection.find(SLIDE_ACTIVE_SEL).find(SCROLLABLE_SEL); 2290 } 2291 return activeSection.find(SCROLLABLE_SEL); 2292 }, 2293 2294 /** 2295 * Returns the scroll height of the wrapped content. 2296 * If this is larger than the window height minus section padding, 2297 * overflow scrolling is needed. 2298 * 2299 * @param {Object} element jQuery object containing current section 2300 * @return {Number} 2301 */ 2302 scrollHeight: function(element) { 2303 return element.find(SCROLLABLE_SEL).children().first().get(0).scrollHeight; 2304 }, 2305 2306 /** 2307 * Called when overflow scrolling is no longer needed for a section. 2308 * 2309 * @param {Object} element jQuery object containing current section 2310 */ 2311 remove: function(element) { 2312 var scrollable = element.find(SCROLLABLE_SEL); 2313 if (scrollable.length) { 2314 var iScrollInstance = scrollable.data('iscrollInstance'); 2315 if(iScrollInstance){ 2316 iScrollInstance.destroy(); 2317 } 2318 2319 scrollable.data('iscrollInstance', null); 2320 } 2321 element.find(SCROLLABLE_SEL).children().first().children().first().unwrap().unwrap(); 2322 }, 2323 2324 /** 2325 * Called when overflow scrolling has already been setup but the 2326 * window height has potentially changed. 2327 * 2328 * @param {Object}
2328 element jQuery object containing current section 2329 * @param {Number} scrollHeight Current window height in pixels 2330 */ 2331 update: function(element, scrollHeight) { 2332 //using a timeout in order to execute the refresh function only once when `update` is called multiple times in a 2333 //short period of time. 2334 //it also comes on handy because iScroll requires the use of timeout when using `refresh`. 2335 clearTimeout(iscrollHandler.refreshId); 2336 iscrollHandler.refreshId = setTimeout(function(){ 2337 $.each(iscrollHandler.iScrollInstances, function(){ 2338 $(this).get(0).refresh(); 2339 }); 2340 }, 150); 2341 2342 //updating the wrappers height 2343 element.find(SCROLLABLE_SEL).css('height', scrollHeight + 'px').parent().css('height', scrollHeight + 'px'); 2344 }, 2345 2346 /** 2347 * Called to get any additional elements needed to wrap the section 2348 * content in order to facilitate overflow scrolling. 2349 * 2350 * @return {String|Object} Can be a string containing HTML, 2351 * a DOM element, or jQuery object. 2352 */ 2353 wrapContent: function() { 2354 return '<div class="' + SCROLLABLE + '"><div class="fp-scroller"></div></div>'; 2355 } 2356 }; 2357})(window, jQuery); 2358 2359 2360// scrolloverflow module 2361(function (window, document, $) { 2362 $.fn.fp_scrolloverflow = (function() { 2363 2364 // keeping central set of classnames and selectors 2365 var SCROLLABLE = 'fp-scrollable'; 2366 var SCROLLABLE_SEL = '.' + SCROLLABLE; 2367 2368 var ACTIVE = 'active'; 2369 var ACTIVE_SEL = '.' + ACTIVE; 2370 2371 var SECTION = 'fp-section'; 2372 var SECTION_SEL = '.' + SECTION; 2373 var SECTION_ACTIVE_SEL = SECTION_SEL + ACTIVE_SEL; 2374 2375 var SLIDE = 'fp-slide'; 2376 var SLIDE_SEL = '.' + SLIDE; 2377 var SLIDE_ACTIVE_SEL = SLIDE_SEL + ACTIVE_SEL; 2378 2379 var SLIDES_WRAPPER = 'fp-slides'; 2380 var SLIDES_WRAPPER_SEL = '.' + SLIDES_WRAPPER; 2381 2382 var TABLE_CELL = 'fp-tableCell'; 2383 var TABLE_CELL_SEL = '.' + TABLE_CELL; 2384 2385 var RESPONSIVE = 'fp-responsive'; 2386 var AUTO_HEIGHT_RESPONSIVE= 'fp-auto-height-responsive'; 2387 2388 /* 2389 * Turns iScroll `mousewheel` option off dynamically 2390 * https://github.com/cubiq/iscroll/issues/1036 2391 */ 2392 IScroll.prototype.wheelOn = function () { 2393 this.wrapper.addEventListener('wheel', this); 2394 this.wrapper.addEventListener('mousewheel', this); 2395 this.wrapper.addEventListener('DOMMouseScroll', this); 2396 }; 2397 2398 /* 2399 * Turns iScroll `mousewheel` option on dynamically 2400 * https://github.com/cubiq/iscroll/issues/1036 2401 */ 2402 IScroll.prototype.wheelOff = function () { 2403 this.wrapper.removeEventListener('wheel', this); 2404 this.wrapper.removeEventListener('mousewheel', this); 2405 this.wrapper.removeEventListener('DOMMouseScroll', this); 2406 }; 2407 2408 2409 function scrollBarHandler(){ 2410 var self = this; 2411 self.options = null; 2412 2413 self.init = function(options, iscrollOptions){ 2414 self.options = options; 2415 self.iscrollOptions = iscrollOptions; 2416 2417 if(document.readyState === 'complete'){ 2418 createScrollBarForAll(); 2419 $.fn.fullpage.shared.afterRenderActions(); 2420 } 2421 //after DOM and images are loaded 2422 $(window).on('load', function(){ 2423 createScrollBarForAll(); 2424 $.fn.fullpage.shared.afterRenderActions(); 2425 }); 2426 2427 return self; 2428 }; 2429 2430 /** 2431 * Creates the scrollbar for the sections and slides in the site 2432 */ 2433 function createScrollBarForAll(){ 2434 if($('body').hasClass(RESPONSIVE)){ 2435 removeResponsiveScrollOverflows(); 2436 } 2437 else{
2438 forEachSectionAndSlide(createScrollBar); 2439 } 2440 } 2441 2442 /** 2443 * Returns an integer representing the padding dimensions in px. 2444 */ 2445 function getPaddings(element){ 2446 var section = element.closest(SECTION_SEL); 2447 if(section.length){ 2448 return parseInt(section.css('padding-bottom')) + parseInt(section.css('padding-top')); 2449 } 2450 return 0; 2451 } 2452 2453 /** 2454 * Checks if the element needs scrollbar and if the user wants to apply it. 2455 * If so it creates it. 2456 * 2457 * @param {Object} element jQuery object of the section or slide 2458 */ 2459 function createScrollBar(element){ 2460 //User doesn't want scrollbar here? Sayonara baby! 2461 if(element.hasClass('fp-noscroll')) return; 2462 2463 //necessary to make `scrollHeight` work under Opera 12 2464 element.css('overflow', 'hidden'); 2465 2466 var scrollOverflowHandler = self.options.scrollOverflowHandler; 2467 var wrap = scrollOverflowHandler.wrapContent(); 2468 var section = element.closest(SECTION_SEL); //in case element is a slide 2469 var scrollable = scrollOverflowHandler.scrollable(element); 2470 var contentHeight; 2471 var paddings = getPaddings(section); 2472 2473 //if there was scroll, the contentHeight will be the one in the scrollable section 2474 if(scrollable.length){ 2475 contentHeight = scrollOverflowHandler.scrollHeight(element); 2476 } 2477 else{ 2478 contentHeight = element.get(0).scrollHeight - paddings; 2479 if(self.options.verticalCentered){ 2480 contentHeight = element.find(TABLE_CELL_SEL).get(0).scrollHeight - paddings; 2481 } 2482 } 2483 2484 var scrollHeight = $(window).height() - paddings; 2485 2486 //needs scroll? 2487 if ( contentHeight > scrollHeight) { 2488 //did we already have an scrollbar ? Updating it 2489 if(scrollable.length){ 2490 scrollOverflowHandler.update(element, scrollHeight); 2491 } 2492 //creating the scrolling 2493 else{ 2494 if(self.options.verticalCentered){ 2495 element.find(TABLE_CELL_SEL).wrapInner(wrap); 2496 }else{ 2497 element.wrapInner(wrap); 2498 } 2499 scrollOverflowHandler.create(element, scrollHeight, self.iscrollOptions); 2500 } 2501 } 2502 //removing the scrolling when it is not necessary anymore 2503 else{ 2504 scrollOverflowHandler.remove(element); 2505 } 2506 2507 //undo 2508 element.css('overflow', ''); 2509 } 2510 2511 /** 2512 * Applies a callback function to each section in the site 2513 * or the slides within them 2514 */ 2515 function forEachSectionAndSlide(callback){ 2516 $(SECTION_SEL).each(function(){ 2517 var slides = $(this).find(SLIDE_SEL); 2518 2519 if(slides.length){ 2520 slides.each(function(){ 2521 callback($(this)); 2522 }); 2523 }else{ 2524 callback($(this)); 2525 } 2526 }); 2527 } 2528 2529 /** 2530 * Removes scrollOverflow for sections using the class `fp-auto-height-responsive` 2531 */ 2532 function removeResponsiveScrollOverflows(){ 2533 var scrollOverflowHandler = self.options.scrollOverflowHandler; 2534 forEachSectionAndSlide(function(element){ 2535 if(element.closest(SECTION_SEL).hasClass(AUTO_HEIGHT_RESPONSIVE)){ 2536 scrollOverflowHandler.remove(element); 2537 } 2538 }); 2539 } 2540 2541 //public functions 2542 self.createScrollBarForAll = createScrollBarForAll; 2543 } 2544 2545 /** 2546 * An object to handle overflow scrolling. 2547 * This uses jquery.slimScroll to accomplish overflow scrolling. 2548 * It is possible to pass in an alternate scrollOverflowHandler 2549 * to the fullpage.js option that implements the same functions 2550 * as this handler. 2551 * 2552 * @type {Object} 2553 */ 2554 var iscrollHandler = { 2555 refreshId: null, 2556 iScrollInstances: [], 2557 2558 // Default options for iScroll.js used when using scrollOverflow 2559 iscrollOptions: { 2560 scrollbars: true, 2561 mouseWheel: true, 2562 hideScrollbars: false, 2563 fadeScrollbars: false, 2564 disableMouse: true, 2565 interactiveScrollbars: true 2566 }, 2567 2568 init: function(options){ 2569 var isTouch = (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0) || (navigator.maxTouchPoints)); 2570 2571 //fixing bug in iScroll with links: https://github.com/cubiq/iscroll/issues/783 2572 iscrollHandler.iscrollOptions.click = isTouch; // see #2035 2573 2574 //extending iScroll options with the user custom ones 2575 iscrollHandler.iscrollOptions = $.extend(iscrollHandler.iscrollOptions, options.scrollOverflowOptions); 2576 2577 return new scrollBarHandler().init(options, iscrollHandler.iscrollOptions); 2578 }, 2579 2580 // Enables or disables the mouse wheel for the active section or all slides in it 2581 toggleWheel: function(value){ 2582 var scrollable = $(SECTION_ACTIVE_SEL).find(SCROLLABLE_SEL); 2583 scrollable.each(function(){ 2584 var iScrollInstance = $(this).data('iscrollInstance'); 2585 if(typeof iScrollInstance !== 'undefined' && iScrollInstance){ 2586 if(value){ 2587 iScrollInstance.wheelOn(); 2588 } 2589 else{ 2590 iScrollInstance.wheelOff(); 2591 } 2592 } 2593 }); 2594 }, 2595 2596 /** 2597 * Turns off iScroll for the destination section. 2598 * When scrolling very fast on some trackpads (and Apple laptops) the inertial scrolling would
2599 * scroll the destination section/slide before the sections animations ends. 2600 */ 2601 onLeave: function(){ 2602 iscrollHandler.toggleWheel(false); 2603 }, 2604 2605 // Turns off iScroll for the leaving section 2606 beforeLeave: function(){ 2607 iscrollHandler.onLeave() 2608 }, 2609 2610 // Turns on iScroll on section load 2611 afterLoad: function(){ 2612 iscrollHandler.toggleWheel(true); 2613 }, 2614 2615 /** 2616 * Called when overflow scrolling is needed for a section. 2617 * 2618 * @param {Object} element jQuery object containing current section 2619 * @param {Number} scrollHeight Current window height in pixels 2620 */ 2621 create: function(element, scrollHeight, iscrollOptions) { 2622 var scrollable = element.find(SCROLLABLE_SEL); 2623 2624 scrollable.height(scrollHeight); 2625 scrollable.each(function() { 2626 var $this = $(this); 2627 var iScrollInstance = $this.data('iscrollInstance'); 2628 if (iScrollInstance) { 2629 $.each(iscrollHandler.iScrollInstances, function(){ 2630 $(this).destroy(); 2631 }); 2632 } 2633 2634 iScrollInstance = new IScroll($this.get(0), iscrollOptions); 2635 iscrollHandler.iScrollInstances.push(iScrollInstance); 2636 2637 //off by default until the section gets active 2638 iScrollInstance.wheelOff(); 2639 2640 $this.data('iscrollInstance', iScrollInstance); 2641 }); 2642 }, 2643 2644 /** 2645 * Return a boolean depending on whether the scrollable element is a 2646 * the end or at the start of the scrolling depending on the given type. 2647 * 2648 * @param {String} type Either 'top' or 'bottom' 2649 * @param {Object} scrollable jQuery object for the scrollable element 2650 * @return {Boolean} 2651 */ 2652 isScrolled: function(type, scrollable) { 2653 var scroller = scrollable.data('iscrollInstance'); 2654 2655 //no scroller? 2656 if (!scroller) { 2657 return true; 2658 } 2659 2660 if (type === 'top') { 2661 return scroller.y >= 0 && !scrollable.scrollTop(); 2662 } else if (type === 'bottom') { 2663 return (0 - scroller.y) + scrollable.scrollTop() + 1 + scrollable.innerHeight() >= scrollable[0].scrollHeight; 2664 } 2665 }, 2666 2667 /** 2668 * Returns the scrollable element for the given section. 2669 * If there are landscape slides, will only return a scrollable element 2670 * if it is in the active slide. 2671 * 2672 * @param {Object} activeSection jQuery object containing current section 2673 * @return {Boolean} 2674 */ 2675 scrollable: function(activeSection){ 2676 // if there are landscape slides, we check if the scrolling bar is in the current one or not 2677 if (activeSection.find(SLIDES_WRAPPER_SEL).length) { 2678 return activeSection.find(SLIDE_ACTIVE_SEL).find(SCROLLABLE_SEL); 2679 } 2680 return activeSection.find(SCROLLABLE_SEL); 2681 }, 2682 2683 /** 2684 * Returns the scroll height of the wrapped content. 2685 * If this is larger than the window height minus section padding, 2686 * overflow scrolling is needed. 2687 * 2688 * @param {Object} element jQuery object containing current section 2689 * @return {Number} 2690 */ 2691 scrollHeight: function(element) { 2692 return element.find(SCROLLABLE_SEL).children().first().get(0).scrollHeight; 2693 }, 2694 2695 /** 2696 * Called when overflow scrolling is no longer needed for a section. 2697 * 2698 * @param {Object}
2698 element jQuery object containing current section 2699 */ 2700 remove: function(element) { 2701 var scrollable = element.find(SCROLLABLE_SEL); 2702 if (scrollable.length) { 2703 var iScrollInstance = scrollable.data('iscrollInstance'); 2704 iScrollInstance.destroy(); 2705 2706 scrollable.data('iscrollInstance', null); 2707 } 2708 element.find(SCROLLABLE_SEL).children().first().children().first().unwrap().unwrap(); 2709 }, 2710 2711 /** 2712 * Called when overflow scrolling has already been setup but the 2713 * window height has potentially changed. 2714 * 2715 * @param {Object} element jQuery object containing current section 2716 * @param {Number} scrollHeight Current window height in pixels 2717 */ 2718 update: function(element, scrollHeight) { 2719 //using a timeout in order to execute the refresh function only once when `update` is called multiple times in a 2720 //short period of time. 2721 //it also comes on handy because iScroll requires the use of timeout when using `refresh`. 2722 clearTimeout(iscrollHandler.refreshId); 2723 iscrollHandler.refreshId = setTimeout(function(){ 2724 $.each(iscrollHandler.iScrollInstances, function(){ 2725 $(this).get(0).refresh(); 2726 2727 //ugly hack that we are forced to use due to the timeout delay 2728 //otherwise done on the fullpage.js reBuild function 2729 $.fn.fullpage.silentMoveTo($(SECTION_ACTIVE_SEL).index() + 1); 2730 }); 2731 }, 150); 2732 2733 //updating the wrappers height 2734 element.find(SCROLLABLE_SEL) 2735 .css('height', scrollHeight + 'px'); 2736 //.parent().css('height', scrollHeight + getPaddings(element) + 'px'); 2737 }, 2738 2739 /** 2740 * Called to get any additional elements needed to wrap the section 2741 * content in order to facilitate overflow scrolling. 2742 * 2743 * @return {String|Object} Can be a string containing HTML, 2744 * a DOM element, or jQuery object. 2745 */ 2746 wrapContent: function() { 2747 return '<div class="' + SCROLLABLE + '"><div class="fp-scroller"></div></div>'; 2748 } 2749 }; 2750 2751 return { 2752 iscrollHandler: iscrollHandler 2753 }; 2754 })(); 2755})(window, document, jQuery);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.