1/*! nanoScrollerJS - v0.8.7 - 2015 2* http://jamesflorentino.github.com/nanoScrollerJS/ 3* Copyright (c) 2015 James Florentino; Licensed MIT */ 4(function(factory) { 5 if (typeof define === 'function' && define.amd) { 6 return define(['jquery'], function($) { 7 return factory($, window, document); 8 }); 9 } else if (typeof exports === 'object') { 10 return module.exports = factory(require('jquery'), window, document); 11 } else { 12 return factory(jQuery, window, document); 13 } 14})(function($, window, document) { 15 "use strict"; 16 var BROWSER_IS_IE7, BROWSER_SCROLLBAR_WIDTH, DOMSCROLL, DOWN, DRAG, ENTER, KEYDOWN, KEYUP, MOUSEDOWN, MOUSEENTER, MOUSEMOVE, MOUSEUP, MOUSEWHEEL, NanoScroll, PANEDOWN, RESIZE, SCROLL, SCROLLBAR, TOUCHMOVE, UP, WHEEL, cAF, defaults, getBrowserScrollbarWidth, hasTransform, isFFWithBuggyScrollbar, rAF, transform, _elementStyle, _prefixStyle, _vendor; 17 defaults = { 18 19 /** 20 a classname for the pane element. 21 @property paneClass 22 @type String 23 @default 'nano-pane' 24 */ 25 paneClass: 'nano-pane', 26 27 /** 28 a classname for the slider element. 29 @property sliderClass 30 @type String 31 @default 'nano-slider' 32 */ 33 sliderClass: 'nano-slider', 34 35 /** 36 a classname for the content element. 37 @property contentClass 38 @type String 39 @default 'nano-content' 40 */ 41 contentClass: 'nano-content', 42 43 /** 44 a classname for enabled mode 45 @property enabledClass 46 @type String 47 @default 'has-scrollbar' 48 */ 49 enabledClass: 'has-scrollbar', 50 51 /** 52 a classname for flashed mode 53 @property flashedClass 54 @type String 55 @default 'flashed' 56 */ 57 flashedClass: 'flashed', 58 59 /** 60 a classname for active mode 61 @property activeClass 62 @type String 63 @default 'active' 64 */ 65 activeClass: 'active', 66 67 /** 68 a setting to enable native scrolling in iOS devices. 69 @property iOSNativeScrolling 70 @type Boolean 71 @default false 72 */ 73 iOSNativeScrolling: false, 74 75 /** 76 a setting to prevent the rest of the page being 77 scrolled when user scrolls the `.content` element. 78 @property preventPageScrolling 79 @type Boolean 80 @default false 81 */ 82 preventPageScrolling: false, 83 84 /** 85 a setting to disable binding to the resize event. 86 @property disableResize 87 @type Boolean 88 @default false 89 */ 90 disableResize: false, 91 92 /** 93 a setting to make the scrollbar always visible. 94 @property alwaysVisible 95 @type Boolean 96 @default false 97 */ 98 alwaysVisible: false, 99 100 /** 101 a default timeout for the `flash()` method. 102 @property flashDelay 103 @type Number 104 @default 1500 105 */ 106 flashDelay: 1500, 107 108 /** 109 a minimum height for the `.slider` element. 110 @property sliderMinHeight 111 @type Number 112 @default 20 113 */ 114 sliderMinHeight: 20, 115 116 /** 117 a maximum height for the `.slider` element. 118 @property sliderMaxHeight 119 @type Number 120 @default null 121 */ 122 sliderMaxHeight: null, 123 124 /** 125 an alternate document context. 126 @property documentContext 127 @type Document 128 @default null 129 */ 130 documentContext: null, 131 132 /** 133 an alternate window context. 134 @property windowContext 135 @type Window 136 @default null 137 */ 138 windowContext: null 139 }; 140 141 /** 142 @property SCROLLBAR 143 @type String 144 @static 145 @final 146 @private 147 */ 148 SCROLLBAR = 'scrollbar'; 149 150 /** 151 @property SCROLL 152 @type String 153 @static 154 @final 155 @private 156 */ 157 SCROLL = 'scroll'; 158 159 /** 160 @property MOUSEDOWN 161 @type String 162 @final 163 @private 164 */ 165 MOUSEDOWN = 'mousedown'; 166 167 /** 168 @property MOUSEENTER 169 @type String 170 @final 171 @private 172 */ 173 MOUSEENTER = 'mouseenter'; 174 175 /** 176 @property MOUSEMOVE 177 @type String 178 @static 179 @final 180 @private 181 */ 182 MOUSEMOVE = 'mousemove'; 183 184 /** 185 @property MOUSEWHEEL 186 @type String 187 @final 188 @private 189 */ 190 MOUSEWHEEL = 'mousewheel'; 191 192 /** 193 @property MOUSEUP
194 @type String 195 @static 196 @final 197 @private 198 */ 199 MOUSEUP = 'mouseup'; 200 201 /** 202 @property RESIZE 203 @type String 204 @final 205 @private 206 */ 207 RESIZE = 'resize'; 208 209 /** 210 @property DRAG 211 @type String 212 @static 213 @final 214 @private 215 */ 216 DRAG = 'drag'; 217 218 /** 219 @property ENTER 220 @type String 221 @static 222 @final 223 @private 224 */ 225 ENTER = 'enter'; 226 227 /** 228 @property UP 229 @type String 230 @static 231 @final 232 @private 233 */ 234 UP = 'up'; 235 236 /** 237 @property PANEDOWN 238 @type String 239 @static 240 @final 241 @private 242 */ 243 PANEDOWN = 'panedown'; 244 245 /** 246 @property DOMSCROLL 247 @type String 248 @static 249 @final 250 @private 251 */ 252 DOMSCROLL = 'DOMMouseScroll'; 253 254 /** 255 @property DOWN 256 @type String 257 @static 258 @final 259 @private 260 */ 261 DOWN = 'down'; 262 263 /** 264 @property WHEEL 265 @type String 266 @static 267 @final 268 @private 269 */ 270 WHEEL = 'wheel'; 271 272 /** 273 @property KEYDOWN 274 @type String 275 @static 276 @final 277 @private 278 */ 279 KEYDOWN = 'keydown'; 280 281 /** 282 @property KEYUP 283 @type String 284 @static 285 @final 286 @private 287 */ 288 KEYUP = 'keyup'; 289 290 /** 291 @property TOUCHMOVE 292 @type String 293 @static 294 @final 295 @private 296 */ 297 TOUCHMOVE = 'touchmove'; 298 299 /** 300 @property BROWSER_IS_IE7 301 @type Boolean 302 @static 303 @final 304 @private 305 */ 306 BROWSER_IS_IE7 = window.navigator.appName === 'Microsoft Internet Explorer' && /msie 7./i.test(window.navigator.appVersion) && window.ActiveXObject; 307 308 /** 309 @property BROWSER_SCROLLBAR_WIDTH 310 @type Number 311 @static 312 @default null 313 @private 314 */ 315 BROWSER_SCROLLBAR_WIDTH = null;
316 rAF = window.requestAnimationFrame; 317 cAF = window.cancelAnimationFrame; 318 _elementStyle = document.createElement('div').style; 319 _vendor = (function() { 320 var i, transform, vendor, vendors, _i, _len; 321 vendors = ['t', 'webkitT', 'MozT', 'msT', 'OT']; 322 for (i = _i = 0, _len = vendors.length; _i < _len; i = ++_i) { 323 vendor = vendors[i]; 324 transform = vendors[i] + 'ransform'; 325 if (transform in _elementStyle) { 326 return vendors[i].substr(0, vendors[i].length - 1); 327 } 328 } 329 return false; 330 })(); 331 _prefixStyle = function(style) { 332 if (_vendor === false) { 333 return false; 334 } 335 if (_vendor === '') { 336 return style; 337 } 338 return _vendor + style.charAt(0).toUpperCase() + style.substr(1); 339 }; 340 transform = _prefixStyle('transform'); 341 hasTransform = transform !== false; 342 343 /** 344 Returns browser's native scrollbar width 345 @method getBrowserScrollbarWidth 346 @return {Number} the scrollbar width in pixels 347 @static 348 @private 349 */ 350 getBrowserScrollbarWidth = function() { 351 var outer, outerStyle, scrollbarWidth; 352 outer = document.createElement('div'); 353 outerStyle = outer.style; 354 outerStyle.position = 'absolute'; 355 outerStyle.width = '100px'; 356 outerStyle.height = '100px'; 357 outerStyle.overflow = SCROLL; 358 outerStyle.top = '-9999px'; 359 document.body.appendChild(outer); 360 scrollbarWidth = outer.offsetWidth - outer.clientWidth; 361 document.body.removeChild(outer); 362 return scrollbarWidth; 363 }; 364 isFFWithBuggyScrollbar = function() { 365 var isOSXFF, ua, version; 366 ua = window.navigator.userAgent; 367 isOSXFF = /(?=.+Mac OS X)(?=.+Firefox)/.test(ua); 368 if (!isOSXFF) { 369 return false; 370 } 371 version = /Firefox\/\d{2}\./.exec(ua); 372 if (version) { 373 version = version[0].replace(/\D+/g, ''); 374 } 375 return isOSXFF && +version > 23; 376 }; 377 378 /** 379 @class NanoScroll 380 @param element {HTMLElement|Node} the main element 381 @param options {Object} nanoScroller's options 382 @constructor 383 */ 384 NanoScroll = (function() { 385 function NanoScroll(el, options) { 386 this.el = el; 387 this.options = options; 388 BROWSER_SCROLLBAR_WIDTH || (BROWSER_SCROLLBAR_WIDTH = getBrowserScrollbarWidth()); 389 this.$el = $(this.el); 390 this.doc = $(this.options.documentContext || document); 391 this.win = $(this.options.windowContext || window); 392 this.body = this.doc.find('body'); 393 this.$content = this.$el.children("." + this.options.contentClass); 394 this.$content.attr('tabindex', this.options.tabIndex || 0); 395 this.content = this.$content[0]; 396 this.previousPosition = 0; 397 if (this.options.iOSNativeScrolling && (this.el.style.WebkitOverflowScrolling != null)) { 398 this.nativeScrolling(); 399 } else { 400 this.generate(); 401 } 402 this.createEvents(); 403 this.addEvents(); 404 this.reset(); 405 } 406 407 408 /** 409 Prevents the rest of the page being scrolled 410 when user scrolls the `.nano-content` element. 411 @method preventScrolling 412 @param event {Event} 413 @param direction {String} Scroll direction (up or down) 414 @private 415 */ 416 417 NanoScroll.prototype.preventScrolling = function(e, direction) { 418 if (!this.isActive) { 419 return; 420 } 421 if (e.type === DOMSCROLL) { 422 if (direction === DOWN && e.originalEvent.detail > 0 || direction === UP && e.originalEvent.detail < 0) { 423 e.preventDefault(); 424 } 425 } else if (e.type === MOUSEWHEEL) { 426 if (!e.originalEvent || !e.originalEvent.wheelDelta) { 427 return; 428 } 429 if (direction === DOWN && e.originalEvent.wheelDelta < 0 || direction === UP && e.originalEvent.wheelDelta > 0) { 430 e.preventDefault(); 431 } 432 } 433 }; 434 435 436 /** 437 Enable iOS native scrolling
438 @method nativeScrolling 439 @private 440 */ 441 442 NanoScroll.prototype.nativeScrolling = function() { 443 this.$content.css({ 444 WebkitOverflowScrolling: 'touch' 445 }); 446 this.iOSNativeScrolling = true; 447 this.isActive = true; 448 }; 449 450 451 /** 452 Updates those nanoScroller properties that 453 are related to current scrollbar position. 454 @method updateScrollValues 455 @private 456 */ 457 458 NanoScroll.prototype.updateScrollValues = function() { 459 var content, direction; 460 content = this.content; 461 this.maxScrollTop = content.scrollHeight - content.clientHeight; 462 this.prevScrollTop = this.contentScrollTop || 0; 463 this.contentScrollTop = content.scrollTop; 464 direction = this.contentScrollTop > this.previousPosition ? "down" : this.contentScrollTop < this.previousPosition ? "up" : "same"; 465 this.previousPosition = this.contentScrollTop; 466 if (direction !== "same") { 467 this.$el.trigger('update', { 468 position: this.contentScrollTop, 469 maximum: this.maxScrollTop, 470 direction: direction 471 }); 472 } 473 if (!this.iOSNativeScrolling) { 474 this.maxSliderTop = this.paneHeight - this.sliderHeight; 475 this.sliderTop = this.maxScrollTop === 0 ? 0 : this.contentScrollTop * this.maxSliderTop / this.maxScrollTop; 476 } 477 }; 478 479 480 /** 481 Updates CSS styles for current scroll position. 482 Uses CSS 2d transfroms and `window.requestAnimationFrame` if available. 483 @method setOnScrollStyles 484 @private 485 */ 486 487 NanoScroll.prototype.setOnScrollStyles = function() { 488 var cssValue; 489 if (hasTransform) { 490 cssValue = {}; 491 cssValue[transform] = "translate(0, " + this.sliderTop + "px)"; 492 } else { 493 cssValue = { 494 top: this.sliderTop 495 }; 496 } 497 if (rAF) { 498 if (cAF && this.scrollRAF) { 499 cAF(this.scrollRAF); 500 } 501 this.scrollRAF = rAF((function(_this) { 502 return function() { 503 _this.scrollRAF = null; 504 return _this.slider.css(cssValue); 505 }; 506 })(this)); 507 } else { 508 this.slider.css(cssValue); 509 } 510 }; 511 512 513 /** 514 Creates event related methods 515 @method createEvents 516 @private 517 */ 518 519 NanoScroll.prototype.createEvents = function() { 520 this.events = { 521 down: (function(_this) { 522 return function(e) { 523 _this.isBeingDragged = true; 524 _this.offsetY = e.pageY - _this.slider.offset().top; 525 if (!_this.slider.is(e.target)) { 526 _this.offsetY = 0; 527 } 528 _this.pane.addClass(_this.options.activeClass); 529 _this.doc.bind(MOUSEMOVE, _this.events[DRAG]).bind(MOUSEUP, _this.events[UP]); 530 _this.body.bind(MOUSEENTER, _this.events[ENTER]); 531 return false; 532 }; 533 })(this), 534 drag: (function(_this) { 535 return function(e) { 536 _this.sliderY = e.pageY - _this.$el.offset().top - _this.paneTop - (_this.offsetY || _this.sliderHeight * 0.5); 537 _this.scroll(); 538 if (_this.contentScrollTop >= _this.maxScrollTop && _this.prevScrollTop !== _this.maxScrollTop) { 539 _this.$el.trigger('scrollend'); 540 } else if (_this.contentScrollTop === 0 && _this.prevScrollTop !== 0) { 541 _this.$el.trigger('scrolltop'); 542 } 543 return false; 544 }; 545 })(this), 546 up: (function(_this) { 547 return function(e) { 548 _this.isBeingDragged = false; 549 _this.pane.removeClass(_this.options.activeClass); 550 _this.doc.unbind(MOUSEMOVE, _this.events[DRAG]).unbind(MOUSEUP, _this.events[UP]); 551 _this.body.unbind(MOUSEENTER, _this.events[ENTER]); 552 return false; 553 }; 554 })(this), 555 resize: (function(_this) { 556 return function(e) { 557 _this.reset(); 558 }; 559 })(this), 560 panedown: (function(_this) { 561 return function(e) { 562 _this.sliderY = (e.offsetY || e.originalEvent.layerY) - (_this.sliderHeight * 0.5); 563 _this.scroll(); 564 _this.events.down(e); 565 return false;
566 }; 567 })(this), 568 scroll: (function(_this) { 569 return function(e) { 570 _this.updateScrollValues(); 571 if (_this.isBeingDragged) { 572 return; 573 } 574 if (!_this.iOSNativeScrolling) { 575 _this.sliderY = _this.sliderTop; 576 _this.setOnScrollStyles(); 577 } 578 if (e == null) { 579 return; 580 } 581 if (_this.contentScrollTop >= _this.maxScrollTop) { 582 if (_this.options.preventPageScrolling) { 583 _this.preventScrolling(e, DOWN); 584 } 585 if (_this.prevScrollTop !== _this.maxScrollTop) { 586 _this.$el.trigger('scrollend'); 587 } 588 } else if (_this.contentScrollTop === 0) { 589 if (_this.options.preventPageScrolling) { 590 _this.preventScrolling(e, UP); 591 } 592 if (_this.prevScrollTop !== 0) { 593 _this.$el.trigger('scrolltop'); 594 } 595 } 596 }; 597 })(this), 598 wheel: (function(_this) { 599 return function(e) { 600 var delta; 601 if (e == null) { 602 return; 603 } 604 delta = e.delta || e.wheelDelta || (e.originalEvent && e.originalEvent.wheelDelta) || -e.detail || (e.originalEvent && -e.originalEvent.detail); 605 if (delta) { 606 _this.sliderY += -delta / 3; 607 } 608 _this.scroll(); 609 return false; 610 }; 611 })(this), 612 enter: (function(_this) { 613 return function(e) { 614 var _ref; 615 if (!_this.isBeingDragged) { 616 return; 617 } 618 if ((e.buttons || e.which) !== 1) { 619 return (_ref = _this.events)[UP].apply(_ref, arguments); 620 } 621 }; 622 })(this) 623 }; 624 }; 625 626 627 /** 628 Adds event listeners with jQuery. 629 @method addEvents 630 @private 631 */ 632 633 NanoScroll.prototype.addEvents = function() { 634 var events; 635 this.removeEvents(); 636 events = this.events; 637 if (!this.options.disableResize) { 638 this.win.bind(RESIZE, events[RESIZE]); 639 } 640 if (!this.iOSNativeScrolling) { 641 this.slider.bind(MOUSEDOWN, events[DOWN]); 642 this.pane.bind(MOUSEDOWN, events[PANEDOWN]).bind("" + MOUSEWHEEL + " " + DOMSCROLL, events[WHEEL]); 643 } 644 this.$content.bind("" + SCROLL + " " + MOUSEWHEEL + " " + DOMSCROLL + " " + TOUCHMOVE, events[SCROLL]); 645 }; 646 647 648 /** 649 Removes event listeners with jQuery. 650 @method removeEvents 651 @private 652 */ 653 654 NanoScroll.prototype.removeEvents = function() { 655 var events; 656 events = this.events; 657 this.win.unbind(RESIZE, events[RESIZE]); 658 if (!this.iOSNativeScrolling) { 659 this.slider.unbind(); 660 this.pane.unbind(); 661 } 662 this.$content.unbind("" + SCROLL + " " + MOUSEWHEEL + " " + DOMSCROLL + " " + TOUCHMOVE, events[SCROLL]); 663 }; 664 665 666 /** 667 Generates nanoScroller's scrollbar and elements for it. 668 @method generate 669 @chainable 670 @private 671 */ 672 673 NanoScroll.prototype.generate = function() { 674 var contentClass, cssRule, currentPadding, options, pane, paneClass, sliderClass; 675 options = this.options; 676 paneClass = options.paneClass, sliderClass = options.sliderClass, contentClass = options.contentClass; 677 if (!(pane = this.$el.children("." + paneClass)).length && !pane.children("." + sliderClass).length) { 678 this.$el.append("<div class=\"" + paneClass + "\"><div class=\"" + sliderClass + "\" /></div>"); 679 } 680 this.pane = this.$el.children("." + paneClass); 681 this.slider = this.pane.find("." + sliderClass); 682 if (BROWSER_SCROLLBAR_WIDTH === 0 && isFFWithBuggyScrollbar()) { 683 currentPadding = window.getComputedStyle(this.content, null).getPropertyValue('padding-right').replace(/[^0-9.]+/g, ''); 684 cssRule = { 685 right: -14, 686 paddingRight: +currentPadding + 14 687 }; 688 } else if (BROWSER_SCROLLBAR_WIDTH) { 689 cssRule = { 690 right: -BROWSER_SCROLLBAR_WIDTH 691 }; 692 this.$el.addClass(options.enabledClass); 693 } 694 if (cssRule != null) { 695 this.$content.css(cssRule); 696 } 697 return this; 698 }; 699 700 701 /** 702 @method restore 703 @private 704 */ 705 706 NanoScroll.prototype.restore = function() { 707 this.stopped = false;
708 if (!this.iOSNativeScrolling) { 709 this.pane.show(); 710 } 711 this.addEvents(); 712 }; 713 714 715 /** 716 Resets nanoScroller's scrollbar. 717 @method reset 718 @chainable 719 @example 720 $(".nano").nanoScroller(); 721 */ 722 723 NanoScroll.prototype.reset = function() { 724 var content, contentHeight, contentPosition, contentStyle, contentStyleOverflowY, paneBottom, paneHeight, paneOuterHeight, paneTop, parentMaxHeight, right, sliderHeight; 725 if (this.iOSNativeScrolling) { 726 this.contentHeight = this.content.scrollHeight; 727 return; 728 } 729 if (!this.$el.find("." + this.options.paneClass).length) { 730 this.generate().stop(); 731 } 732 if (this.stopped) { 733 this.restore(); 734 } 735 content = this.content; 736 contentStyle = content.style; 737 contentStyleOverflowY = contentStyle.overflowY; 738 if (BROWSER_IS_IE7) { 739 this.$content.css({ 740 height: this.$content.height() 741 }); 742 } 743 contentHeight = content.scrollHeight + BROWSER_SCROLLBAR_WIDTH; 744 parentMaxHeight = parseInt(this.$el.css("max-height"), 10); 745 if (parentMaxHeight > 0) { 746 this.$el.height(""); 747 this.$el.height(content.scrollHeight > parentMaxHeight ? parentMaxHeight : content.scrollHeight); 748 } 749 paneHeight = this.pane.outerHeight(false); 750 paneTop = parseInt(this.pane.css('top'), 10); 751 paneBottom = parseInt(this.pane.css('bottom'), 10); 752 paneOuterHeight = paneHeight + paneTop + paneBottom; 753 sliderHeight = Math.round(paneOuterHeight / contentHeight * paneHeight); 754 if (sliderHeight < this.options.sliderMinHeight) { 755 sliderHeight = this.options.sliderMinHeight; 756 } else if ((this.options.sliderMaxHeight != null) && sliderHeight > this.options.sliderMaxHeight) { 757 sliderHeight = this.options.sliderMaxHeight; 758 } 759 if (contentStyleOverflowY === SCROLL && contentStyle.overflowX !== SCROLL) { 760 sliderHeight += BROWSER_SCROLLBAR_WIDTH; 761 } 762 this.maxSliderTop = paneOuterHeight - sliderHeight; 763 this.contentHeight = contentHeight; 764 this.paneHeight = paneHeight; 765 this.paneOuterHeight = paneOuterHeight; 766 this.sliderHeight = sliderHeight; 767 this.paneTop = paneTop; 768 this.slider.height(sliderHeight); 769 this.events.scroll(); 770 this.pane.show(); 771 this.isActive = true; 772 if ((content.scrollHeight === content.clientHeight) || (this.pane.outerHeight(true) >= content.scrollHeight && contentStyleOverflowY !== SCROLL)) { 773 this.pane.hide(); 774 this.isActive = false; 775 } else if (this.el.clientHeight === content.scrollHeight && contentStyleOverflowY === SCROLL) { 776 this.slider.hide(); 777 } else { 778 this.slider.show(); 779 } 780 this.pane.css({ 781 opacity: (this.options.alwaysVisible ? 1 : ''), 782 visibility: (this.options.alwaysVisible ? 'visible' : '') 783 }); 784 contentPosition = this.$content.css('position'); 785 if (contentPosition === 'static' || contentPosition === 'relative') { 786 right = parseInt(this.$content.css('right'), 10); 787 if (right) { 788 this.$content.css({ 789 right: '', 790 marginRight: right 791 }); 792 } 793 } 794 return this; 795 }; 796 797 798 /** 799 @method scroll 800 @private 801 @example 802 $(".nano").nanoScroller({ scroll: 'top' }); 803 */ 804 805 NanoScroll.prototype.scroll = function() { 806 if (!this.isActive) { 807 return; 808 } 809 this.sliderY = Math.max(0, this.sliderY); 810 this.sliderY = Math.min(this.maxSliderTop, this.sliderY); 811 this.$content.scrollTop(this.maxScrollTop * this.sliderY / this.maxSliderTop); 812 if (!this.iOSNativeScrolling) { 813 this.updateScrollValues(); 814 this.setOnScrollStyles(); 815 } 816 return this; 817 }; 818 819 820 /** 821 Scroll at the bottom with an offset value 822 @method scrollBottom 823 @param offsetY {Number} 824 @chainable 825 @example 826 $(".nano").nanoScroller({ scrollBottom: value }); 827 */ 828 829 NanoScroll.prototype.scrollBottom = function(offsetY) { 830 if (!this.isActive) { 831 return; 832 } 833 this.$content.scrollTop(this.contentHeight - this.$content.height() - offsetY).trigger(MOUSEWHEEL);
834 this.stop().restore(); 835 return this; 836 }; 837 838 839 /** 840 Scroll at the top with an offset value 841 @method scrollTop 842 @param offsetY {Number} 843 @chainable 844 @example 845 $(".nano").nanoScroller({ scrollTop: value }); 846 */ 847 848 NanoScroll.prototype.scrollTop = function(offsetY) { 849 if (!this.isActive) { 850 return; 851 } 852 this.$content.scrollTop(+offsetY).trigger(MOUSEWHEEL); 853 this.stop().restore(); 854 return this; 855 }; 856 857 858 /** 859 Scroll to an element 860 @method scrollTo 861 @param node {Node} A node to scroll to. 862 @chainable 863 @example 864 $(".nano").nanoScroller({ scrollTo: $('#a_node') }); 865 */ 866 867 NanoScroll.prototype.scrollTo = function(node) { 868 if (!this.isActive) { 869 return; 870 } 871 this.scrollTop(this.$el.find(node).get(0).offsetTop); 872 return this; 873 }; 874 875 876 /** 877 To stop the operation. 878 This option will tell the plugin to disable all event bindings and hide the gadget scrollbar from the UI. 879 @method stop 880 @chainable 881 @example 882 $(".nano").nanoScroller({ stop: true }); 883 */ 884 885 NanoScroll.prototype.stop = function() { 886 if (cAF && this.scrollRAF) { 887 cAF(this.scrollRAF); 888 this.scrollRAF = null; 889 } 890 this.stopped = true; 891 this.removeEvents(); 892 if (!this.iOSNativeScrolling) { 893 this.pane.hide(); 894 } 895 return this; 896 }; 897 898 899 /** 900 Destroys nanoScroller and restores browser's native scrollbar. 901 @method destroy 902 @chainable 903 @example 904 $(".nano").nanoScroller({ destroy: true }); 905 */ 906 907 NanoScroll.prototype.destroy = function() { 908 if (!this.stopped) { 909 this.stop(); 910 } 911 if (!this.iOSNativeScrolling && this.pane.length) { 912 this.pane.remove(); 913 } 914 if (BROWSER_IS_IE7) { 915 this.$content.height(''); 916 } 917 this.$content.removeAttr('tabindex'); 918 if (this.$el.hasClass(this.options.enabledClass)) { 919 this.$el.removeClass(this.options.enabledClass); 920 this.$content.css({ 921 right: '' 922 }); 923 } 924 return this; 925 }; 926 927 928 /** 929 To flash the scrollbar gadget for an amount of time defined in plugin settings (defaults to 1,5s). 930 Useful if you want to show the user (e.g. on pageload) that there is more content waiting for him. 931 @method flash 932 @chainable 933 @example 934 $(".nano").nanoScroller({ flash: true }); 935 */ 936 937 NanoScroll.prototype.flash = function() { 938 if (this.iOSNativeScrolling) { 939 return; 940 } 941 if (!this.isActive) { 942 return; 943 } 944 this.reset(); 945 this.pane.addClass(this.options.flashedClass); 946 setTimeout((function(_this) { 947 return function() { 948 _this.pane.removeClass(_this.options.flashedClass); 949 }; 950 })(this), this.options.flashDelay); 951 return this; 952 }; 953 954 return NanoScroll; 955 956 })(); 957 $.fn.nanoScroller = function(settings) { 958 return this.each(function() { 959 var options, scrollbar; 960 if (!(scrollbar = this.nanoscroller)) { 961 options = $.extend({}, defaults, settings); 962 this.nanoscroller = scrollbar = new NanoScroll(this, options); 963 } 964 if (settings && typeof settings === "object") { 965 $.extend(scrollbar.options, settings); 966 if (settings.scrollBottom != null) { 967 return scrollbar.scrollBottom(settings.scrollBottom); 968 } 969 if (settings.scrollTop != null) { 970 return scrollbar.scrollTop(settings.scrollTop); 971 } 972 if (settings.scrollTo) { 973 return scrollbar.scrollTo(settings.scrollTo); 974 } 975 if (settings.scroll === 'bottom') { 976 return scrollbar.scrollBottom(0); 977 } 978 if (settings.scroll === 'top') { 979 return scrollbar.scrollTop(0); 980 } 981 if (settings.scroll && settings.scroll instanceof $) { 982 return scrollbar.scrollTo(settings.scroll); 983 } 984 if (settings.stop) { 985 return scrollbar.stop(); 986 } 987 if (settings.destroy) { 988 return scrollbar.destroy(); 989 } 990 if (settings.flash) { 991 return scrollbar.flash(); 992 } 993 } 994 return scrollbar.reset(); 995 }); 996 }; 997 $.fn.nanoScroller.Constructor = NanoScroll; 998});
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.