Subversion Repositories Integrator Subversion

Rev

Rev 182 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 espaco 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
});