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