Completed
Push — master ( 5bf5a9...80b817 )
by Rain
01:36
created

vendors/jquery-nanoscroller/jquery.nanoscroller.js   F

Complexity

Total Complexity 134
Complexity/F 3.83

Size

Lines of Code 895
Function Count 35

Duplication

Duplicated Lines 83
Ratio 9.27 %

Importance

Changes 0
Metric Value
cc 0
wmc 134
nc 0
mnd 3
bc 103
fnc 35
dl 83
loc 895
rs 2.1818
bpm 2.9428
cpm 3.8285
noi 7
c 0
b 0
f 0

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complexity

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like vendors/jquery-nanoscroller/jquery.nanoscroller.js often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

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