PageSourceSearch

https://vse.fi/wp-content/themes/mag-pro/assest/js/jquery.nicescroll.js?ver=3.6.8

js vse.fi collected 2026-10-02 17:17:48 UTC 132,031 bytes, 3,797 lines download raw bytes

1/* jquery.nicescroll
2-- version 3.6.8
3-- copyright 2016-02-29 InuYaksa*2016
4-- licensed under the MIT
5--
6-- http://nicescroll.areaaperta.com/
7-- https://github.com/inuyaksa/jquery.nicescroll
8--
9*/
10
11(function(factory) {
12  if (typeof define === 'function' && define.amd) {
13    // AMD. Register as anonymous module.
14    define(['jquery'], factory);
15  } else if (typeof exports === 'object') {
16    // Node/CommonJS.
17    module.exports = factory(require('jquery'));
18  } else {
19    // Browser globals.
20    factory(jQuery);
21  }
22}(function(jQuery) {
23  "use strict";
24
25  // globals
26  var domfocus = false;
27  var mousefocus = false;
28  var tabindexcounter = 0;
29  var ascrailcounter = 2000;
30  var globalmaxzindex = 0;
31
32  var $ = jQuery; // sandbox
33
34  // http://stackoverflow.com/questions/2161159/get-script-path
35  function getScriptPath() {
36    var scripts = document.getElementsByTagName('script');
37    var path = scripts.length ? scripts[scripts.length - 1].src.split('?')[0] : '';
38    return (path.split('/').length > 0) ? path.split('/').slice(0, -1).join('/') + '/' : '';
39  }
40
41  var vendors = ['webkit','ms','moz','o'];
42
43  var setAnimationFrame = window.requestAnimationFrame || false;
44  var clearAnimationFrame = window.cancelAnimationFrame || false;
45
46  if (!setAnimationFrame) {  // legacy detection
47    for (var vx in vendors) {
48      var v = vendors[vx];
49      setAnimationFrame = window[v + 'RequestAnimationFrame'];
50      if (setAnimationFrame) {
51        clearAnimationFrame = window[v + 'CancelAnimationFrame'] || window[v + 'CancelRequestAnimationFrame'];
52        break;
53      }
54    }
55  }
56
57  var ClsMutationObserver = window.MutationObserver || window.WebKitMutationObserver || false;
58
59  var _globaloptions = {
60    zindex: "auto",
61    cursoropacitymin: 0,
62    cursoropacitymax: 1,
63    cursorcolor: "#424242",
64    cursorwidth: "6px",
65    cursorborder: "1px solid #fff",
66    cursorborderradius: "5px",
67    scrollspeed: 60,
68    mousescrollstep: 8 * 3,
69    touchbehavior: false,
70    hwacceleration: true,
71    usetransition: true,
72    boxzoom: false,
73    dblclickzoom: true,
74    gesturezoom: true,
75    grabcursorenabled: true,
76    autohidemode: true,
77    background: "",
78    iframeautoresize: true,
79    cursorminheight: 32,
80    preservenativescrolling: true,
81    railoffset: false,
82    railhoffset: false,
83    bouncescroll: true,
84    spacebarenabled: true,
85    railpadding: {
86      top: 0,
87      right: 0,
88      left: 0,
89      bottom: 0
90    },
91    disableoutline: true,
92    horizrailenabled: true,
93    railalign: "right",
94    railvalign: "bottom",
95    enabletranslate3d: true,
96    enablemousewheel: true,
97    enablekeyboard: true,
98    smoothscroll: true,
99    sensitiverail: true,
100    enablemouselockapi: true,
101    //      cursormaxheight:false,
102    cursorfixedheight: false,
103    directionlockdeadzone: 6,
104    hidecursordelay: 400,
105    nativeparentscrolling: true,
106    enablescrollonselection: true,
107    overflowx: true,
108    overflowy: true,
109    cursordragspeed: 0.3,
110    rtlmode: "auto",
111    cursordragontouch: false,
112    oneaxismousemode: "auto",
113    scriptpath: getScriptPath(),
114    preventmultitouchscrolling: true,
115    disablemutationobserver:false
116  };
117
118  var browserdetected = false;
119
120  var getBrowserDetection = function() {
121
122    if (browserdetected) return browserdetected;
123
124    var _el = document.createElement('DIV'),
125        _style = _el.style,
126        _agent = navigator.userAgent,
127        _platform = navigator.platform,
128        d = {};
129
130    d.haspointerlock = "pointerLockElement" in document || "webkitPointerLockElement" in document || "mozPointerLockElement" in document;
131
132    d.isopera = ("opera" in window); // 12-
133    d.isopera12 = (d.isopera && ("getUserMedia" in navigator));
134    d.isoperamini = (Object.prototype.toString.call(window.operamini) === "[object OperaMini]");
135
136    d.isie = (("all" in document) && ("attachEvent" in _el) && !d.isopera); //IE10-
137    d.isieold = (d.isie && !("msInterpolationMode" in _style)); // IE6 and older
138    d.isie7 = d.isie && !d.isieold && (!("documentMode" in document) || (document.documentMode == 7));
139    d.isie8 = d.isie && ("documentMode" in document) && (document.documentMode == 8);
140    d.isie9 = d.isie && ("performance" in window) && (document.documentMode == 9);
141    d.isie10 = d.isie && ("performance" in window) && (document.documentMode == 10);
142    d.isie11 = ("msRequestFullscreen" in _el) && (document.documentMode >= 11); // IE11+
143    d.isieedge12 = (navigator.userAgent.match(/Edge\/12\./));  // IE Edge 12
144    d.isieedge = ("msOverflowStyle" in _el);  // IE Edge
145    d.ismodernie = d.isie11 || d.isieedge;
146    
147    d.isie9mobile = /iemobile.9/i.test(_agent); //wp 7.1 mango
148    if (d.isie9mobile) d.isie9 = false;
149    d.isie7mobile = (!d.isie9mobile && d.isie7) && /iemobile/i.test(_agent); //wp 7.0
150
151    d.ismozilla = ("MozAppearance" in _style);
152
153    d.iswebkit = ("WebkitAppearance" in _style);
154
155    d.ischrome = ("chrome" in window);
156    d.ischrome38 = (d.ischrome && ("touchAction" in _style)); // behavior changed in touch emulation    
157    d.ischrome22 = (!d.ischrome38)&&(d.ischrome && d.haspointerlock);
158    d.ischrome26 = (!d.ischrome38)&&(d.ischrome && ("transition" in _style)); // issue with transform detection (maintain prefix)
159    
160    d.cantouch = ("ontouchstart" in document.documentElement) || ("ontouchstart" in window); // with detection for Chrome Touch Emulation    
161    d.hasw3ctouch = (window.PointerEvent || false) && ((navigator.MaxTouchPoints > 0)||(navigator.msMaxTouchPoints > 0)); //IE11 pointer events, following W3C Pointer Events spec
162    d.hasmstouch = (!d.hasw3ctouch)&&(window.MSPointerEvent || false); // IE10 pointer events
163
164    d.ismac = /^mac$/i.test(_platform);
165    
166    d.isios = (d.cantouch && /iphone|ipad|ipod/i.test(_platform));
167    d.isios4 = ((d.isios) && !("seal" in Object));
168    d.isios7 = ((d.isios)&&("webkitHidden" in document));  //iOS 7+
169    d.isios8 = ((d.isios)&&("hidden" in document));  //iOS 8+
170
171    d.isandroid = (/android/i.test(_agent));
172
173    d.haseventlistener = ("addEventListener" in _el);
174    
175    d.trstyle = false;
176    d.hastransform = false;
177    d.hastranslate3d = false;
178    d.transitionstyle = false;
179    d.hastransition = false;
180    d.transitionend = false;
181
182    var a;
183    var check = ['transform', 'msTransform', 'webkitTransform', 'MozTransform', 'OTransform'];    
184    for (a = 0; a < check.length; a++) {
185      if (_style[check[a]] !== undefined) {
186        d.trstyle = check[a];
187        break;
188      }
189    }
190    d.hastransform = (!!d.trstyle);
191    if (d.hastransform) {
192      _style[d.trstyle] = "translate3d(1px,2px,3px)";
193      d.hastranslate3d = /translate3d/.test(_style[d.trstyle]);
194    }
195
196    d.transitionstyle = false;
197    d.prefixstyle = '';
198    d.transitionend = false;
199    check = ['transition', 'webkitTransition', 'msTransition', 'MozTransition', 'OTransition', 'OTransition', 'KhtmlTransition'];
200    var prefix = ['', '-webkit-', '-ms-', '-moz-', '-o-', '-o', '-khtml-'];
201    var evs = ['transitionend', 'webkitTransitionEnd', 'msTransitionEnd', 'transitionend', 'otransitionend', 'oTransitionEnd', 'KhtmlTransitionEnd'];
202    for (a = 0; a < check.length; a++) {
203      if (check[a] in _style) {
204        d.transitionstyle = check[a];
205        d.prefixstyle = prefix[a];
206        d.transitionend = evs[a];
207        break;
208      }
209    }
210    if (d.ischrome26) {  // always use prefix
211      d.prefixstyle = prefix[1];
212    }
213
214    d.hastransition = (d.transitionstyle);
215
216    function detectCursorGrab() {
217      var lst = ['grab','-webkit-grab', '-moz-grab'];
218      if ((d.ischrome && !d.ischrome38) || d.isie) lst = []; // force setting for IE returns false positive and chrome cursor bug
219      for (var a = 0; a < lst.length; a++) {
220        var p = lst[a];
221        _style.cursor = p;
222        if (_style.cursor == p) return p;
223      }
224      return 'url(//patriciaportfolio.googlecode.com/files/openhand.cur),n-resize'; // thank you google for custom cursor!
225    }
226    d.cursorgrabvalue = detectCursorGrab();
227
228    d.hasmousecapture = ("setCapture" in _el);
229
230    d.hasMutationObserver = (ClsMutationObserver !== false);
231
232    _el = null; //memory released
233
234    browserdetected = d;
235
236    return d;
237  };
238
239  var NiceScrollClass = function(myopt, me) {
240
241    var self = this;
242
243    this.version = '3.6.8';
244    this.name = 'nicescroll';
245
246    this.me = me;
247
248    this.opt = {
249      doc: $("body"),
250      win: false
251    };
252
253    $.extend(this.opt, _globaloptions);  // clone opts
254
255    // Options for internal use
256    this.opt.snapbackspeed = 80;
257
258    if (myopt || false) {
259      for (var a in self.opt) {
260        if (myopt[a] !== undefined) self.opt[a] = myopt[a];
261      }
262    }
263
264    if (self.opt.disablemutationobserver) ClsMutationObserver = false;
265    
266    this.doc = self.opt.doc;
267    this.iddoc = (this.doc && this.doc[0]) ? this.doc[0].id || '' : '';
268    this.ispage = /^BODY|HTML/.test((self.opt.win) ? self.opt.win[0].nodeName : this.doc[0].nodeName);
269    this.haswrapper = (self.opt.win !== false);
270    this.win = self.opt.win || (this.ispage ? $(window) : this.doc);
vendor: 7,117 bytes, lines 271-508
271    this.docscroll = (this.ispage && !this.haswrapper) ? $(window) : this.win;
272    this.body = $("body");
273    this.viewport = false;
274
275    this.isfixed = false;
276
277    this.iframe = false;
278    this.isiframe = ((this.doc[0].nodeName == 'IFRAME') && (this.win[0].nodeName == 'IFRAME'));
279
280    this.istextarea = (this.win[0].nodeName == 'TEXTAREA');
281
282    this.forcescreen = false; //force to use screen position on events
283
284    this.canshowonmouseevent = (self.opt.autohidemode != "scroll");
285
286    // Events jump table    
287    this.onmousedown = false;
288    this.onmouseup = false;
289    this.onmousemove = false;
290    this.onmousewheel = false;
291    this.onkeypress = false;
292    this.ongesturezoom = false;
293    this.onclick = false;
294
295    // Nicescroll custom events
296    this.onscrollstart = false;
297    this.onscrollend = false;
298    this.onscrollcancel = false;
299
300    this.onzoomin = false;
301    this.onzoomout = false;
302
303    // Let's start!  
304    this.view = false;
305    this.page = false;
306
307    this.scroll = {
308      x: 0,
309      y: 0
310    };
311    this.scrollratio = {
312      x: 0,
313      y: 0
314    };
315    this.cursorheight = 20;
316    this.scrollvaluemax = 0;
317
318    // http://dev.w3.org/csswg/css-writing-modes-3/#logical-to-physical
319    // http://dev.w3.org/csswg/css-writing-modes-3/#svg-writing-mode
320    if (this.opt.rtlmode == "auto") {
321      var target = this.win[0] == window ? this.body : this.win;
322      var writingMode = target.css("writing-mode") || target.css("-webkit-writing-mode") || target.css("-ms-writing-mode") || target.css("-moz-writing-mode");
323
324      if (writingMode == "horizontal-tb" || writingMode == "lr-tb" || writingMode == "") {
325        this.isrtlmode = (target.css("direction") == "rtl");
326        this.isvertical = false;
327      } else {
328        this.isrtlmode = (writingMode == "vertical-rl" || writingMode == "tb" || writingMode == "tb-rl" || writingMode == "rl-tb");
329        this.isvertical = (writingMode == "vertical-rl" || writingMode == "tb" || writingMode == "tb-rl");
330      }
331    } else {
332      this.isrtlmode = (this.opt.rtlmode === true);
333      this.isvertical = false;
334    }
335    //    this.checkrtlmode = false;
336    
337    this.scrollrunning = false;
338
339    this.scrollmom = false;
340
341    this.observer        = false;  // observer div changes
342    this.observerremover = false;  // observer on parent for remove detection
343    this.observerbody    = false;  // observer on body for position change
344
345    do {
346      this.id = "ascrail" + (ascrailcounter++);
347    } while (document.getElementById(this.id));
348
349    this.rail = false;
350    this.cursor = false;
351    this.cursorfreezed = false;
352    this.selectiondrag = false;
353
354    this.zoom = false;
355    this.zoomactive = false;
356
357    this.hasfocus = false;
358    this.hasmousefocus = false;
359
360    this.visibility = true;
361    this.railslocked = false;  // locked by resize
362    this.locked = false;  // prevent lost of locked status sets by user
363    this.hidden = false; // rails always hidden
364    this.cursoractive = true; // user can interact with cursors
365
366    this.wheelprevented = false; //prevent mousewheel event
367
368    this.overflowx = self.opt.overflowx;
369    this.overflowy = self.opt.overflowy;
370
371    this.nativescrollingarea = false;
372    this.checkarea = 0;
373
374    this.events = []; // event list for unbind
375
376    this.saved = {};  // style saved
377
378    this.delaylist = {};
379    this.synclist = {};
380
381    this.lastdeltax = 0;
382    this.lastdeltay = 0;
383
384    this.detected = getBrowserDetection();
385
386    var cap = $.extend({}, this.detected);
387
388    this.canhwscroll = (cap.hastransform && self.opt.hwacceleration);
389    this.ishwscroll = (this.canhwscroll && self.haswrapper);
390
391    if (!this.isrtlmode) {
392      this.hasreversehr = false;
393    } else if (this.isvertical) { // RTL mode with reverse horizontal axis
394      this.hasreversehr = !(cap.iswebkit || cap.isie || cap.isie11);
395    } else {
396      this.hasreversehr = !(cap.iswebkit || (cap.isie && !cap.isie10 && !cap.isie11));
397    }
398
399    this.istouchcapable = false; // desktop devices with touch screen support
400
401    //## Check WebKit-based desktop with touch support
402    //## + Firefox 18 nightly build (desktop) false positive (or desktop with touch support)
403    
404    if (!cap.cantouch && (cap.hasw3ctouch||cap.hasmstouch)) {  // desktop device with multiple input
405      this.istouchcapable = true;
406    } else if (cap.cantouch && !cap.isios && !cap.isandroid && (cap.iswebkit || cap.ismozilla)) {
407      this.istouchcapable = true;
408//      cap.cantouch = false; // parse normal desktop events
409    }
410
411    //## disable MouseLock API on user request
412    if (!self.opt.enablemouselockapi) {
413      cap.hasmousecapture = false;
414      cap.haspointerlock = false;
415    }
416
417/* deprecated
418    this.delayed = function(name, fn, tm, lazy) {
419    };
420*/    
421
422/*
423    this.debounced = function(name, fn, tm) {
424		if (!self) return;
425      var dd = self.delaylist[name];
426      self.delaylist[name] = fn;
427      if (!dd) {
428        self.debouncedelayed =  setTimeout(function() {
429					if (!self) return;
430          var fn = self.delaylist[name];
431          self.delaylist[name] = false;
432          fn.call(self);
433        }, tm);
434      }
435    };
436*/
437
438		this.debounced = function(name, fn, tm) {
439      if (!self) return;
440			var dd = self.delaylist[name]||false;
441			if (!dd) {
442        //fixed loop call fn:checkSelectionScroll
443				//fn.call(self);				
444				self.delaylist[name] = {
445					h: setAnimationFrame(function(){
446						self.delaylist[name].fn.call(self);
447					  self.delaylist[name] = false;	
448					}, tm)
449				};
450        fn.call(self);
451			}			
452			self.delaylist[name].fn = fn;				
453		};
454
455    var _onsync = false;
456
457    this.synched = function(name, fn) {
458
459      function requestSync() {
460        if (_onsync) return;
461        setAnimationFrame(function() {
462          if (!self) return;
463          _onsync = false;
464          for (var nn in self.synclist) {
465            var fn = self.synclist[nn];
466            if (fn) fn.call(self);
467            self.synclist[nn] = false;
468          }
469        });
470        _onsync = true;
471      }
472
473      self.synclist[name] = fn;
474      requestSync();
475      return name;
476    };
477
478    this.unsynched = function(name) {
479      if (self.synclist[name]) self.synclist[name] = false;
480    };
481
482    this.css = function(el, pars) { // save & set
483      for (var n in pars) {
484        self.saved.css.push([el, n, el.css(n)]);
485        el.css(n, pars[n]);
486      }
487    };
488
489    this.scrollTop = function(val) {
490      return (val === undefined) ? self.getScrollTop() : self.setScrollTop(val);
491    };
492
493    this.scrollLeft = function(val) {
494      return (val === undefined) ? self.getScrollLeft() : self.setScrollLeft(val);
495    };
496
497    // derived by by Dan Pupius www.pupius.net
498    var BezierClass = function(st, ed, spd, p1, p2, p3, p4) {
499    
500      this.st = st;
501      this.ed = ed;
502      this.spd = spd;
503
504      this.p1 = p1 || 0;
505      this.p2 = p2 || 1;
506      this.p3 = p3 || 0;
507      this.p4 = p4 || 1;
508
509      this.ts = (new Date()).getTime();
510      this.df = this.ed - this.st;
511    };
512    BezierClass.prototype = {
513      B2: function(t) {
514        return 3 * t * t * (1 - t);
515      },
516      B3: function(t) {
517        return 3 * t * (1 - t) * (1 - t);
518      },
519      B4: function(t) {
520        return (1 - t) * (1 - t) * (1 - t);
521      },
522      getNow: function() {
523        var nw = (new Date()).getTime();
524        var pc = 1 - ((nw - this.ts) / this.spd);
525        var bz = this.B2(pc) + this.B3(pc) + this.B4(pc);
526        return (pc < 0) ? this.ed : this.st + Math.round(this.df * bz);
527      },
528      update: function(ed, spd) {
529        this.st = this.getNow();
530        this.ed = ed;
531        this.spd = spd;
532        this.ts = (new Date()).getTime();
533        this.df = this.ed - this.st;
534        return this;
535      }
536    };
537
538    //derived from http://stackoverflow.com/questions/11236090/
539    function getMatrixValues() {
540      var tr = self.doc.css(cap.trstyle);
541      if (tr && (tr.substr(0, 6) == "matrix")) {
542        return tr.replace(/^.*\((.*)\)$/g, "$1").replace(/px/g, '').split(/, +/);
543      }
544      return false;
545    }
546
547    if (this.ishwscroll) {
548      // hw accelerated scroll
549      this.doc.translate = {
550        x: 0,
551        y: 0,
552        tx: "0px",
553        ty: "0px"
554      };
555
556      //this one can help to enable hw accel on ios6 http://indiegamr.com/ios6-html-hardware-acceleration-changes-and-how-to-fix-them/
557      if (cap.hastranslate3d && cap.isios) this.doc.css("-webkit-backface-visibility", "hidden"); // prevent flickering http://stackoverflow.com/questions/3461441/      
558
vendor: 11,434 bytes, lines 559-866
559      this.getScrollTop = function(last) {
560        if (!last) {
561          var mtx = getMatrixValues();
562          if (mtx) return (mtx.length == 16) ? -mtx[13] : -mtx[5]; //matrix3d 16 on IE10
563          if (self.timerscroll && self.timerscroll.bz) return self.timerscroll.bz.getNow();
564        }
565        return self.doc.translate.y;
566      };
567
568      this.getScrollLeft = function(last) {
569        if (!last) {
570          var mtx = getMatrixValues();
571          if (mtx) return (mtx.length == 16) ? -mtx[12] : -mtx[4]; //matrix3d 16 on IE10
572          if (self.timerscroll && self.timerscroll.bh) return self.timerscroll.bh.getNow();
573        }
574        return self.doc.translate.x;
575      };
576
577      this.notifyScrollEvent = function(el) {
578        var e = document.createEvent("UIEvents");
579        e.initUIEvent("scroll", false, true, window, 1);
580        e.niceevent = true;
581        el.dispatchEvent(e);
582      };
583
584      var cxscrollleft = (this.isrtlmode) ? 1 : -1;
585
586      if (cap.hastranslate3d && self.opt.enabletranslate3d) {
587        this.setScrollTop = function(val, silent) {
588          self.doc.translate.y = val;
589          self.doc.translate.ty = (val * -1) + "px";
590          self.doc.css(cap.trstyle, "translate3d(" + self.doc.translate.tx + "," + self.doc.translate.ty + ",0px)");
591          if (!silent) self.notifyScrollEvent(self.win[0]);
592        };
593        this.setScrollLeft = function(val, silent) {
594          self.doc.translate.x = val;
595          self.doc.translate.tx = (val * cxscrollleft) + "px";
596          self.doc.css(cap.trstyle, "translate3d(" + self.doc.translate.tx + "," + self.doc.translate.ty + ",0px)");
597          if (!silent) self.notifyScrollEvent(self.win[0]);
598        };
599      } else {
600        this.setScrollTop = function(val, silent) {
601          self.doc.translate.y = val;
602          self.doc.translate.ty = (val * -1) + "px";
603          self.doc.css(cap.trstyle, "translate(" + self.doc.translate.tx + "," + self.doc.translate.ty + ")");
604          if (!silent) self.notifyScrollEvent(self.win[0]);
605        };
606        this.setScrollLeft = function(val, silent) {
607          self.doc.translate.x = val;
608          self.doc.translate.tx = (val * cxscrollleft) + "px";
609          self.doc.css(cap.trstyle, "translate(" + self.doc.translate.tx + "," + self.doc.translate.ty + ")");
610          if (!silent) self.notifyScrollEvent(self.win[0]);
611        };
612      }
613    } else {
614      // native scroll
615      this.getScrollTop = function() {
616        return self.docscroll.scrollTop();
617      };
618      this.setScrollTop = function(val) {
619        return setTimeout(function() {(self)&&self.docscroll.scrollTop(val)}, 1);
620      };
621      this.getScrollLeft = function() {
622        var val;
623        if (!self.hasreversehr) {
624          val = self.docscroll.scrollLeft();
625        } else if (self.detected.ismozilla) {
626          val = self.page.maxw - Math.abs(self.docscroll.scrollLeft());
627        } else {
628          val = self.page.maxw - self.docscroll.scrollLeft();
629        }
630        return val;
631      };
632      this.setScrollLeft = function(val) {
633        return setTimeout(function() {
634          if (!self) return;
635					if (self.hasreversehr) {
636						if (self.detected.ismozilla) {
637							val = -(self.page.maxw - val);
638						} else {
639							val = self.page.maxw - val;
640						}
641					}
642					return self.docscroll.scrollLeft(val);
643				}, 1);					
644      };
645    }
646
647    this.getTarget = function(e) {
648      if (!e) return false;
649      if (e.target) return e.target;
650      if (e.srcElement) return e.srcElement;
651      return false;
652    };
653
654    this.hasParent = function(e, id) {
655      if (!e) return false;
656      var el = e.target || e.srcElement || e || false;
657      while (el && el.id != id) {
658        el = el.parentNode || false;
659      }
660      return (el !== false);
661    };
662
663    function getZIndex() {
664      var dom = self.win;
665      if ("zIndex" in dom) return dom.zIndex(); // use jQuery UI method when available
666      while (dom.length > 0) {
667        if (dom[0].nodeType == 9) return false;
668        var zi = dom.css('zIndex');
669        if (!isNaN(zi) && zi != 0) return parseInt(zi);
670        dom = dom.parent();
671      }
672      return false;
673    }
674
675    //inspired by http://forum.jquery.com/topic/width-includes-border-width-when-set-to-thin-medium-thick-in-ie
676    var _convertBorderWidth = {
677      "thin": 1,
678      "medium": 3,
679      "thick": 5
680    };
681
682    function getWidthToPixel(dom, prop, chkheight) {
683      var wd = dom.css(prop);
684      var px = parseFloat(wd);
685      if (isNaN(px)) {
686        px = _convertBorderWidth[wd] || 0;
687        var brd = (px == 3) ? ((chkheight) ? (self.win.outerHeight() - self.win.innerHeight()) : (self.win.outerWidth() - self.win.innerWidth())) : 1; //DON'T TRUST CSS
688        if (self.isie8 && px) px += 1;
689        return (brd) ? px : 0;
690      }
691      return px;
692    }
693
694    this.getDocumentScrollOffset = function() {
695      return {
696        top: window.pageYOffset || document.documentElement.scrollTop,
697        left: window.pageXOffset || document.documentElement.scrollLeft
698      };
699    };
700    
701    this.getOffset = function() {
702      if (self.isfixed) {
703        var ofs = self.win.offset();  // fix Chrome auto issue (when right/bottom props only)
704        var scrl = self.getDocumentScrollOffset();
705        ofs.top-=scrl.top;
706        ofs.left-=scrl.left;
707        return ofs;  
708      }
709      var ww = self.win.offset();
710      if (!self.viewport) return ww;      
711      var vp = self.viewport.offset();
712      return {
713        top: ww.top - vp.top,// + self.viewport.scrollTop(),
714        left: ww.left - vp.left // + self.viewport.scrollLeft()
715      };
716    };
717
718    this.updateScrollBar = function(len) {
719      var pos, off;
720      if (self.ishwscroll) {
721        self.rail.css({  //**
722          height: self.win.innerHeight() - (self.opt.railpadding.top + self.opt.railpadding.bottom)
723        });
724        if (self.railh) self.railh.css({  //**
725          width: self.win.innerWidth() - (self.opt.railpadding.left + self.opt.railpadding.right)
726        });
727        
728      } else {
729        var wpos = self.getOffset();
730        pos = {
731          top: wpos.top,
732          left: wpos.left - (self.opt.railpadding.left + self.opt.railpadding.right)
733        };
734        pos.top += getWidthToPixel(self.win, 'border-top-width', true);
735        pos.left += (self.rail.align) ? self.win.outerWidth() - getWidthToPixel(self.win, 'border-right-width') - self.rail.width : getWidthToPixel(self.win, 'border-left-width');
736
737        off = self.opt.railoffset;
738        if (off) {
739          if (off.top) pos.top += off.top;
740          if (off.left) pos.left += off.left;
741        }
742        
743        if (!self.railslocked) self.rail.css({
744          top: pos.top,
745          left: pos.left,
746          height: ((len) ? len.h : self.win.innerHeight()) - (self.opt.railpadding.top + self.opt.railpadding.bottom)
747        });
748
749        if (self.zoom) {
750          self.zoom.css({
751            top: pos.top + 1,
752            left: (self.rail.align == 1) ? pos.left - 20 : pos.left + self.rail.width + 4
753          });
754        }
755
756        if (self.railh && !self.railslocked) {
757          pos = {
758            top: wpos.top,
759            left: wpos.left
760          };
761          off = self.opt.railhoffset;
762          if (off) {
763            if (off.top) pos.top += off.top;
764            if (off.left) pos.left += off.left;
765          }
766          var y = (self.railh.align) ? pos.top + getWidthToPixel(self.win, 'border-top-width', true) + self.win.innerHeight() - self.railh.height : pos.top + getWidthToPixel(self.win, 'border-top-width', true);
767          var x = pos.left + getWidthToPixel(self.win, 'border-left-width');
768          self.railh.css({
769            top: y - (self.opt.railpadding.top + self.opt.railpadding.bottom),
770            left: x,
771            width: self.railh.width
772          });
773        }
774
775      }
776    };
777
778    this.doRailClick = function(e, dbl, hr) {
779      var fn, pg, cur, pos;
780
781      if (self.railslocked) return;
782      self.cancelEvent(e);
783
784      if (dbl) {
785        fn = (hr) ? self.doScrollLeft : self.doScrollTop;
786        cur = (hr) ? ((e.pageX - self.railh.offset().left - (self.cursorwidth / 2)) * self.scrollratio.x) : ((e.pageY - self.rail.offset().top - (self.cursorheight / 2)) * self.scrollratio.y);
787        fn(cur);
788      } else {
789        fn = (hr) ? self.doScrollLeftBy : self.doScrollBy;
790        cur = (hr) ? self.scroll.x : self.scroll.y;
791        pos = (hr) ? e.pageX - self.railh.offset().left : e.pageY - self.rail.offset().top;
792        pg = (hr) ? self.view.w : self.view.h;
793        fn((cur >= pos) ? pg: -pg);//   (cur >= pos) ? fn(pg): fn(-pg);
794      }
795
796    };
797
798    self.hasanimationframe = (setAnimationFrame);
799    self.hascancelanimationframe = (clearAnimationFrame);
800
801    if (!self.hasanimationframe) {
802      setAnimationFrame = function(fn) {
803        return setTimeout(fn, 15 - Math.floor((+new Date()) / 1000) % 16);
804      }; // 1000/60)};
805      clearAnimationFrame = clearTimeout;
806    } else if (!self.hascancelanimationframe) clearAnimationFrame = function() {
807      self.cancelAnimationFrame = true;
808    };
809
810    this.init = function() {
811    
812      self.saved.css = [];
813      
814      if (cap.isie7mobile) return true; // SORRY, DO NOT WORK!
815      if (cap.isoperamini) return true; // SORRY, DO NOT WORK!
816
817      var _touchaction = (cap.isie10) ? '-ms-touch-action' : 'touch-action';
818      if (cap.hasmstouch) self.css((self.ispage) ? $("html") : self.win, {
819        _touchaction: 'none'
820      });
821
822      var _scrollyhidden =  (cap.ismodernie||cap.isie10) ? {'-ms-overflow-style':'none'} : {'overflow-y':'hidden'};  // IE is always a world apart!
823      
824      self.zindex = "auto";
825      if (!self.ispage && self.opt.zindex == "auto") {
826        self.zindex = getZIndex() || "auto";
827      } else {
828        self.zindex = self.opt.zindex;
829      }
830
831      if (!self.ispage && self.zindex != "auto" && self.zindex > globalmaxzindex) {
832        globalmaxzindex = self.zindex;
833      }
834
835      if (self.isie && self.zindex == 0 && self.opt.zindex == "auto") { // fix IE auto == 0
836        self.zindex = "auto";
837      }
838
839      if (!self.ispage || (!cap.cantouch && !cap.isieold && !cap.isie9mobile)) {
840
841        var cont = self.docscroll;
842        if (self.ispage) cont = (self.haswrapper) ? self.win : self.doc;
843
844        if (!cap.isie9mobile) self.css(cont, _scrollyhidden);
845
846        if (self.ispage && cap.isie7) {
847          if (self.doc[0].nodeName == 'BODY') self.css($("html"), {
848            'overflow-y': 'hidden'
849          }); //IE7 double scrollbar issue
850          else if (self.doc[0].nodeName == 'HTML') self.css($("body"), _scrollyhidden); //IE7 double scrollbar issue
851        }
852
853        if (cap.isios && !self.ispage && !self.haswrapper) self.css($("body"), {
854          "-webkit-overflow-scrolling": "touch"
855        }); //force hw acceleration
856
857        var cursor = $(document.createElement('div'));
858        cursor.css({
859          position: "relative",
860          top: 0,
861          "float": "right",
862          width: self.opt.cursorwidth,
863          height: 0,
864          'background-color': self.opt.cursorcolor,
865          border: self.opt.cursorborder,
866          'background-clip': 'padding-box',
867          '-webkit-border-radius': self.opt.cursorborderradius,
868          '-moz-border-radius': self.opt.cursorborderradius,
869          'border-radius': self.opt.cursorborderradius
870        });
871
872        cursor.hborder = parseFloat(cursor.outerHeight() - cursor.innerHeight());
873        
874        cursor.addClass('nicescroll-cursors');
875        
876        self.cursor = cursor;
877
878        var rail = $(document.createElement('div'));
879        rail.attr('id', self.id);
880        rail.addClass('nicescroll-rails nicescroll-rails-vr');
881
882        var v, a, kp = ["left","right","top","bottom"];  //**
883        for (var n in kp) {
884          a = kp[n];
885          v = self.opt.railpadding[a];
886          (v) ? rail.css("padding-"+a,v+"px") : self.opt.railpadding[a] = 0;
887        }
888
889        rail.append(cursor);
890
891        rail.width = Math.max(parseFloat(self.opt.cursorwidth), cursor.outerWidth());
892        rail.css({
893          width: rail.width + "px",
894          zIndex: self.zindex,
895          background: self.opt.background,
896          cursor: "default"
897        });
898
899        rail.visibility = true;
900        rail.scrollable = true;
901
902        rail.align = (self.opt.railalign == "left") ? 0 : 1;
903
904        self.rail = rail;
905
906        self.rail.drag = false;
907
908        var zoom = false;
909        if (self.opt.boxzoom && !self.ispage && !cap.isieold) {
910          zoom = document.createElement('div');
911
912          self.bind(zoom, "click", self.doZoom);
913          self.bind(zoom, "mouseenter", function() {
914            self.zoom.css('opacity', self.opt.cursoropacitymax);
915          });
916          self.bind(zoom, "mouseleave", function() {
917            self.zoom.css('opacity', self.opt.cursoropacitymin);
918          });
919
920          self.zoom = $(zoom);
921          self.zoom.css({
922            cursor: "pointer",
923            zIndex: self.zindex,
924            backgroundImage: 'url(' + self.opt.scriptpath + 'zoomico.png)',
925            height: 18,
926            width: 18,
927            backgroundPosition: '0px 0px'
928          });
929          if (self.opt.dblclickzoom) self.bind(self.win, "dblclick", self.doZoom);
930          if (cap.cantouch && self.opt.gesturezoom) {
931            self.ongesturezoom = function(e) {
932              if (e.scale > 1.5) self.doZoomIn(e);
933              if (e.scale < 0.8) self.doZoomOut(e);
934              return self.cancelEvent(e);
935            };
936            self.bind(self.win, "gestureend", self.ongesturezoom);
937          }
938        }
939
940        // init HORIZ
941
942        self.railh = false;
943        var railh;
944
945        if (self.opt.horizrailenabled) {
946
947          self.css(cont, {
948            overflowX: 'hidden'
949          });
950
951          var cursor = $(document.createElement('div'));
952          cursor.css({
953            position: "absolute",
954            top: 0,
955            height: self.opt.cursorwidth,
956            width: 0,
957            backgroundColor: self.opt.cursorcolor,
958            border: self.opt.cursorborder,
959            backgroundClip: 'padding-box',
960            '-webkit-border-radius': self.opt.cursorborderradius,
961            '-moz-border-radius': self.opt.cursorborderradius,
962            'border-radius': self.opt.cursorborderradius
963          });
964
965          if (cap.isieold) cursor.css('overflow', 'hidden');  //IE6 horiz scrollbar issue
966          
967          cursor.wborder = parseFloat(cursor.outerWidth() - cursor.innerWidth());
968          
969          cursor.addClass('nicescroll-cursors');
970          
971          self.cursorh = cursor;
972
973          railh = $(document.createElement('div'));
974          railh.attr('id', self.id + '-hr');
975          railh.addClass('nicescroll-rails nicescroll-rails-hr');
976          railh.height = Math.max(parseFloat(self.opt.cursorwidth), cursor.outerHeight());
977          railh.css({
978            height: railh.height + "px",
979            'zIndex': self.zindex,
980            "background": self.opt.background
981          });
982
983          railh.append(cursor);
984
985          railh.visibility = true;
986          railh.scrollable = true;
987
988          railh.align = (self.opt.railvalign == "top") ? 0 : 1;
989
990          self.railh = railh;
991
992          self.railh.drag = false;
993
994        }
995
996        //        
997
998        if (self.ispage) {
999          rail.css({
1000            position: "fixed",
1001            top: 0,
1002            height: "100%"
1003          });
1004          (rail.align) ? rail.css({
1005            right: 0
1006          }): rail.css({
1007            left: 0
1008          });
1009          self.body.append(rail);
1010          if (self.railh) {
1011            railh.css({
1012              position: "fixed",
1013              left: 0,
1014              width: "100%"
1015            });
1016            (railh.align) ? railh.css({
1017              bottom: 0
1018            }): railh.css({
1019              top: 0
1020            });
1021            self.body.append(railh);
1022          }
1023        } else {
1024          if (self.ishwscroll) {
1025            if (self.win.css('position') == 'static') self.css(self.win, {
1026              'position': 'relative'
1027            });
1028            var bd = (self.win[0].nodeName == 'HTML') ? self.body : self.win;
1029            $(bd).scrollTop(0).scrollLeft(0);  // fix rail position if content already scrolled
1030            if (self.zoom) {
1031              self.zoom.css({
1032                position: "absolute",
1033                top: 1,
1034                right: 0,
1035                "margin-right": rail.width + 4
1036              });
1037              bd.append(self.zoom);
1038            }
1039            rail.css({
1040              position: "absolute",
1041              top: 0
1042            });
1043            (rail.align) ? rail.css({
1044              right: 0
1045            }): rail.css({
1046              left: 0
1047            });
1048            bd.append(rail);
1049            if (railh) {
1050              railh.css({
1051                position: "absolute",
1052                left: 0,
1053                bottom: 0
1054              });
1055              (railh.align) ? railh.css({
1056                bottom: 0
1057              }): railh.css({
1058                top: 0
1059              });
1060              bd.append(railh);
1061            }
1062          } else {
1063            self.isfixed = (self.win.css("position") == "fixed");
1064            var rlpos = (self.isfixed) ? "fixed" : "absolute";
1065
1066            if (!self.isfixed) self.viewport = self.getViewport(self.win[0]);
1067            if (self.viewport) {
1068              self.body = self.viewport;
1069              if ((/fixed|absolute/.test(self.viewport.css("position"))) == false) self.css(self.viewport, {
1070                "position": "relative"
1071              });
1072            }
1073
1074            rail.css({
1075              position: rlpos
1076            });
1077            if (self.zoom) self.zoom.css({
1078              position: rlpos
1079            });
1080            self.updateScrollBar();
1081            self.body.append(rail);
1082            if (self.zoom) self.body.append(self.zoom);
1083            if (self.railh) {
1084              railh.css({
1085                position: rlpos
1086              });
1087              self.body.append(railh);
1088            }
1089          }
1090
1091          if (cap.isios) self.css(self.win, {
1092            '-webkit-tap-highlight-color': 'rgba(0,0,0,0)',
1093            '-webkit-touch-callout': 'none'
1094          }); // prevent grey layer on click
1095
1096          if (cap.isie && self.opt.disableoutline) self.win.attr("hideFocus", "true"); // IE, prevent dotted rectangle on focused div
1097          if (cap.iswebkit && self.opt.disableoutline) self.win.css('outline', 'none');  // Webkit outline
1098          //if (cap.isopera&&self.opt.disableoutline) self.win.css({"outline":"0"});  // Opera 12- to test [TODO]
1099
1100        }
1101
1102        if (self.opt.autohidemode === false) {
1103          self.autohidedom = false;
1104          self.rail.css({
1105            opacity: self.opt.cursoropacitymax
1106          });
1107          if (self.railh) self.railh.css({
1108            opacity: self.opt.cursoropacitymax
1109          });
1110        } else if ((self.opt.autohidemode === true) || (self.opt.autohidemode === "leave")) {
1111          self.autohidedom = $().add(self.rail);
1112          if (cap.isie8) self.autohidedom = self.autohidedom.add(self.cursor);
1113          if (self.railh) self.autohidedom = self.autohidedom.add(self.railh);
1114          if (self.railh && cap.isie8) self.autohidedom = self.autohidedom.add(self.cursorh);
1115        } else if (self.opt.autohidemode == "scroll") {
1116          self.autohidedom = $().add(self.rail);
1117          if (self.railh) self.autohidedom = self.autohidedom.add(self.railh);
1118        } else if (self.opt.autohidemode == "cursor") {
1119          self.autohidedom = $().add(self.cursor);
1120          if (self.railh) self.autohidedom = self.autohidedom.add(self.cursorh);
1121        } else if (self.opt.autohidemode == "hidden") {
1122          self.autohidedom = false;
1123          self.hide();
1124          self.railslocked = false;
1125        }
1126
1127        if (cap.isie9mobile) {
1128
1129          self.scrollmom = new ScrollMomentumClass2D(self);
1130
1131          self.onmangotouch = function() {
1132            var py = self.getScrollTop();
1133            var px = self.getScrollLeft();
1134
1135            if ((py == self.scrollmom.lastscrolly) && (px == self.scrollmom.lastscrollx)) return true;
1136
1137            var dfy = py - self.mangotouch.sy;
1138            var dfx = px - self.mangotouch.sx;
1139            var df = Math.round(Math.sqrt(Math.pow(dfx, 2) + Math.pow(dfy, 2)));
1140            if (df == 0) return;
1141
1142            var dry = (dfy < 0) ? -1 : 1;
1143            var drx = (dfx < 0) ? -1 : 1;
1144
1145            var tm = +new Date();
1146            if (self.mangotouch.lazy) clearTimeout(self.mangotouch.lazy);
1147
1148            if (((tm - self.mangotouch.tm) > 80) || (self.mangotouch.dry != dry) || (self.mangotouch.drx != drx)) {
1149              self.scrollmom.stop();
1150              self.scrollmom.reset(px, py);
1151              self.mangotouch.sy = py;
1152              self.mangotouch.ly = py;
1153              self.mangotouch.sx = px;
1154              self.mangotouch.lx = px;
1155              self.mangotouch.dry = dry;
1156              self.mangotouch.drx = drx;
1157              self.mangotouch.tm = tm;
1158            } else {
1159
1160              self.scrollmom.stop();
1161              self.scrollmom.update(self.mangotouch.sx - dfx, self.mangotouch.sy - dfy);
1162              self.mangotouch.tm = tm;
1163
1164              var ds = Math.max(Math.abs(self.mangotouch.ly - py), Math.abs(self.mangotouch.lx - px));
1165              self.mangotouch.ly = py;
1166              self.mangotouch.lx = px;
1167
1168              if (ds > 2) {
1169                self.mangotouch.lazy = setTimeout(function() {
1170                  self.mangotouch.lazy = false;
1171                  self.mangotouch.dry = 0;
1172                  self.mangotouch.drx = 0;
1173                  self.mangotouch.tm = 0;
1174                  self.scrollmom.doMomentum(30);
1175                }, 100);
1176              }
1177            }
1178          };
1179
1180          var top = self.getScrollTop();
1181          var lef = self.getScrollLeft();
1182          self.mangotouch = {
1183            sy: top,
1184            ly: top,
1185            dry: 0,
1186            sx: lef,
1187            lx: lef,
1188            drx: 0,
1189            lazy: false,
1190            tm: 0
1191          };
1192
1193          self.bind(self.docscroll, "scroll", self.onmangotouch);
1194
1195        } else {
1196
1197          if (cap.cantouch || self.istouchcapable || self.opt.touchbehavior || cap.hasmstouch) {
1198
1199            self.scrollmom = new ScrollMomentumClass2D(self);
1200
1201            self.ontouchstart = function(e) {
1202              if (e.pointerType && e.pointerType != 2 && e.pointerType != "touch") return false;
1203              
1204              self.hasmoving = false;
1205
1206              if (!self.railslocked) {
1207                var tg;
1208                if (cap.hasmstouch) {
1209                  tg = (e.target) ? e.target : false;
1210                  while (tg) {
1211                    var nc = $(tg).getNiceScroll();
1212                    if ((nc.length > 0) && (nc[0].me == self.me)) break;
1213                    if (nc.length > 0) return false;
1214                    if ((tg.nodeName == 'DIV') && (tg.id == self.id)) break;
1215                    tg = (tg.parentNode) ? tg.parentNode : false;
1216                  }
1217                }
1218
1219                self.cancelScroll();
1220
1221                tg = self.getTarget(e);
1222
1223                if (tg) {
1224                  var skp = (/INPUT/i.test(tg.nodeName)) && (/range/i.test(tg.type));
1225                  if (skp) return self.stopPropagation(e);
1226                }
1227
1228                if (!("clientX" in e) && ("changedTouches" in e)) {
1229                  e.clientX = e.changedTouches[0].clientX;
1230                  e.clientY = e.changedTouches[0].clientY;
1231                }
1232
1233                if (self.forcescreen) {
1234                  var le = e;
1235                  e = {
1236                    "original": (e.original) ? e.original : e
1237                  };
1238                  e.clientX = le.screenX;
1239                  e.clientY = le.screenY;
1240                }
1241
1242                self.rail.drag = {
1243                  x: e.clientX,
1244                  y: e.clientY,
1245                  sx: self.scroll.x,
1246                  sy: self.scroll.y,
1247                  st: self.getScrollTop(),
1248                  sl: self.getScrollLeft(),
1249                  pt: 2,
1250                  dl: false
1251                };
1252
1253                if (self.ispage || !self.opt.directionlockdeadzone) {
1254                  self.rail.drag.dl = "f";
1255                } else {
1256
1257                  var view = {
1258                    w: $(window).width(),
1259                    h: $(window).height()
1260                  };
1261
1262                  var page = {
1263                    w: Math.max(document.body.scrollWidth, document.documentElement.scrollWidth),
1264                    h: Math.max(document.body.scrollHeight, document.documentElement.scrollHeight)
1265                  };
1266
1267                  var maxh = Math.max(0, page.h - view.h);
1268                  var maxw = Math.max(0, page.w - view.w);
1269
1270                  if (!self.rail.scrollable && self.railh.scrollable) self.rail.drag.ck = (maxh > 0) ? "v" : false;
1271                  else if (self.rail.scrollable && !self.railh.scrollable) self.rail.drag.ck = (maxw > 0) ? "h" : false;
1272                  else self.rail.drag.ck = false;
1273                  if (!self.rail.drag.ck) self.rail.drag.dl = "f";
1274                }
1275
1276                if (self.opt.touchbehavior && self.isiframe && cap.isie) {
1277                  var wp = self.win.position();
1278                  self.rail.drag.x += wp.left;
1279                  self.rail.drag.y += wp.top;
1280                }
1281
1282                self.hasmoving = false;
1283                self.lastmouseup = false;
1284                self.scrollmom.reset(e.clientX, e.clientY);
1285                
1286                if (!cap.cantouch && !this.istouchcapable && !e.pointerType) {       
1287                
1288                  var ip = (tg) ? /INPUT|SELECT|TEXTAREA/i.test(tg.nodeName) : false;
1289                  if (!ip) {
1290                    if (!self.ispage && cap.hasmousecapture) tg.setCapture();
1291                    if (self.opt.touchbehavior) {
1292                      if (tg.onclick && !(tg._onclick || false)) { // intercept DOM0 onclick event
1293                        tg._onclick = tg.onclick;
1294                        tg.onclick = function(e) {
1295                          if (self.hasmoving) return false;
1296                          tg._onclick.call(this, e);
1297                        };
1298                      }
1299                      return self.cancelEvent(e);
1300                    }
1301                    return self.stopPropagation(e);
1302                  }
1303
1304                  if (/SUBMIT|CANCEL|BUTTON/i.test($(tg).attr('type'))) {
1305                    self.preventclick = {
1306                      "tg": tg,
1307                      "click": false
1308                    };
1309                  }
1310
1311                }
1312              }
1313
1314            };
1315
1316            self.ontouchend = function(e) {              
1317              if (!self.rail.drag) return true;              
1318              if (self.rail.drag.pt == 2) {
1319                if (e.pointerType && e.pointerType != 2 && e.pointerType != "touch") return false;
1320								
1321                self.scrollmom.doMomentum();
1322                self.rail.drag = false;
1323                if (self.hasmoving) {
1324                  self.lastmouseup = true;
1325                  self.hideCursor();
1326                  if (cap.hasmousecapture) document.releaseCapture();
1327                  if (!cap.cantouch) return self.cancelEvent(e);
1328                }
1329              }
1330              else if (self.rail.drag.pt == 1) {
1331                return self.onmouseup(e);
1332              }
1333
1334            };
1335
1336            var moveneedoffset = (self.opt.touchbehavior && self.isiframe && !cap.hasmousecapture);
1337
1338            self.ontouchmove = function(e, byiframe) {
1339
1340              if (!self.rail.drag) return false;
1341            
1342              if (e.targetTouches && self.opt.preventmultitouchscrolling) {
1343                if (e.targetTouches.length > 1) return false; // multitouch
1344              }
1345            
1346              if (e.pointerType && e.pointerType != 2 && e.pointerType != "touch") return false;
1347          
1348              if (self.rail.drag.pt == 2) {
1349                if (cap.cantouch && (cap.isios) && e.original === undefined) return true; // prevent ios "ghost" events by clickable elements
1350
1351                self.hasmoving = true;
1352
1353                if (self.preventclick && !self.preventclick.click) {
1354                  self.preventclick.click = self.preventclick.tg.onclick || false;
1355                  self.preventclick.tg.onclick = self.onpreventclick;
1356                }
1357
1358                var ev = $.extend({
1359                  "original": e
1360                }, e);
1361                e = ev;
1362
1363                if (("changedTouches" in e)) {
1364                  e.clientX = e.changedTouches[0].clientX;
1365                  e.clientY = e.changedTouches[0].clientY;
1366                }
1367
1368                if (self.forcescreen) {
1369                  var le = e;
1370                  e = {
1371                    "original": (e.original) ? e.original : e
1372                  };
1373                  e.clientX = le.screenX;
1374                  e.clientY = le.screenY;
1375                }
1376
1377                var ofy,ofx;
1378                ofx = ofy = 0;
1379
1380                if (moveneedoffset && !byiframe) {
1381                  var wp = self.win.position();
1382                  ofx = -wp.left;
1383                  ofy = -wp.top;
1384                }
1385
1386                var fy = e.clientY + ofy;
1387                var my = (fy - self.rail.drag.y);
1388                var fx = e.clientX + ofx;
1389                var mx = (fx - self.rail.drag.x);
1390
1391                var ny = self.rail.drag.st - my;
1392
1393                if (self.ishwscroll && self.opt.bouncescroll) {
1394                  if (ny < 0) {
1395                    ny = Math.round(ny / 2);
1396                    //                    fy = 0;
1397                  } else if (ny > self.page.maxh) {
1398                    ny = self.page.maxh + Math.round((ny - self.page.maxh) / 2);
1399                    //                    fy = 0;
1400                  }
1401                } else {
1402                  if (ny < 0) {
1403                    ny = 0;
1404                    fy = 0;
1405                  }
1406                  if (ny > self.page.maxh) {
1407                    ny = self.page.maxh;
1408                    fy = 0;
1409                  }
1410                }
1411
1412                var nx;
1413                if (self.railh && self.railh.scrollable) {
1414                  nx = (self.isrtlmode) ? mx - self.rail.drag.sl : self.rail.drag.sl - mx;
1415
1416                  if (self.ishwscroll && self.opt.bouncescroll) {
1417                    if (nx < 0) {
1418                      nx = Math.round(nx / 2);
1419                      //                      fx = 0;
1420                    } else if (nx > self.page.maxw) {
1421                      nx = self.page.maxw + Math.round((nx - self.page.maxw) / 2);
1422                      //                      fx = 0;
1423                    }
1424                  } else {
1425                    if (nx < 0) {
1426                      nx = 0;
1427                      fx = 0;
1428                    }
1429                    if (nx > self.page.maxw) {
1430                      nx = self.page.maxw;
1431                      fx = 0;
1432                    }
1433                  }
1434
1435                }
1436
1437                var grabbed = false;
1438                if (self.rail.drag.dl) {
1439                  grabbed = true;
1440                  if (self.rail.drag.dl == "v") nx = self.rail.drag.sl;
1441                  else if (self.rail.drag.dl == "h") ny = self.rail.drag.st;
1442                } else {
1443                  var ay = Math.abs(my);
1444                  var ax = Math.abs(mx);
1445                  var dz = self.opt.directionlockdeadzone;
1446                  if (self.rail.drag.ck == "v") {
1447                    if (ay > dz && (ax <= (ay * 0.3))) {
1448                      self.rail.drag = false;
1449                      return true;
1450                    } else if (ax > dz) {
1451                      self.rail.drag.dl = "f";
1452                      $("body").scrollTop($("body").scrollTop()); // stop iOS native scrolling (when active javascript has blocked)
1453                    }
1454                  } else if (self.rail.drag.ck == "h") {
1455                    if (ax > dz && (ay <= (ax * 0.3))) {
1456                      self.rail.drag = false;
1457                      return true;
1458                    } else if (ay > dz) {
1459                      self.rail.drag.dl = "f";
1460                      $("body").scrollLeft($("body").scrollLeft()); // stop iOS native scrolling (when active javascript has blocked)
1461                    }
1462                  }
1463                }
1464
1465                self.synched("touchmove", function() {
1466                  if (self.rail.drag && (self.rail.drag.pt == 2)) {
1467                    if (self.prepareTransition) self.prepareTransition(0);
1468                    if (self.rail.scrollable) self.setScrollTop(ny);
1469                    self.scrollmom.update(fx, fy);
1470                    if (self.railh && self.railh.scrollable) {
1471                      self.setScrollLeft(nx);
1472                      self.showCursor(ny, nx);
1473                    } else {
1474                      self.showCursor(ny);
1475                    }
1476                    if (cap.isie10) document.selection.clear();
1477                  }
1478                });
1479
1480                if (cap.ischrome && self.istouchcapable) grabbed = false; //chrome touch emulation doesn't like!
1481                if (grabbed) return self.cancelEvent(e);
1482              }
1483              else if (self.rail.drag.pt == 1) { // drag on cursor
1484                return self.onmousemove(e);
1485              }
1486
1487            };
1488
1489            self.ontouchstartCursor = function (e, hronly) {
1490              if (self.rail.drag && self.rail.drag.pt != 3) return;
1491              if (self.locked) return self.cancelEvent(e);
1492              self.cancelScroll();
1493              self.rail.drag = {
1494                x: e.touches[0].clientX,
1495                y: e.touches[0].clientY,
1496                sx: self.scroll.x,
1497                sy: self.scroll.y,
1498                pt: 3,
1499                hr: (!!hronly)
1500              };
1501              var tg = self.getTarget(e);
1502              if (!self.ispage && cap.hasmousecapture) tg.setCapture();
1503              if (self.isiframe && !cap.hasmousecapture) {
1504                self.saved["csspointerevents"] = self.doc.css("pointer-events");
1505                self.css(self.doc, {"pointer-events": "none"});
1506              }
1507              return self.cancelEvent(e);
1508            };
1509
1510            self.ontouchendCursor = function (e) {
1511              if (self.rail.drag) {
1512                if (cap.hasmousecapture) document.releaseCapture();
1513                if (self.isiframe && !cap.hasmousecapture) self.doc.css("pointer-events", self.saved["csspointerevents"]);
1514                if (self.rail.drag.pt != 3)return;
1515                self.rail.drag = false;
1516                //if (!self.rail.active) self.hideCursor();
1517                return self.cancelEvent(e);
1518              }
1519            };
1520
1521            self.ontouchmoveCursor = function (e) {
1522              if (self.rail.drag) {
1523                if (self.rail.drag.pt != 3)return;
1524
1525                self.cursorfreezed = true;
1526
1527                if (self.rail.drag.hr) {
1528                  self.scroll.x = self.rail.drag.sx + (e.touches[0].clientX - self.rail.drag.x);
vendor: 25,563 bytes, lines 1529-2166
1529                  if (self.scroll.x < 0) self.scroll.x = 0;
1530                  var mw = self.scrollvaluemaxw;
1531                  if (self.scroll.x > mw) self.scroll.x = mw;
1532                } else {
1533                  self.scroll.y = self.rail.drag.sy + (e.touches[0].clientY - self.rail.drag.y);
1534                  if (self.scroll.y < 0) self.scroll.y = 0;
1535                  var my = self.scrollvaluemax;
1536                  if (self.scroll.y > my) self.scroll.y = my;
1537                }
1538
1539                self.synched('touchmove', function () {
1540                  if (self.rail.drag && (self.rail.drag.pt == 3)) {
1541                    self.showCursor();
1542                    if (self.rail.drag.hr) self.doScrollLeft(Math.round(self.scroll.x * self.scrollratio.x), self.opt.cursordragspeed);
1543                    else self.doScrollTop(Math.round(self.scroll.y * self.scrollratio.y), self.opt.cursordragspeed);
1544                  }
1545                });
1546
1547                return self.cancelEvent(e);
1548              }
1549              /*
1550               else {
1551               self.checkarea = true;
1552               }
1553               */
1554            };
1555
1556          }
1557
1558          self.onmousedown = function(e, hronly) {
1559            if (self.rail.drag && self.rail.drag.pt != 1) return;
1560            if (self.railslocked) return self.cancelEvent(e);
1561            self.cancelScroll();
1562            self.rail.drag = {
1563              x: e.clientX,
1564              y: e.clientY,
1565              sx: self.scroll.x,
1566              sy: self.scroll.y,
1567              pt: 1,
1568              hr: (!!hronly)
1569            };
1570            var tg = self.getTarget(e);
1571            if (!self.ispage && cap.hasmousecapture) tg.setCapture();
1572            if (self.isiframe && !cap.hasmousecapture) {
1573              self.saved.csspointerevents = self.doc.css("pointer-events");
1574              self.css(self.doc, {
1575                "pointer-events": "none"
1576              });
1577            }
1578            self.hasmoving = false;
1579            return self.cancelEvent(e);
1580          };
1581
1582          self.onmouseup = function(e) {
1583            if (self.rail.drag) {
1584              if (self.rail.drag.pt != 1) return true;
1585							
1586              if (cap.hasmousecapture) document.releaseCapture();
1587              if (self.isiframe && !cap.hasmousecapture) self.doc.css("pointer-events", self.saved.csspointerevents);              
1588              self.rail.drag = false;
1589              //if (!self.rail.active) self.hideCursor();
1590              if (self.hasmoving) self.triggerScrollEnd(); // TODO - check &&!self.scrollrunning
1591              return self.cancelEvent(e);
1592            }
1593          };
1594
1595          self.onmousemove = function(e) {
1596            if (self.rail.drag) {
1597              if (self.rail.drag.pt != 1) return;
1598
1599              if (cap.ischrome && e.which == 0) return self.onmouseup(e);
1600
1601              self.cursorfreezed = true;
1602              self.hasmoving = true;
1603
1604              if (self.rail.drag.hr) {
1605                self.scroll.x = self.rail.drag.sx + (e.clientX - self.rail.drag.x);
1606                if (self.scroll.x < 0) self.scroll.x = 0;
1607                var mw = self.scrollvaluemaxw;
1608                if (self.scroll.x > mw) self.scroll.x = mw;
1609              } else {
1610                self.scroll.y = self.rail.drag.sy + (e.clientY - self.rail.drag.y);
1611                if (self.scroll.y < 0) self.scroll.y = 0;
1612                var my = self.scrollvaluemax;
1613                if (self.scroll.y > my) self.scroll.y = my;
1614              }
1615
1616              self.synched('mousemove', function() {
1617                if (self.rail.drag && (self.rail.drag.pt == 1)) {
1618                  self.showCursor();
1619                  if (self.rail.drag.hr) {
1620                    if (self.hasreversehr) {
1621                      self.doScrollLeft(self.scrollvaluemaxw-Math.round(self.scroll.x * self.scrollratio.x), self.opt.cursordragspeed);
1622                    } else {
1623                      self.doScrollLeft(Math.round(self.scroll.x * self.scrollratio.x), self.opt.cursordragspeed);
1624                    }
1625                  }
1626                  else self.doScrollTop(Math.round(self.scroll.y * self.scrollratio.y), self.opt.cursordragspeed);
1627                }
1628              });
1629
1630              return self.cancelEvent(e);
1631            }
1632            else {
1633              self.checkarea = 0;
1634            }
1635          };
1636
1637          if (cap.cantouch || self.opt.touchbehavior) {
1638
1639            self.onpreventclick = function(e) {
1640              if (self.preventclick) {
1641                self.preventclick.tg.onclick = self.preventclick.click;
1642                self.preventclick = false;
1643                return self.cancelEvent(e);
1644              }
1645            };
1646
1647            self.bind(self.win, "mousedown", self.ontouchstart); // control content dragging
1648
1649            self.onclick = (cap.isios) ? false : function(e) {  // it needs to check IE11 ???
1650              if (self.lastmouseup) {
1651                self.lastmouseup = false;
1652                return self.cancelEvent(e);
1653              } else {
1654                return true;
1655              }
1656            };
1657
1658            if (self.opt.grabcursorenabled && cap.cursorgrabvalue) {
1659              self.css((self.ispage) ? self.doc : self.win, {
1660                'cursor': cap.cursorgrabvalue
1661              });
1662              self.css(self.rail, {
1663                'cursor': cap.cursorgrabvalue
1664              });
1665            }
1666
1667          } else {
1668
1669            var checkSelectionScroll = function(e) {
1670              if (!self.selectiondrag) return;
1671
1672              if (e) {
1673                var ww = self.win.outerHeight();
1674                var df = (e.pageY - self.selectiondrag.top);
1675                if (df > 0 && df < ww) df = 0;
1676                if (df >= ww) df -= ww;
1677                self.selectiondrag.df = df;
1678              }
1679              if (self.selectiondrag.df == 0) return;
1680
1681              var rt = -Math.floor(self.selectiondrag.df / 6) * 2;
1682              self.doScrollBy(rt);
1683
1684              self.debounced("doselectionscroll", function() {
1685                checkSelectionScroll();
1686              }, 50);
1687            };
1688
1689            if ("getSelection" in document) { // A grade - Major browsers
1690              self.hasTextSelected = function() {
1691                return (document.getSelection().rangeCount > 0);
1692              };
1693            } else if ("selection" in document) { //IE9-
1694              self.hasTextSelected = function() {
1695                return (document.selection.type != "None");
1696              };
1697            } else {
1698              self.hasTextSelected = function() { // no support
1699                return false;
1700              };
1701            }
1702
1703            self.onselectionstart = function(e) {
1704/*  More testing - severe chrome issues            
1705              if (!self.haswrapper&&(e.which&&e.which==2)) {  // fool browser to manage middle button scrolling
1706                self.win.css({'overflow':'auto'});
1707                setTimeout(function(){
1708                  self.win.css({'overflow':''});
1709                },10);                
1710                return true;
1711              }            
1712*/              
1713              if (self.ispage) return;
1714              self.selectiondrag = self.win.offset();
1715            };
1716            
1717            self.onselectionend = function(e) {
1718              self.selectiondrag = false;
1719            };
1720            self.onselectiondrag = function(e) {
1721              if (!self.selectiondrag) return;
1722              if (self.hasTextSelected()) self.debounced("selectionscroll", function() {
1723                checkSelectionScroll(e);
1724              }, 250);
1725            };
1726
1727
1728          }
1729
1730          if (cap.hasw3ctouch) { //IE11+
1731            self.css(self.rail, {
1732              'touch-action': 'none'
1733            });
1734            self.css(self.cursor, {
1735              'touch-action': 'none'
1736            });
1737            self.bind(self.win, "pointerdown", self.ontouchstart);
1738            self.bind(document, "pointerup", self.ontouchend);
1739            self.bind(document, "pointermove", self.ontouchmove);
1740          } else if (cap.hasmstouch) { //IE10
1741            self.css(self.rail, {
1742              '-ms-touch-action': 'none'
1743            });
1744            self.css(self.cursor, {
1745              '-ms-touch-action': 'none'
1746            });
1747            self.bind(self.win, "MSPointerDown", self.ontouchstart);
1748            self.bind(document, "MSPointerUp", self.ontouchend);
1749            self.bind(document, "MSPointerMove", self.ontouchmove);
1750            self.bind(self.cursor, "MSGestureHold", function(e) {
1751              e.preventDefault();
1752            });
1753            self.bind(self.cursor, "contextmenu", function(e) {
1754              e.preventDefault();
1755            });
1756          } else if (this.istouchcapable) { //desktop with screen touch enabled
1757            self.bind(self.win, "touchstart", self.ontouchstart);
1758            self.bind(document, "touchend", self.ontouchend);
1759            self.bind(document, "touchcancel", self.ontouchend);
1760            self.bind(document, "touchmove", self.ontouchmove);
1761          }
1762
1763          
1764          if (self.opt.cursordragontouch || (!cap.cantouch && !self.opt.touchbehavior)) {
1765
1766            self.rail.css({
1767              cursor: "default"
1768            });
1769            self.railh && self.railh.css({
1770              cursor: "default"
1771            });
1772
1773            self.jqbind(self.rail, "mouseenter", function() {
1774              if (!self.ispage && !self.win.is(":visible")) return false;
1775              if (self.canshowonmouseevent) self.showCursor();
1776              self.rail.active = true;
1777            });
1778            self.jqbind(self.rail, "mouseleave", function() {
1779              self.rail.active = false;
1780              if (!self.rail.drag) self.hideCursor();
1781            });
1782
1783            if (self.opt.sensitiverail) {
1784              self.bind(self.rail, "click", function(e) {
1785                self.doRailClick(e, false, false);
1786              });
1787              self.bind(self.rail, "dblclick", function(e) {
1788                self.doRailClick(e, true, false);
1789              });
1790              self.bind(self.cursor, "click", function(e) {
1791                self.cancelEvent(e);
1792              });
1793              self.bind(self.cursor, "dblclick", function(e) {
1794                self.cancelEvent(e);
1795              });
1796            }
1797
1798            if (self.railh) {
1799              self.jqbind(self.railh, "mouseenter", function() {
1800                if (!self.ispage && !self.win.is(":visible")) return false;
1801                if (self.canshowonmouseevent) self.showCursor();
1802                self.rail.active = true;
1803              });
1804              self.jqbind(self.railh, "mouseleave", function() {
1805                self.rail.active = false;
1806                if (!self.rail.drag) self.hideCursor();
1807              });
1808
1809              if (self.opt.sensitiverail) {
1810                self.bind(self.railh, "click", function(e) {
1811                  self.doRailClick(e, false, true);
1812                });
1813                self.bind(self.railh, "dblclick", function(e) {
1814                  self.doRailClick(e, true, true);
1815                });
1816                self.bind(self.cursorh, "click", function(e) {
1817                  self.cancelEvent(e);
1818                });
1819                self.bind(self.cursorh, "dblclick", function(e) {
1820                  self.cancelEvent(e);
1821                });
1822              }
1823
1824            }
1825
1826          }
1827
1828          if(self.opt.cursordragontouch && (this.istouchcapable || cap.cantouch)) {
1829            self.bind(self.cursor, "touchstart", self.ontouchstartCursor);
1830            self.bind(self.cursor, "touchmove", self.ontouchmoveCursor);
1831            self.bind(self.cursor, "touchend", self.ontouchendCursor);
1832            self.cursorh && self.bind(self.cursorh, "touchstart", function(e) {
1833                self.ontouchstartCursor(e, true);
1834            });
1835            self.cursorh && self.bind(self.cursorh, "touchmove", self.ontouchmoveCursor);
1836            self.cursorh && self.bind(self.cursorh, "touchend", self.ontouchendCursor);
1837          }
1838
1839          if (!cap.cantouch && !self.opt.touchbehavior) {
1840
1841            self.bind((cap.hasmousecapture) ? self.win : document, "mouseup", self.onmouseup);
1842            self.bind(document, "mousemove", self.onmousemove);
1843            if (self.onclick) self.bind(document, "click", self.onclick);
1844
1845            self.bind(self.cursor, "mousedown", self.onmousedown);
1846            self.bind(self.cursor, "mouseup", self.onmouseup);
1847
1848            if (self.railh) {
1849              self.bind(self.cursorh, "mousedown", function(e) {
1850                self.onmousedown(e, true);
1851              });
1852              self.bind(self.cursorh, "mouseup", self.onmouseup);
1853            }
1854            
1855            if (!self.ispage && self.opt.enablescrollonselection) {
1856              self.bind(self.win[0], "mousedown", self.onselectionstart);
1857              self.bind(document, "mouseup", self.onselectionend);
1858              self.bind(self.cursor, "mouseup", self.onselectionend);
1859              if (self.cursorh) self.bind(self.cursorh, "mouseup", self.onselectionend);
1860              self.bind(document, "mousemove", self.onselectiondrag);
1861            }
1862
1863            if (self.zoom) {
1864              self.jqbind(self.zoom, "mouseenter", function() {
1865                if (self.canshowonmouseevent) self.showCursor();
1866                self.rail.active = true;
1867              });
1868              self.jqbind(self.zoom, "mouseleave", function() {
1869                self.rail.active = false;
1870                if (!self.rail.drag) self.hideCursor();
1871              });
1872            }
1873
1874          } else {
1875
1876            self.bind((cap.hasmousecapture) ? self.win : document, "mouseup", self.ontouchend);
1877            self.bind(document, "mousemove", self.ontouchmove);
1878            if (self.onclick) self.bind(document, "click", self.onclick);
1879
1880            if (self.opt.cursordragontouch) {
1881              self.bind(self.cursor, "mousedown", self.onmousedown);
1882              self.bind(self.cursor, "mouseup", self.onmouseup);
1883              //self.bind(self.cursor, "mousemove", self.onmousemove);
1884              self.cursorh && self.bind(self.cursorh, "mousedown", function(e) {
1885                self.onmousedown(e, true);
1886              });
1887              //self.cursorh && self.bind(self.cursorh, "mousemove", self.onmousemove);
1888              self.cursorh && self.bind(self.cursorh, "mouseup", self.onmouseup);
1889            } else {
1890              self.bind(self.rail, "mousedown", function(e){e.preventDefault();});  // prevent text selection             
1891							self.railh&&self.bind(self.railh, "mousedown", function(e){e.preventDefault();});
1892            }
1893
1894          }
1895            
1896
1897          if (self.opt.enablemousewheel) {
1898            if (!self.isiframe) self.mousewheel((cap.isie && self.ispage) ? document : self.win , self.onmousewheel);
1899            self.mousewheel(self.rail, self.onmousewheel);
1900            if (self.railh) self.mousewheel(self.railh, self.onmousewheelhr);
1901          }
1902
1903          if (!self.ispage && !cap.cantouch && !(/HTML|^BODY/.test(self.win[0].nodeName))) {
1904            if (!self.win.attr("tabindex")) self.win.attr({
1905              "tabindex": tabindexcounter++
1906            });
1907
1908            self.jqbind(self.win, "focus", function(e) {
1909              domfocus = (self.getTarget(e)).id || true;
1910              self.hasfocus = true;
1911              if (self.canshowonmouseevent) self.noticeCursor();
1912            });
1913            self.jqbind(self.win, "blur", function(e) {
1914              domfocus = false;
1915              self.hasfocus = false;
1916            });
1917
1918            self.jqbind(self.win, "mouseenter", function(e) {
1919              mousefocus = (self.getTarget(e)).id || true;
1920              self.hasmousefocus = true;
1921              if (self.canshowonmouseevent) self.noticeCursor();
1922            });
1923            self.jqbind(self.win, "mouseleave", function() {
1924              mousefocus = false;
1925              self.hasmousefocus = false;
1926              if (!self.rail.drag) self.hideCursor();
1927            });
1928
1929          }
1930
1931        } // !ie9mobile
1932
1933        //Thanks to http://www.quirksmode.org !!
1934        self.onkeypress = function(e) {
1935          if (self.railslocked && self.page.maxh == 0) return true;
1936
1937          e = (e) ? e : window.e;
1938          var tg = self.getTarget(e);
1939          if (tg && /INPUT|TEXTAREA|SELECT|OPTION/.test(tg.nodeName)) {
1940            var tp = tg.getAttribute('type') || tg.type || false;
1941            if ((!tp) || !(/submit|button|cancel/i.tp)) return true;
1942          }
1943
1944          if ($(tg).attr('contenteditable')) return true;
1945
1946          if (self.hasfocus || (self.hasmousefocus && !domfocus) || (self.ispage && !domfocus && !mousefocus)) {
1947            var key = e.keyCode;
1948
1949            if (self.railslocked && key != 27) return self.cancelEvent(e);
1950
1951            var ctrl = e.ctrlKey || false;
1952            var shift = e.shiftKey || false;
1953
1954            var ret = false;
1955            switch (key) {
1956              case 38:
1957              case 63233: //safari
1958                self.doScrollBy(24 * 3);
1959                ret = true;
1960                break;
1961              case 40:
1962              case 63235: //safari
1963                self.doScrollBy(-24 * 3);
1964                ret = true;
1965                break;
1966              case 37:
1967              case 63232: //safari
1968                if (self.railh) {
1969                  (ctrl) ? self.doScrollLeft(0): self.doScrollLeftBy(24 * 3);
1970                  ret = true;
1971                }
1972                break;
1973              case 39:
1974              case 63234: //safari
1975                if (self.railh) {
1976                  (ctrl) ? self.doScrollLeft(self.page.maxw): self.doScrollLeftBy(-24 * 3);
1977                  ret = true;
1978                }
1979                break;
1980              case 33:
1981              case 63276: // safari
1982                self.doScrollBy(self.view.h);
1983                ret = true;
1984                break;
1985              case 34:
1986              case 63277: // safari
1987                self.doScrollBy(-self.view.h);
1988                ret = true;
1989                break;
1990              case 36:
1991              case 63273: // safari                
1992                (self.railh && ctrl) ? self.doScrollPos(0, 0): self.doScrollTo(0);
1993                ret = true;
1994                break;
1995              case 35:
1996              case 63275: // safari
1997                (self.railh && ctrl) ? self.doScrollPos(self.page.maxw, self.page.maxh): self.doScrollTo(self.page.maxh);
1998                ret = true;
1999                break;
2000              case 32:
2001                if (self.opt.spacebarenabled) {
2002                  (shift) ? self.doScrollBy(self.view.h): self.doScrollBy(-self.view.h);
2003                  ret = true;
2004                }
2005                break;
2006              case 27: // ESC
2007                if (self.zoomactive) {
2008                  self.doZoom();
2009                  ret = true;
2010                }
2011                break;
2012            }
2013            if (ret) return self.cancelEvent(e);
2014          }
2015        };
2016
2017        if (self.opt.enablekeyboard) self.bind(document, (cap.isopera && !cap.isopera12) ? "keypress" : "keydown", self.onkeypress);
2018
2019        self.bind(document, "keydown", function(e) {
2020          var ctrl = e.ctrlKey || false;
2021          if (ctrl) self.wheelprevented = true;
2022        });
2023        self.bind(document, "keyup", function(e) {
2024          var ctrl = e.ctrlKey || false;
2025          if (!ctrl) self.wheelprevented = false;
2026        });
2027        self.bind(window,"blur",function(e){
2028          self.wheelprevented = false;
2029        });        
2030
2031        self.bind(window, 'resize', self.lazyResize);
2032        self.bind(window, 'orientationchange', self.lazyResize);
2033
2034        self.bind(window, "load", self.lazyResize);
2035
2036        if (cap.ischrome && !self.ispage && !self.haswrapper) { //chrome void scrollbar bug - it persists in version 26
2037          var tmp = self.win.attr("style");
2038          var ww = parseFloat(self.win.css("width")) + 1;
2039          self.win.css('width', ww);
2040          self.synched("chromefix", function() {
2041            self.win.attr("style", tmp);
2042          });
2043        }
2044
2045
2046        // Trying a cross-browser implementation - good luck!
2047
2048        self.onAttributeChange = function(e) {
2049          self.lazyResize(self.isieold ? 250 : 30);
2050        };
2051
2052        if ((!self.isie11) && (ClsMutationObserver !== false)) {  // IE11 crashes  #568
2053          self.observerbody = new ClsMutationObserver(function(mutations) {
2054            mutations.forEach(function(mut){
2055              if (mut.type=="attributes") {
2056                return ($("body").hasClass("modal-open") && $("body").hasClass("modal-dialog") && !$.contains($('.modal-dialog')[0],self.doc[0])) ? self.hide() : self.show();  // Support for Bootstrap modal; Added check if the nice scroll element is inside a modal
2057              }
2058            });
2059            // if (document.body.scrollHeight!=self.page.maxh) return self.lazyResize(30);
2060            if (self.me.clientWidth!=self.page.width || self.me.clientHeight!=self.page.height) return self.lazyResize(30);
2061          });
2062          self.observerbody.observe(document.body, {
2063            childList: true,
2064            subtree: true,
2065            characterData: false,
2066            attributes: true,
2067            attributeFilter: ['class']
2068          });
2069        }
2070        
2071        if (!self.ispage && !self.haswrapper) {
2072          // redesigned MutationObserver for Chrome18+/Firefox14+/iOS6+ with support for: remove div, add/remove content
2073          if (ClsMutationObserver !== false) {
2074            self.observer = new ClsMutationObserver(function(mutations) {
2075              mutations.forEach(self.onAttributeChange);
2076            });
2077            self.observer.observe(self.win[0], {
2078              childList: true,
2079              characterData: false,
2080              attributes: true,
2081              subtree: false
2082            });
2083            self.observerremover = new ClsMutationObserver(function(mutations) {
2084              mutations.forEach(function(mo) {
2085                if (mo.removedNodes.length > 0) {
2086                  for (var dd in mo.removedNodes) {
2087                    if (!!self && (mo.removedNodes[dd] == self.win[0])) return self.remove();
2088                  }
2089                }
2090              });
2091            });
2092            self.observerremover.observe(self.win[0].parentNode, {
2093              childList: true,
2094              characterData: false,
2095              attributes: false,
2096              subtree: false
2097            });
2098          } else {
2099            self.bind(self.win, (cap.isie && !cap.isie9) ? "propertychange" : "DOMAttrModified", self.onAttributeChange);
2100            if (cap.isie9) self.win[0].attachEvent("onpropertychange", self.onAttributeChange); //IE9 DOMAttrModified bug
2101            self.bind(self.win, "DOMNodeRemoved", function(e) {
2102              if (e.target == self.win[0]) self.remove();
2103            });
2104          }
2105        }
2106
2107        //
2108
2109        if (!self.ispage && self.opt.boxzoom) self.bind(window, "resize", self.resizeZoom);
2110				if (self.istextarea) {
2111					self.bind(self.win, "keydown", self.lazyResize);
2112					self.bind(self.win, "mouseup", self.lazyResize);
2113				}
2114
2115        //        self.checkrtlmode = true;
2116        self.lazyResize(30);
2117
2118      }
2119      
2120      if (this.doc[0].nodeName == 'IFRAME') {
2121        var oniframeload = function() {
2122          self.iframexd = false;
2123          var doc;
2124          try {
2125            doc = 'contentDocument' in this ? this.contentDocument : this.contentWindow.document;
2126            var a = doc.domain;
2127          } catch (e) {
2128            self.iframexd = true;
2129            doc = false;
2130          }
2131          
2132          if (self.iframexd) {
2133            if ("console" in window) console.log('NiceScroll error: policy restriced iframe');
2134            return true; //cross-domain - I can't manage this        
2135          }
2136
2137          self.forcescreen = true;
2138
2139          if (self.isiframe) {
2140            self.iframe = {
2141              "doc": $(doc),
2142              "html": self.doc.contents().find('html')[0],
2143              "body": self.doc.contents().find('body')[0]
2144            };
2145            self.getContentSize = function() {
2146              return {
2147                w: Math.max(self.iframe.html.scrollWidth, self.iframe.body.scrollWidth),
2148                h: Math.max(self.iframe.html.scrollHeight, self.iframe.body.scrollHeight)
2149              };
2150            };
2151            self.docscroll = $(self.iframe.body); //$(this.contentWindow);
2152          }
2153
2154          if (!cap.isios && self.opt.iframeautoresize && !self.isiframe) {
2155            self.win.scrollTop(0); // reset position
2156            self.doc.height(""); //reset height to fix browser bug
2157            var hh = Math.max(doc.getElementsByTagName('html')[0].scrollHeight, doc.body.scrollHeight);
2158            self.doc.height(hh);
2159          }
2160          self.lazyResize(30);
2161
2162          if (cap.isie7) self.css($(self.iframe.html), _scrollyhidden);
2163          self.css($(self.iframe.body), _scrollyhidden);
2164
2165          if (cap.isios && self.haswrapper) {
2166            self.css($(doc.body), {
2167              '-webkit-transform': 'translate3d(0,0,0)'
2168            }); // avoid iFrame content clipping - thanks to http://blog.derraab.com/2012/04/02/avoid-iframe-content-clipping-with-css-transform-on-ios/
2169          }
2170
2171          if ('contentWindow' in this) {
2172            self.bind(this.contentWindow, "scroll", self.onscroll); //IE8 & minor
2173          } else {
2174            self.bind(doc, "scroll", self.onscroll);
2175          }
2176
2177          if (self.opt.enablemousewheel) {
2178            self.mousewheel(doc, self.onmousewheel);
2179          }
2180
2181          if (self.opt.enablekeyboard) self.bind(doc, (cap.isopera) ? "keypress" : "keydown", self.onkeypress);
2182
2183          if (cap.cantouch || self.opt.touchbehavior) {
2184            self.bind(doc, "mousedown", self.ontouchstart);
2185            self.bind(doc, "mousemove", function(e) {
2186              return self.ontouchmove(e, true);
2187            });
2188            if (self.opt.grabcursorenabled && cap.cursorgrabvalue) self.css($(doc.body), {
2189              'cursor': cap.cursorgrabvalue
2190            });
2191          }
2192
2193          self.bind(doc, "mouseup", self.ontouchend);
2194
2195          if (self.zoom) {
2196            if (self.opt.dblclickzoom) self.bind(doc, 'dblclick', self.doZoom);
2197            if (self.ongesturezoom) self.bind(doc, "gestureend", self.ongesturezoom);
2198          }
2199        };
2200
2201        if (this.doc[0].readyState && this.doc[0].readyState == "complete") {
2202          setTimeout(function() {
2203            oniframeload.call(self.doc[0], false);
2204          }, 500);
2205        }
2206        self.bind(this.doc, "load", oniframeload);
2207
2208      }
2209
2210    };
2211
2212    this.showCursor = function(py, px) {
2213      if (self.cursortimeout) {
2214        clearTimeout(self.cursortimeout);
2215        self.cursortimeout = 0;
2216      }
2217      if (!self.rail) return;
2218      if (self.autohidedom) {
2219        self.autohidedom.stop().css({
2220          opacity: self.opt.cursoropacitymax
2221        });
2222        self.cursoractive = true;
2223      }
2224
2225      if (!self.rail.drag || self.rail.drag.pt != 1) {
2226        if (py !== undefined && py !== false) {
2227          self.scroll.y = Math.round(py * 1 / self.scrollratio.y);
2228        }
2229        if (px !== undefined) {
2230          self.scroll.x = Math.round(px * 1 / self.scrollratio.x);
2231        }
2232      }
2233
2234      self.cursor.css({
2235        height: self.cursorheight,
2236        top: self.scroll.y
2237      });
2238      if (self.cursorh) {        
2239        var lx = (self.hasreversehr) ? self.scrollvaluemaxw-self.scroll.x : self.scroll.x;
2240        (!self.rail.align && self.rail.visibility) ? self.cursorh.css({
2241          width: self.cursorwidth,
2242          left: lx + self.rail.width
2243        }): self.cursorh.css({
2244          width: self.cursorwidth,
2245          left: lx
2246        });
2247        self.cursoractive = true;
2248      }
2249
2250      if (self.zoom) self.zoom.stop().css({
2251        opacity: self.opt.cursoropacitymax
2252      });
2253    };
2254
2255    this.hideCursor = function(tm) {
2256      if (self.cursortimeout) return;
2257      if (!self.rail) return;
2258      if (!self.autohidedom) return;
2259      if (self.hasmousefocus && self.opt.autohidemode == "leave") return;
2260      self.cursortimeout = setTimeout(function() {
2261        if (!self.rail.active || !self.showonmouseevent) {
2262          self.autohidedom.stop().animate({
2263            opacity: self.opt.cursoropacitymin
2264          });
2265          if (self.zoom) self.zoom.stop().animate({
2266            opacity: self.opt.cursoropacitymin
2267          });
2268          self.cursoractive = false;
2269        }
2270        self.cursortimeout = 0;
2271      }, tm || self.opt.hidecursordelay);
2272    };
2273
2274    this.noticeCursor = function(tm, py, px) {
2275      self.showCursor(py, px);
2276      if (!self.rail.active) self.hideCursor(tm);
2277    };
2278
2279    this.getContentSize =
2280      (self.ispage) ?
2281      function() {
2282        return {
2283          w: Math.max(document.body.scrollWidth, document.documentElement.scrollWidth),
2284          h: Math.max(document.body.scrollHeight, document.documentElement.scrollHeight)
2285        };
2286      } : (self.haswrapper) ?
2287      function() {
2288        return {
2289          w: self.doc.outerWidth() + parseInt(self.win.css('paddingLeft')) + parseInt(self.win.css('paddingRight')),
2290          h: self.doc.outerHeight() + parseInt(self.win.css('paddingTop')) + parseInt(self.win.css('paddingBottom'))
2291        };
2292      } : function() {
2293        return {
2294          w: self.docscroll[0].scrollWidth,
2295          h: self.docscroll[0].scrollHeight
2296        };
2297      };
2298
2299    this.onResize = function(e, page) {
2300    
2301      if (!self || !self.win) return false;
2302
2303      if (!self.haswrapper && !self.ispage) {
2304        if (self.win.css('display') == 'none') {
2305          if (self.visibility) self.hideRail().hideRailHr();
2306          return false;
2307        } else {
2308          if (!self.hidden && !self.visibility) self.showRail().showRailHr();
2309        }
2310      }
2311
2312      var premaxh = self.page.maxh;
2313      var premaxw = self.page.maxw;
2314
2315      var preview = {
2316        h: self.view.h,
2317        w: self.view.w
2318      };
2319
2320      self.view = {
2321        w: (self.ispage) ? self.win.width() : parseInt(self.win[0].clientWidth),
2322        h: (self.ispage) ? self.win.height() : parseInt(self.win[0].clientHeight)
2323      };
2324
2325      self.page = (page) ? page : self.getContentSize();
2326
2327      self.page.maxh = Math.max(0, self.page.h - self.view.h);
2328      self.page.maxw = Math.max(0, self.page.w - self.view.w);
2329      
2330      if ((self.page.maxh == premaxh) && (self.page.maxw == premaxw) && (self.view.w == preview.w) && (self.view.h == preview.h)) {
2331        // test position        
2332        if (!self.ispage) {
2333          var pos = self.win.offset();
2334          if (self.lastposition) {
2335            var lst = self.lastposition;
2336            if ((lst.top == pos.top) && (lst.left == pos.left)) return self; //nothing to do            
2337          }
2338          self.lastposition = pos;
2339        } else {
2340          return self; //nothing to do
2341        }
2342      }
2343
2344      if (self.page.maxh == 0) {
2345        self.hideRail();
2346        self.scrollvaluemax = 0;
2347        self.scroll.y = 0;
2348        self.scrollratio.y = 0;
2349        self.cursorheight = 0;
2350        self.setScrollTop(0);
2351        if (self.rail) self.rail.scrollable = false;
2352      } else {
2353        self.page.maxh -= (self.opt.railpadding.top + self.opt.railpadding.bottom);  //**
2354        self.rail.scrollable = true;
2355      }
2356
2357      if (self.page.maxw == 0) {
2358        self.hideRailHr();
2359        self.scrollvaluemaxw = 0;
2360        self.scroll.x = 0;
2361        self.scrollratio.x = 0;
2362        self.cursorwidth = 0;
2363        self.setScrollLeft(0);
2364        if (self.railh) {
2365          self.railh.scrollable = false;
2366        }
2367      } else {
2368          self.page.maxw -= (self.opt.railpadding.left + self.opt.railpadding.right);  //**
2369          if (self.railh) self.railh.scrollable = (self.opt.horizrailenabled);
2370      }
2371
2372      self.railslocked = (self.locked) || ((self.page.maxh == 0) && (self.page.maxw == 0));
2373      if (self.railslocked) {
2374        if (!self.ispage) self.updateScrollBar(self.view);
2375        return false;
2376      }
2377
2378      if (!self.hidden && !self.visibility) {
2379        self.showRail().showRailHr();
2380      }
2381      else if (self.railh && (!self.hidden && !self.railh.visibility)) self.showRailHr();
2382
2383      if (self.istextarea && self.win.css('resize') && self.win.css('resize') != 'none') self.view.h -= 20;
2384
2385      self.cursorheight = Math.min(self.view.h, Math.round(self.view.h * (self.view.h / self.page.h)));
2386      self.cursorheight = (self.opt.cursorfixedheight) ? self.opt.cursorfixedheight : Math.max(self.opt.cursorminheight, self.cursorheight);
2387
2388      self.cursorwidth = Math.min(self.view.w, Math.round(self.view.w * (self.view.w / self.page.w)));
2389      self.cursorwidth = (self.opt.cursorfixedheight) ? self.opt.cursorfixedheight : Math.max(self.opt.cursorminheight, self.cursorwidth);
2390
2391      self.scrollvaluemax = self.view.h - self.cursorheight - self.cursor.hborder - (self.opt.railpadding.top + self.opt.railpadding.bottom);  //**
2392
2393      if (self.railh) {
2394        self.railh.width = (self.page.maxh > 0) ? (self.view.w - self.rail.width) : self.view.w;
2395        self.scrollvaluemaxw = self.railh.width - self.cursorwidth - self.cursorh.wborder - (self.opt.railpadding.left + self.opt.railpadding.right);  //**
2396      }
2397
2398      /*
2399      if (self.checkrtlmode&&self.railh) {
2400        self.checkrtlmode = false;
2401        if (self.opt.rtlmode&&self.scroll.x==0) self.setScrollLeft(self.page.maxw);
2402      }
2403*/
2404
2405      if (!self.ispage) self.updateScrollBar(self.view);
2406
2407      self.scrollratio = {
2408        x: (self.page.maxw / self.scrollvaluemaxw),
2409        y: (self.page.maxh / self.scrollvaluemax)
2410      };
2411
2412      var sy = self.getScrollTop();
2413      if (sy > self.page.maxh) {
2414        self.doScrollTop(self.page.maxh);
2415      } else {
2416        self.scroll.y = Math.round(self.getScrollTop() * (1 / self.scrollratio.y));
2417        self.scroll.x = Math.round(self.getScrollLeft() * (1 / self.scrollratio.x));
2418        if (self.cursoractive) self.noticeCursor();
2419      }
2420
2421      if (self.scroll.y && (self.getScrollTop() == 0)) self.doScrollTo(Math.floor(self.scroll.y * self.scrollratio.y));
2422
2423      return self;
2424    };
2425
2426    this.resize = self.onResize;
2427
2428		this.hlazyresize = 0;
2429		
2430    this.lazyResize = function(tm) { // event debounce
2431/*		
2432      tm = (isNaN(tm)) ? 30 : tm;
2433      self.debounced('resize', self.resize, tm);
2434*/
2435
2436//			if (!self.haswrapper&&self.opt.autohidemode!==false) self.hide();	
2437			if (!self.haswrapper) self.hide();	
2438			if (self.hlazyresize) clearTimeout(self.hlazyresize);
2439			self.hlazyresize = setTimeout(function(){
2440				self && self.show().resize();
2441			},240);
2442			
2443      return self;
2444    };
2445
2446    // modified by MDN https://developer.mozilla.org/en-US/docs/DOM/Mozilla_event_reference/wheel
2447    function _modernWheelEvent(dom, name, fn, bubble) {
2448      self._bind(dom, name, function(e) {
2449        var e = (e) ? e : window.event;
2450        var event = {
2451          original: e,
2452          target: e.target || e.srcElement,
2453          type: "wheel",
2454          deltaMode: e.type == "MozMousePixelScroll" ? 0 : 1,
2455          deltaX: 0,
2456          deltaZ: 0,
2457          preventDefault: function() {
2458            e.preventDefault ? e.preventDefault() : e.returnValue = false;
2459            return false;
2460          },
2461          stopImmediatePropagation: function() {
2462            (e.stopImmediatePropagation) ? e.stopImmediatePropagation(): e.cancelBubble = true;
2463          }
2464        };
2465
2466        if (name == "mousewheel") {
2467          e.wheelDeltaX && (event.deltaX = -1 / 40 * e.wheelDeltaX);
2468					e.wheelDeltaY && (event.deltaY = -1 / 40 * e.wheelDeltaY);
2469					!event.deltaY && !event.deltaX && (event.deltaY = -1 / 40 * e.wheelDelta);
2470        } else {
2471          event.deltaY = e.detail;
2472        }
2473
2474        return fn.call(dom, event);
2475      }, bubble);
2476    }
2477
2478
2479
2480    this.jqbind = function(dom, name, fn) { // use jquery bind for non-native events (mouseenter/mouseleave)
2481      self.events.push({
2482        e: dom,
2483        n: name,
2484        f: fn,
2485        q: true
2486      });
2487      $(dom).bind(name, fn);
2488    };
2489    
2490    this.mousewheel = function(dom, fn, bubble) { // bind mousewheel
2491      var el = ("jquery" in dom) ? dom[0] : dom;
2492      if ("onwheel" in document.createElement("div")) { // Modern browsers support "wheel"
2493        self._bind(el, "wheel", fn, bubble || false);
2494      } else {
2495        var wname = (document.onmousewheel !== undefined) ? "mousewheel" : "DOMMouseScroll"; // older Webkit+IE support or older Firefox          
2496        _modernWheelEvent(el, wname, fn, bubble || false);
2497        if (wname == "DOMMouseScroll") _modernWheelEvent(el, "MozMousePixelScroll", fn, bubble || false); // Firefox legacy
2498      }
2499    };
2500    
2501    if (cap.haseventlistener) {  // W3C standard event model
2502    
2503      this.bind = function(dom, name, fn, bubble) {  // W3C
2504        var el = ("jquery" in dom) ? dom[0] : dom;
2505        self._bind(el, name, fn, bubble || false);
2506      };
2507    
2508      this._bind = function(el, name, fn, bubble) { // primitive bind
2509        self.events.push({
2510          e: el,
2511          n: name,
2512          f: fn,
2513          b: bubble,
2514          q: false
2515        });
2516        el.addEventListener(name, fn, bubble || false);
2517      };    
2518      this.cancelEvent = function(e) {
2519        if (!e) return false;
2520        var e = (e.original) ? e.original : e;
2521        if (e.cancelable) e.preventDefault();
2522        e.stopPropagation();
2523        if (e.preventManipulation) e.preventManipulation(); //IE10
2524        return false;
2525      };
2526      this.stopPropagation = function(e) {
2527        if (!e) return false;
2528        var e = (e.original) ? e.original : e;
2529        e.stopPropagation();
2530        return false;
2531      };
2532      this._unbind = function(el, name, fn, bub) { // primitive unbind
2533        el.removeEventListener(name, fn, bub);
2534      };
2535    } else {  // old IE model
2536
2537      this.bind = function(dom, name, fn, bubble) {  // legacy IE
2538        var el = ("jquery" in dom) ? dom[0] : dom;
2539        self._bind(el, name, function(e) {
2540          e = e || window.event || false;
2541          if (e && e.srcElement) {
2542            e.target = e.srcElement;
2543          }
2544          if (!("pageY" in e)) {
2545            e.pageX = e.clientX + document.documentElement.scrollLeft;
2546            e.pageY = e.clientY + document.documentElement.scrollTop;
2547          }
2548          return ((fn.call(el, e) === false) || bubble === false) ? self.cancelEvent(e) : true;
2549        });
2550      };
2551    
2552      this._bind = function(el, name, fn, bubble) { // primitive bind
2553        self.events.push({
2554          e: el,
2555          n: name,
2556          f: fn,
2557          b: bubble,
2558          q: false
2559        });
2560        if (el.attachEvent) {
2561          el.attachEvent("on" + name, fn);
2562        } else {
2563          el["on" + name] = fn;
2564        }
2565      };    
2566      // Thanks to http://www.switchonthecode.com !!
2567      this.cancelEvent = function(e) {
2568        var e = window.event || false;
2569        if (!e) return false;
2570        e.cancelBubble = true;
2571        e.cancel = true;
2572        e.returnValue = false;
2573        return false;
2574      };
2575      this.stopPropagation = function(e) {
2576        var e = window.event || false;
2577        if (!e) return false;
2578        e.cancelBubble = true;
2579        return false;
2580      };
2581      this._unbind = function(el, name, fn, bub) { // primitive unbind IE old
2582        if (el.detachEvent) {
2583          el.detachEvent('on' + name, fn);
2584        } else {
2585          el['on' + name] = false;
2586        }
2587      };
2588    }
2589    
2590    this.unbindAll = function() {
2591      for (var a = 0; a < self.events.length; a++) {
2592        var r = self.events[a];
2593        (r.q) ? r.e.unbind(r.n, r.f): self._unbind(r.e, r.n, r.f, r.b);
2594      }
2595    };
2596
2597    this.showRail = function() {
2598      if ((self.page.maxh != 0) && (self.ispage || self.win.css('display') != 'none')) {
2599        self.visibility = true;
2600        self.rail.visibility = true;
2601        self.rail.css('display', 'block');
2602      }
2603      return self;
2604    };
2605
2606    this.showRailHr = function() {
2607      if (!self.railh) return self;
2608      if ((self.page.maxw != 0) && (self.ispage || self.win.css('display') != 'none')) {
2609        self.railh.visibility = true;
2610        self.railh.css('display', 'block');
2611      }
2612      return self;
2613    };
2614
2615    this.hideRail = function() {
2616      self.visibility = false;
2617      self.rail.visibility = false;
2618      self.rail.css('display', 'none');
2619      return self;
2620    };
2621
2622    this.hideRailHr = function() {
2623      if (!self.railh) return self;
2624      self.railh.visibility = false;
2625      self.railh.css('display', 'none');
2626      return self;
2627    };
2628
2629    this.show = function() {
2630      self.hidden = false;
2631      self.railslocked = false;
2632      return self.showRail().showRailHr();
2633    };
2634
2635    this.hide = function() {
2636      self.hidden = true;
2637      self.railslocked = true;
2638      return self.hideRail().hideRailHr();
2639    };
2640
2641    this.toggle = function() {
2642      return (self.hidden) ? self.show() : self.hide();
2643    };
2644
2645    this.remove = function() {
2646      self.stop();
2647      if (self.cursortimeout) clearTimeout(self.cursortimeout);
2648//      if (self.debouncedelayed) clearTimeout(self.debouncedelayed);
2649			for(var n in self.delaylist) if (self.delaylist[n]) clearAnimationFrame(self.delaylist[n].h);
2650      self.doZoomOut();
2651      self.unbindAll();
2652
2653      if (cap.isie9) self.win[0].detachEvent("onpropertychange", self.onAttributeChange); //IE9 DOMAttrModified bug
2654
2655      if (self.observer !== false) self.observer.disconnect();
2656      if (self.observerremover !== false) self.observerremover.disconnect();
2657      if (self.observerbody !== false) self.observerbody.disconnect();
2658
2659      self.events = null;
2660
2661      if (self.cursor) {
2662        self.cursor.remove();
2663      }
2664      if (self.cursorh) {
2665        self.cursorh.remove();
2666      }
2667      if (self.rail) {
2668        self.rail.remove();
2669      }
2670      if (self.railh) {
2671        self.railh.remove();
2672      }
2673      if (self.zoom) {
2674        self.zoom.remove();
2675      }
2676      for (var a = 0; a < self.saved.css.length; a++) {
2677        var d = self.saved.css[a];
2678        d[0].css(d[1], (d[2] === undefined) ? '' : d[2]);
2679      }
2680      self.saved = false;
2681      self.me.data('__nicescroll', ''); //erase all traces
2682
2683      // memory leak fixed by GianlucaGuarini - thanks a lot!
2684      // remove the current nicescroll from the $.nicescroll array & normalize array
2685      var lst = $.nicescroll;
2686      lst.each(function(i) {
2687        if (!this) return;
2688        if (this.id === self.id) {
2689          delete lst[i];
2690          for (var b = ++i; b < lst.length; b++, i++) lst[i] = lst[b];
2691          lst.length--;
2692          if (lst.length) delete lst[lst.length];
2693        }
2694      });
2695
2696      for (var i in self) {
2697        self[i] = null;
2698        delete self[i];
2699      }
2700
2701      self = null;
2702
2703    };
2704
2705    this.scrollstart = function(fn) {
2706      this.onscrollstart = fn;
2707      return self;
2708    };
2709    this.scrollend = function(fn) {
2710      this.onscrollend = fn;
2711      return self;
2712    };
2713    this.scrollcancel = function(fn) {
2714      this.onscrollcancel = fn;
2715      return self;
2716    };
2717
2718    this.zoomin = function(fn) {
2719      this.onzoomin = fn;
2720      return self;
2721    };
2722    this.zoomout = function(fn) {
2723      this.onzoomout = fn;
2724      return self;
2725    };
2726
2727    this.isScrollable = function(e) {
2728      var dom = (e.target) ? e.target : e;
2729      if (dom.nodeName == 'OPTION') return true;
2730      while (dom && (dom.nodeType == 1) && (dom !== this.me[0]) && !(/^BODY|HTML/.test(dom.nodeName))) {
2731        var dd = $(dom);
2732        var ov = dd.css('overflowY') || dd.css('overflowX') || dd.css('overflow') || '';
2733        if (/scroll|auto/.test(ov)) return (dom.clientHeight != dom.scrollHeight);
2734        dom = (dom.parentNode) ? dom.parentNode : false;
2735      }
2736      return false;
2737    };
2738
2739    this.getViewport = function(me) {
2740      var dom = (me && me.parentNode) ? me.parentNode : false;
2741      while (dom && (dom.nodeType == 1) && !(/^BODY|HTML/.test(dom.nodeName))) {
2742        var dd = $(dom);
2743        if (/fixed|absolute/.test(dd.css("position"))) return dd;
2744        var ov = dd.css('overflowY') || dd.css('overflowX') || dd.css('overflow') || '';
2745        if ((/scroll|auto/.test(ov)) && (dom.clientHeight != dom.scrollHeight)) return dd;
2746        if (dd.getNiceScroll().length > 0) return dd;
2747        dom = (dom.parentNode) ? dom.parentNode : false;
2748      }
2749      return false; //(dom) ? $(dom) : false;
2750    };
2751
2752    this.triggerScrollEnd = function() {
2753      if (!self.onscrollend) return;
2754
2755      var px = self.getScrollLeft();
2756      var py = self.getScrollTop();
2757
2758      var info = {
2759        type: "scrollend",
2760        current: {
2761          x: px,
2762          y: py
2763        },
2764        end: {
2765          x: px,
2766          y: py
2767        }
2768      };
2769      self.onscrollend.call(self, info);
2770    };
2771
2772    function execScrollWheel(e, hr, chkscroll) {
2773      var px, py;
2774      
2775      if (e.deltaMode == 0) { // PIXEL
2776        px = -Math.floor(e.deltaX * (self.opt.mousescrollstep / (18 * 3)));
2777        py = -Math.floor(e.deltaY * (self.opt.mousescrollstep / (18 * 3)));
2778      } else if (e.deltaMode == 1) { // LINE
2779        px = -Math.floor(e.deltaX * self.opt.mousescrollstep);
2780        py = -Math.floor(e.deltaY * self.opt.mousescrollstep);
2781      }
2782
2783      if (hr && self.opt.oneaxismousemode && (px == 0) && py) { // classic vertical-only mousewheel + browser with x/y support 
2784        px = py;
2785        py = 0;
2786      
2787        if (chkscroll) {
2788          var hrend = (px < 0) ? (self.getScrollLeft() >= self.page.maxw) : (self.getScrollLeft() <= 0);
2789          if (hrend) {  // preserve vertical scrolling
2790            py = px;
2791            px = 0;            
2792          }
2793        }
2794        
2795      }
2796
2797      // invert horizontal direction for rtl mode
2798      if (self.isrtlmode) px = -px;
2799
2800      if (px) {
2801        if (self.scrollmom) {
2802          self.scrollmom.stop();
2803        }
2804        self.lastdeltax += px;
2805        self.debounced("mousewheelx", function() {
2806          var dt = self.lastdeltax;
2807          self.lastdeltax = 0;
2808          if (!self.rail.drag) {
2809            self.doScrollLeftBy(dt);
2810          }
2811        }, 15);
2812      }
2813      if (py) {
2814        if (self.opt.nativeparentscrolling && chkscroll && !self.ispage && !self.zoomactive) {
2815          if (py < 0) {
2816            if (self.getScrollTop() >= self.page.maxh) return true;
2817          } else {
2818            if (self.getScrollTop() <= 0) return true;
2819          }
2820        }
2821        if (self.scrollmom) {
2822          self.scrollmom.stop();
2823        }
2824        self.lastdeltay += py;
2825//        self.debounced("mousewheely", function() {
2826	      self.synched("mousewheely", function() {
2827          var dt = self.lastdeltay;
2828          self.lastdeltay = 0;
2829          if (!self.rail.drag) {
2830            self.doScrollBy(dt);
2831          }
2832        }, 15);
2833      }
2834
2835      e.stopImmediatePropagation();
2836      return e.preventDefault();
2837    }
2838
2839    this.onmousewheel = function(e) {
2840      if (self.wheelprevented) return;
2841      if (self.railslocked) {
2842        self.debounced("checkunlock", self.resize, 250);
2843        return true;
2844      }
2845      if (self.rail.drag) return self.cancelEvent(e);
2846
2847      if (self.opt.oneaxismousemode == "auto" && e.deltaX != 0) self.opt.oneaxismousemode = false; // check two-axis mouse support (not very elegant)
2848
2849      if (self.opt.oneaxismousemode && e.deltaX == 0) {
2850        if (!self.rail.scrollable) {
2851          if (self.railh && self.railh.scrollable) {
2852            return self.onmousewheelhr(e);
2853          } else {
2854            return true;
2855          }
2856        }
2857      }
2858
2859      var nw = +(new Date());
2860      var chk = false;
2861      if (self.opt.preservenativescrolling && ((self.checkarea + 600) < nw)) {
2862        self.nativescrollingarea = self.isScrollable(e);
2863        chk = true;
2864      }
2865      self.checkarea = nw;
2866      if (self.nativescrollingarea) return true; // this isn't my business
2867      var ret = execScrollWheel(e, false, chk);
2868      if (ret) self.checkarea = 0;
2869      return ret;
2870    };
2871
2872    this.onmousewheelhr = function(e) {
2873      if (self.wheelprevented) return;
2874      if (self.railslocked || !self.railh.scrollable) return true;
2875      if (self.rail.drag) return self.cancelEvent(e);
2876
2877      var nw = +(new Date());
2878      var chk = false;
2879      if (self.opt.preservenativescrolling && ((self.checkarea + 600) < nw)) {
2880        self.nativescrollingarea = self.isScrollable(e);
2881        chk = true;
2882      }
2883      self.checkarea = nw;
2884      if (self.nativescrollingarea) return true; // this isn't my business
2885      if (self.railslocked) return self.cancelEvent(e);
2886
2887      return execScrollWheel(e, true, chk);
2888    };
2889
2890    this.stop = function() {
2891      self.cancelScroll();
2892      if (self.scrollmon) self.scrollmon.stop();
2893      self.cursorfreezed = false;
2894      self.scroll.y = Math.round(self.getScrollTop() * (1 / self.scrollratio.y));
2895      self.noticeCursor();
2896      return self;
2897    };
2898
2899    this.getTransitionSpeed = function(dif) {
2900      var sp = Math.round(self.opt.scrollspeed * 10);
2901      var ex = Math.min(sp, Math.round((dif / 20) * self.opt.scrollspeed));
2902      return (ex > 20) ? ex : 0;
2903    };
2904
2905    if (!self.opt.smoothscroll) {
2906      this.doScrollLeft = function(x, spd) { //direct
2907        var y = self.getScrollTop();
2908        self.doScrollPos(x, y, spd);
2909      };
2910      this.doScrollTop = function(y, spd) { //direct
2911        var x = self.getScrollLeft();
2912        self.doScrollPos(x, y, spd);
2913      };
2914      this.doScrollPos = function(x, y, spd) { //direct
2915        var nx = (x > self.page.maxw) ? self.page.maxw : x;
2916        if (nx < 0) nx = 0;
2917        var ny = (y > self.page.maxh) ? self.page.maxh : y;
2918        if (ny < 0) ny = 0;
2919        self.synched('scroll', function() {
2920          self.setScrollTop(ny);
2921          self.setScrollLeft(nx);
2922        });
2923      };
2924      this.cancelScroll = function() {}; // direct
2925    } else if (self.ishwscroll && cap.hastransition && self.opt.usetransition && !!self.opt.smoothscroll) {
2926      this.prepareTransition = function(dif, istime) {
2927        var ex = (istime) ? ((dif > 20) ? dif : 0) : self.getTransitionSpeed(dif);
2928        var trans = (ex) ? cap.prefixstyle + 'transform ' + ex + 'ms ease-out' : '';
2929        if (!self.lasttransitionstyle || self.lasttransitionstyle != trans) {
2930          self.lasttransitionstyle = trans;
2931          self.doc.css(cap.transitionstyle, trans);
2932        }
2933        return ex;
2934      };
2935
2936      this.doScrollLeft = function(x, spd) { //trans
2937        var y = (self.scrollrunning) ? self.newscrolly : self.getScrollTop();
2938        self.doScrollPos(x, y, spd);
2939      };
2940
2941      this.doScrollTop = function(y, spd) { //trans
2942        var x = (self.scrollrunning) ? self.newscrollx : self.getScrollLeft();
2943        self.doScrollPos(x, y, spd);
2944      };
2945
2946      this.doScrollPos = function(x, y, spd) { //trans
2947
2948        var py = self.getScrollTop();
2949        var px = self.getScrollLeft();
2950
2951        if (((self.newscrolly - py) * (y - py) < 0) || ((self.newscrollx - px) * (x - px) < 0)) self.cancelScroll(); //inverted movement detection      
2952
2953        if (self.opt.bouncescroll == false) {
2954          if (y < 0) y = 0;
2955          else if (y > self.page.maxh) y = self.page.maxh;
2956          if (x < 0) x = 0;
2957          else if (x > self.page.maxw) x = self.page.maxw;
2958        }
2959
2960        if (self.scrollrunning && x == self.newscrollx && y == self.newscrolly) return false;
2961
2962        self.newscrolly = y;
2963        self.newscrollx = x;
2964
2965        self.newscrollspeed = spd || false;
2966
2967        if (self.timer) return false;
2968
2969        self.timer = setTimeout(function() {
2970
2971          var top = self.getScrollTop();
2972          var lft = self.getScrollLeft();
2973
2974          var dst = {};
2975          dst.x = x - lft;
2976          dst.y = y - top;
2977          dst.px = lft;
2978          dst.py = top;
2979
2980          var dd = Math.round(Math.sqrt(Math.pow(dst.x, 2) + Math.pow(dst.y, 2)));
2981          var ms = (self.newscrollspeed && self.newscrollspeed > 1) ? self.newscrollspeed : self.getTransitionSpeed(dd);
2982          if (self.newscrollspeed && self.newscrollspeed <= 1) ms *= self.newscrollspeed;
2983
2984          self.prepareTransition(ms, true);
2985
2986          if (self.timerscroll && self.timerscroll.tm) clearInterval(self.timerscroll.tm);
2987
2988          if (ms > 0) {
2989
2990            if (!self.scrollrunning && self.onscrollstart) {
2991              var info = {
2992                "type": "scrollstart",
2993                "current": {
2994                  "x": lft,
2995                  "y": top
2996                },
2997                "request": {
2998                  "x": x,
2999                  "y": y
3000                },
3001                "end": {
3002                  "x": self.newscrollx,
3003                  "y": self.newscrolly
3004                },
3005                "speed": ms
3006              };
3007              self.onscrollstart.call(self, info);
3008            }
3009
3010            if (cap.transitionend) {
3011              if (!self.scrollendtrapped) {
3012                self.scrollendtrapped = true;
3013                self.bind(self.doc, cap.transitionend, self.onScrollTransitionEnd, false); //I have got to do something usefull!!
3014              }
3015            } else {
3016              if (self.scrollendtrapped) clearTimeout(self.scrollendtrapped);
3017              self.scrollendtrapped = setTimeout(self.onScrollTransitionEnd, ms); // simulate transitionend event
3018            }
3019
3020            var py = top;
3021            var px = lft;
3022            self.timerscroll = {
3023              bz: new BezierClass(py, self.newscrolly, ms, 0, 0, 0.58, 1),
3024              bh: new BezierClass(px, self.newscrollx, ms, 0, 0, 0.58, 1)
3025            };
3026            if (!self.cursorfreezed) self.timerscroll.tm = setInterval(function() {
3027              self.showCursor(self.getScrollTop(), self.getScrollLeft());
3028            }, 60);
3029
3030          }
3031
3032          self.synched("doScroll-set", function() {
3033            self.timer = 0;
3034            if (self.scrollendtrapped) self.scrollrunning = true;
3035            self.setScrollTop(self.newscrolly);
3036            self.setScrollLeft(self.newscrollx);
3037            if (!self.scrollendtrapped) self.onScrollTransitionEnd();
3038          });
3039
3040
3041        }, 50);
3042
3043      };
3044
3045      this.cancelScroll = function() {
3046        if (!self.scrollendtrapped) return true;
3047        var py = self.getScrollTop();
3048        var px = self.getScrollLeft();
3049        self.scrollrunning = false;
3050        if (!cap.transitionend) clearTimeout(cap.transitionend);
3051        self.scrollendtrapped = false;
3052        self._unbind(self.doc[0], cap.transitionend, self.onScrollTransitionEnd);
3053        self.prepareTransition(0);
3054        self.setScrollTop(py); // fire event onscroll
3055        if (self.railh) self.setScrollLeft(px);
3056        if (self.timerscroll && self.timerscroll.tm) clearInterval(self.timerscroll.tm);
3057        self.timerscroll = false;
3058
3059        self.cursorfreezed = false;
3060
3061        self.showCursor(py, px);
3062        return self;
3063      };
3064      this.onScrollTransitionEnd = function() {
3065        if (self.scrollendtrapped) self._unbind(self.doc[0], cap.transitionend, self.onScrollTransitionEnd);
3066        self.scrollendtrapped = false;
3067        self.prepareTransition(0);
3068        if (self.timerscroll && self.timerscroll.tm) clearInterval(self.timerscroll.tm);
3069        self.timerscroll = false;
3070        var py = self.getScrollTop();
3071        var px = self.getScrollLeft();
3072        self.setScrollTop(py); // fire event onscroll        
3073        if (self.railh) self.setScrollLeft(px);
3073 // fire event onscroll left
3074
3075        self.noticeCursor(false, py, px);
3076
3077        self.cursorfreezed = false;
3078
3079        if (py < 0) py = 0;
3080        else if (py > self.page.maxh) py = self.page.maxh;
3081        if (px < 0) px = 0;
3082        else if (px > self.page.maxw) px = self.page.maxw;
3083        if ((py != self.newscrolly) || (px != self.newscrollx)) return self.doScrollPos(px, py, self.opt.snapbackspeed);
3084
3085        if (self.onscrollend && self.scrollrunning) {
3086          self.triggerScrollEnd();
3087        }
3088        self.scrollrunning = false;
3089
3090      };
3091
3092    } else {
3093
3094      this.doScrollLeft = function(x, spd) { //no-trans
3095        var y = (self.scrollrunning) ? self.newscrolly : self.getScrollTop();
3096        self.doScrollPos(x, y, spd);
3097      };
3098
3099      this.doScrollTop = function(y, spd) { //no-trans
3100        var x = (self.scrollrunning) ? self.newscrollx : self.getScrollLeft();
3101        self.doScrollPos(x, y, spd);
3102      };
3103
3104      this.doScrollPos = function(x, y, spd) { //no-trans
3105        var y = (y === undefined || y === false) ? self.getScrollTop(true) : y;
3106
3107        if ((self.timer) && (self.newscrolly == y) && (self.newscrollx == x)) return true;
3108
3109        if (self.timer) clearAnimationFrame(self.timer);
3110        self.timer = 0;
3111
3112        var py = self.getScrollTop();
3113        var px = self.getScrollLeft();
3114
3115        if (((self.newscrolly - py) * (y - py) < 0) || ((self.newscrollx - px) * (x - px) < 0)) self.cancelScroll(); //inverted movement detection
3116
3117        self.newscrolly = y;
3118        self.newscrollx = x;
3119
3120        if (!self.bouncescroll || !self.rail.visibility) {
3121          if (self.newscrolly < 0) {
3122            self.newscrolly = 0;
3123          } else if (self.newscrolly > self.page.maxh) {
3124            self.newscrolly = self.page.maxh;
3125          }
3126        }
3127        if (!self.bouncescroll || !self.railh.visibility) {
3128          if (self.newscrollx < 0) {
3129            self.newscrollx = 0;
3130          } else if (self.newscrollx > self.page.maxw) {
3131            self.newscrollx = self.page.maxw;
3132          }
3133        }
3134
3135        self.dst = {};
3136        self.dst.x = x - px;
3137        self.dst.y = y - py;
3138        self.dst.px = px;
3139        self.dst.py = py;
3140
3141        var dst = Math.round(Math.sqrt(Math.pow(self.dst.x, 2) + Math.pow(self.dst.y, 2)));
3142
3143        self.dst.ax = self.dst.x / dst;
3144        self.dst.ay = self.dst.y / dst;
3145
3146        var pa = 0;
3147        var pe = dst;
3148
3149        if (self.dst.x == 0) {
3150          pa = py;
3151          pe = y;
3152          self.dst.ay = 1;
3153          self.dst.py = 0;
3154        } else if (self.dst.y == 0) {
3155          pa = px;
3156          pe = x;
3157          self.dst.ax = 1;
3158          self.dst.px = 0;
3159        }
3160
3161        var ms = self.getTransitionSpeed(dst);
3162        if (spd && spd <= 1) ms *= spd;
3163        if (ms > 0) {
3164          self.bzscroll = (self.bzscroll) ? self.bzscroll.update(pe, ms) : new BezierClass(pa, pe, ms, 0, 1, 0, 1);
3165        } else {
3166          self.bzscroll = false;
3167        }
3168
3169        if (self.timer) return;
3170
3171        if ((py == self.page.maxh && y >= self.page.maxh) || (px == self.page.maxw && x >= self.page.maxw)) self.checkContentSize();
3172
3173        var sync = 1;
3174
3175        function scrolling() {
3176          if (self.cancelAnimationFrame) return true;
3177
3178          self.scrollrunning = true;
3179
3180          sync = 1 - sync;
3181          if (sync) return (self.timer = setAnimationFrame(scrolling) || 1);
3182
3183          var done = 0;
3184          var sx, sy;
3185
3186          var sc = sy = self.getScrollTop();
3187          if (self.dst.ay) {
3188            sc = (self.bzscroll) ? self.dst.py + (self.bzscroll.getNow() * self.dst.ay) : self.newscrolly;
3189            var dr = sc - sy;
3190            if ((dr < 0 && sc < self.newscrolly) || (dr > 0 && sc > self.newscrolly)) sc = self.newscrolly;
3191            self.setScrollTop(sc);
3192            if (sc == self.newscrolly) done = 1;
3193          } else {
3194            done = 1;
3195          }
3196
3197          var scx = sx = self.getScrollLeft();
3198          if (self.dst.ax) {
3199            scx = (self.bzscroll) ? self.dst.px + (self.bzscroll.getNow() * self.dst.ax) : self.newscrollx;
3200            var dr = scx - sx;
3201            if ((dr < 0 && scx < self.newscrollx) || (dr > 0 && scx > self.newscrollx)) scx = self.newscrollx;
3202            self.setScrollLeft(scx);
3203            if (scx == self.newscrollx) done += 1;
3204          } else {
3205            done += 1;
3206          }
3207
3208          if (done == 2) {
3209            self.timer = 0;
3210            self.cursorfreezed = false;
3211            self.bzscroll = false;
3212            self.scrollrunning = false;
3213            if (sc < 0) sc = 0;
3214            else if (sc > self.page.maxh) sc = Math.max(0,self.page.maxh);
3215            if (scx < 0) scx = 0;
3216            else if (scx > self.page.maxw) scx = self.page.maxw;
3217            if ((scx != self.newscrollx) || (sc != self.newscrolly)) self.doScrollPos(scx, sc);
3218            else {
3219              if (self.onscrollend) {
3220                self.triggerScrollEnd();
3221              }
3222            }
3223          } else {
3224            self.timer = setAnimationFrame(scrolling) || 1;
3225          }
3226        }
3227        self.cancelAnimationFrame = false;
3228        self.timer = 1;
3229
3230        if (self.onscrollstart && !self.scrollrunning) {
3231          var info = {
3232            "type": "scrollstart",
3233            "current": {
3234              "x": px,
3235              "y": py
3236            },
3237            "request": {
3238              "x": x,
3239              "y": y
3240            },
3241            "end": {
3242              "x": self.newscrollx,
3243              "y": self.newscrolly
3244            },
3245            "speed": ms
3246          };
3247          self.onscrollstart.call(self, info);
3248        }
3249
3250        scrolling();
3251
3252        if ((py == self.page.maxh && y >= py) || (px == self.page.maxw && x >= px)) self.checkContentSize();
3253
3254        self.noticeCursor();
3255      };
3256
3257      this.cancelScroll = function() {
3258        if (self.timer) clearAnimationFrame(self.timer);
3259        self.timer = 0;
3260        self.bzscroll = false;
3261        self.scrollrunning = false;
3262        return self;
3263      };
3264
3265    }
3266
3267    this.doScrollBy = function(stp, relative) {
3268      var ny = 0;
3269      if (relative) {
3270        ny = Math.floor((self.scroll.y - stp) * self.scrollratio.y);
3271      } else {
3272        var sy = (self.timer) ? self.newscrolly : self.getScrollTop(true);
3273        ny = sy - stp;
3274      }
3275      if (self.bouncescroll) {
3276        var haf = Math.round(self.view.h / 2);
3277        if (ny < -haf) ny = -haf;
3278        else if (ny > (self.page.maxh + haf)) ny = (self.page.maxh + haf);
3279      }
3280      self.cursorfreezed = false;
3281
3282      var py = self.getScrollTop(true);
3283      if (ny < 0 && py <= 0) return self.noticeCursor();
3284      else if (ny > self.page.maxh && py >= self.page.maxh) {
3285        self.checkContentSize();
3286        return self.noticeCursor();
3287      }
3288
3289      self.doScrollTop(ny);
3290    };
3291
3292    this.doScrollLeftBy = function(stp, relative) {
3293      var nx = 0;
3294      if (relative) {
3295        nx = Math.floor((self.scroll.x - stp) * self.scrollratio.x);
3296      } else {
3297        var sx = (self.timer) ? self.newscrollx : self.getScrollLeft(true);
3298        nx = sx - stp;
3299      }
3300      if (self.bouncescroll) {
3301        var haf = Math.round(self.view.w / 2);
3302        if (nx < -haf) nx = -haf;
3303        else if (nx > (self.page.maxw + haf)) nx = (self.page.maxw + haf);
3304      }
3305      self.cursorfreezed = false;
3306
3307      var px = self.getScrollLeft(true);
3308      if (nx < 0 && px <= 0) return self.noticeCursor();
3309      else if (nx > self.page.maxw && px >= self.page.maxw) return self.noticeCursor();
3310
3311      self.doScrollLeft(nx);
3312    };
3313
3314    this.doScrollTo = function(pos, relative) {
3315      var ny = (relative) ? Math.round(pos * self.scrollratio.y) : pos;
3316      if (ny < 0) ny = 0;
3317      else if (ny > self.page.maxh) ny = self.page.maxh;
vendor: 13,081 bytes, lines 3318-3779
3318      self.cursorfreezed = false;
3319      self.doScrollTop(pos);
3320    };
3321
3322    this.checkContentSize = function() {
3323      var pg = self.getContentSize();
3324      if ((pg.h != self.page.h) || (pg.w != self.page.w)) self.resize(false, pg);
3325    };
3326
3327    self.onscroll = function(e) {
3328      if (self.rail.drag) return;
3329      if (!self.cursorfreezed) {
3330        self.synched('scroll', function() {
3331          self.scroll.y = Math.round(self.getScrollTop() * (1 / self.scrollratio.y));
3332          if (self.railh) self.scroll.x = Math.round(self.getScrollLeft() * (1 / self.scrollratio.x));
3333          self.noticeCursor();
3334        });
3335      }
3336    };
3337    self.bind(self.docscroll, "scroll", self.onscroll);
3338
3339    this.doZoomIn = function(e) {
3340      if (self.zoomactive) return;
3341      self.zoomactive = true;
3342
3343      self.zoomrestore = {
3344        style: {}
3345      };
3346      var lst = ['position', 'top', 'left', 'zIndex', 'backgroundColor', 'marginTop', 'marginBottom', 'marginLeft', 'marginRight'];
3347      var win = self.win[0].style;
3348      for (var a in lst) {
3349        var pp = lst[a];
3350        self.zoomrestore.style[pp] = (win[pp] !== undefined) ? win[pp] : '';
3351      }
3352
3353      self.zoomrestore.style.width = self.win.css('width');
3354      self.zoomrestore.style.height = self.win.css('height');
3355
3356      self.zoomrestore.padding = {
3357        w: self.win.outerWidth() - self.win.width(),
3358        h: self.win.outerHeight() - self.win.height()
3359      };
3360
3361      if (cap.isios4) {
3362        self.zoomrestore.scrollTop = $(window).scrollTop();
3363        $(window).scrollTop(0);
3364      }
3365
3366      self.win.css({
3367        position: (cap.isios4) ? "absolute" : "fixed",
3368        top: 0,
3369        left: 0,
3370        zIndex: globalmaxzindex + 100,
3371        margin: 0
3372      });
3373      var bkg = self.win.css("backgroundColor");
3374      if (bkg == "" || /transparent|rgba\(0, 0, 0, 0\)|rgba\(0,0,0,0\)/.test(bkg)) self.win.css("backgroundColor", "#fff");
3375      self.rail.css({
3376        zIndex: globalmaxzindex + 101
3377      });
3378      self.zoom.css({
3379        zIndex: globalmaxzindex + 102
3380      });
3381      self.zoom.css('backgroundPosition', '0px -18px');
3382      self.resizeZoom();
3383
3384      if (self.onzoomin) self.onzoomin.call(self);
3385
3386      return self.cancelEvent(e);
3387    };
3388
3389    this.doZoomOut = function(e) {
3390      if (!self.zoomactive) return;
3391      self.zoomactive = false;
3392
3393      self.win.css("margin", "");
3394      self.win.css(self.zoomrestore.style);
3395
3396      if (cap.isios4) {
3397        $(window).scrollTop(self.zoomrestore.scrollTop);
3398      }
3399
3400      self.rail.css({
3401        "z-index": self.zindex
3402      });
3403      self.zoom.css({
3404        "z-index": self.zindex
3405      });
3406      self.zoomrestore = false;
3407      self.zoom.css('backgroundPosition', '0px 0px');
3408      self.onResize();
3409
3410      if (self.onzoomout) self.onzoomout.call(self);
3411
3412      return self.cancelEvent(e);
3413    };
3414
3415    this.doZoom = function(e) {
3416      return (self.zoomactive) ? self.doZoomOut(e) : self.doZoomIn(e);
3417    };
3418
3419    this.resizeZoom = function() {
3420      if (!self.zoomactive) return;
3421
3422      var py = self.getScrollTop(); //preserve scrolling position
3423      self.win.css({
3424        width: $(window).width() - self.zoomrestore.padding.w + "px",
3425        height: $(window).height() - self.zoomrestore.padding.h + "px"
3426      });
3427      self.onResize();
3428
3429      self.setScrollTop(Math.min(self.page.maxh, py));
3430    };
3431
3432    this.init();
3433
3434    $.nicescroll.push(this);
3435
3436  };
3437
3438  // Inspired by the work of Kin Blas
3439  // http://webpro.host.adobe.com/people/jblas/momentum/includes/jquery.momentum.0.7.js  
3440
3441
3442  var ScrollMomentumClass2D = function(nc) {
3443    var self = this;
3444    this.nc = nc;
3445
3446    this.lastx = 0;
3447    this.lasty = 0;
3448    this.speedx = 0;
3449    this.speedy = 0;
3450    this.lasttime = 0;
3451    this.steptime = 0;
3452    this.snapx = false;
3453    this.snapy = false;
3454    this.demulx = 0;
3455    this.demuly = 0;
3456
3457    this.lastscrollx = -1;
3458    this.lastscrolly = -1;
3459
3460    this.chkx = 0;
3461    this.chky = 0;
3462
3463    this.timer = 0;
3464
3465    this.time = function() {
3466      return +new Date(); //beautifull hack
3467    };
3468
3469    this.reset = function(px, py) {
3470      self.stop();
3471      var now = self.time();
3472      self.steptime = 0;
3473      self.lasttime = now;
3474      self.speedx = 0;
3475      self.speedy = 0;
3476      self.lastx = px;
3477      self.lasty = py;
3478      self.lastscrollx = -1;
3479      self.lastscrolly = -1;
3480    };
3481
3482    this.update = function(px, py) {
3483      var now = self.time();
3484      self.steptime = now - self.lasttime;
3485      self.lasttime = now;
3486      var dy = py - self.lasty;
3487      var dx = px - self.lastx;
3488      var sy = self.nc.getScrollTop();
3489      var sx = self.nc.getScrollLeft();
3490      var newy = sy + dy;
3491      var newx = sx + dx;
3492      self.snapx = (newx < 0) || (newx > self.nc.page.maxw);
3493      self.snapy = (newy < 0) || (newy > self.nc.page.maxh);
3494      self.speedx = dx;
3495      self.speedy = dy;
3496      self.lastx = px;
3497      self.lasty = py;
3498    };
3499
3500    this.stop = function() {
3501      self.nc.unsynched("domomentum2d");
3502      if (self.timer) clearTimeout(self.timer);
3503      self.timer = 0;
3504      self.lastscrollx = -1;
3505      self.lastscrolly = -1;
3506    };
3507
3508    this.doSnapy = function(nx, ny) {
3509      var snap = false;
3510
3511      if (ny < 0) {
3512        ny = 0;
3513        snap = true;
3514      } else if (ny > self.nc.page.maxh) {
3515        ny = self.nc.page.maxh;
3516        snap = true;
3517      }
3518
3519      if (nx < 0) {
3520        nx = 0;
3521        snap = true;
3522      } else if (nx > self.nc.page.maxw) {
3523        nx = self.nc.page.maxw;
3524        snap = true;
3525      }
3526
3527      (snap) ? self.nc.doScrollPos(nx, ny, self.nc.opt.snapbackspeed): self.nc.triggerScrollEnd();
3528    };
3529
3530    this.doMomentum = function(gp) {
3531      var t = self.time();
3532      var l = (gp) ? t + gp : self.lasttime;
3533
3534      var sl = self.nc.getScrollLeft();
3535      var st = self.nc.getScrollTop();
3536
3537      var pageh = self.nc.page.maxh;
3538      var pagew = self.nc.page.maxw;
3539
3540      self.speedx = (pagew > 0) ? Math.min(60, self.speedx) : 0;
3541      self.speedy = (pageh > 0) ? Math.min(60, self.speedy) : 0;
3542
3543      var chk = l && (t - l) <= 60;
3544
3545      if ((st < 0) || (st > pageh) || (sl < 0) || (sl > pagew)) chk = false;
3546
3547      var sy = (self.speedy && chk) ? self.speedy : false;
3548      var sx = (self.speedx && chk) ? self.speedx : false;
3549
3550      if (sy || sx) {
3551        var tm = Math.max(16, self.steptime); //timeout granularity
3552
3553        if (tm > 50) { // do smooth
3554          var xm = tm / 50;
3555          self.speedx *= xm;
3556          self.speedy *= xm;
3557          tm = 50;
3558        }
3559
3560        self.demulxy = 0;
3561
3562        self.lastscrollx = self.nc.getScrollLeft();
3563        self.chkx = self.lastscrollx;
3564        self.lastscrolly = self.nc.getScrollTop();
3565        self.chky = self.lastscrolly;
3566
3567        var nx = self.lastscrollx;
3568        var ny = self.lastscrolly;
3569
3570        var onscroll = function() {
3571          var df = ((self.time() - t) > 600) ? 0.04 : 0.02;
3572
3573          if (self.speedx) {
3574            nx = Math.floor(self.lastscrollx - (self.speedx * (1 - self.demulxy)));
3575            self.lastscrollx = nx;
3576            if ((nx < 0) || (nx > pagew)) df = 0.10;
3577          }
3578
3579          if (self.speedy) {
3580            ny = Math.floor(self.lastscrolly - (self.speedy * (1 - self.demulxy)));
3581            self.lastscrolly = ny;
3582            if ((ny < 0) || (ny > pageh)) df = 0.10;
3583          }
3584
3585          self.demulxy = Math.min(1, self.demulxy + df);
3586
3587          self.nc.synched("domomentum2d", function() {
3588
3589            if (self.speedx) {
3590              var scx = self.nc.getScrollLeft();
3591//              if (scx != self.chkx) self.stop();
3592              self.chkx = nx;
3593              self.nc.setScrollLeft(nx);
3594            }
3595
3596            if (self.speedy) {
3597              var scy = self.nc.getScrollTop();
3598//              if (scy != self.chky) self.stop();
3599              self.chky = ny;
3600              self.nc.setScrollTop(ny);
3601            }
3602
3603            if (!self.timer) {
3604              self.nc.hideCursor();
3605              self.doSnapy(nx, ny);
3606            }
3607
3608          });
3609
3610          if (self.demulxy < 1) {
3611            self.timer = setTimeout(onscroll, tm);
3612          } else {
3613            self.stop();
3614            self.nc.hideCursor();
3615            self.doSnapy(nx, ny);
3616          }
3617        };
3618
3619        onscroll();
3620
3621      } else {
3622        self.doSnapy(self.nc.getScrollLeft(), self.nc.getScrollTop());
3623      }
3624
3625    };
3626
3627  };
3628
3629
3630  // override jQuery scrollTop
3631
3632  var _scrollTop = jQuery.fn.scrollTop; // preserve original function
3633
3634  jQuery.cssHooks.pageYOffset = {
3635    get: function(elem, computed, extra) {
3636      var nice = $.data(elem, '__nicescroll') || false;
3637      return (nice && nice.ishwscroll) ? nice.getScrollTop() : _scrollTop.call(elem);
3638    },
3639    set: function(elem, value) {
3640      var nice = $.data(elem, '__nicescroll') || false;
3641      (nice && nice.ishwscroll) ? nice.setScrollTop(parseInt(value)): _scrollTop.call(elem, value);
3642      return this;
3643    }
3644  };
3645
3646  /*  
3647  $.fx.step["scrollTop"] = function(fx){    
3648    $.cssHooks["scrollTop"].set( fx.elem, fx.now + fx.unit );
3649  };
3650*/
3651
3652  jQuery.fn.scrollTop = function(value) {
3653    if (value === undefined) {
3654      var nice = (this[0]) ? $.data(this[0], '__nicescroll') || false : false;
3655      return (nice && nice.ishwscroll) ? nice.getScrollTop() : _scrollTop.call(this);
3656    } else {
3657      return this.each(function() {
3658        var nice = $.data(this, '__nicescroll') || false;
3659        (nice && nice.ishwscroll) ? nice.setScrollTop(parseInt(value)): _scrollTop.call($(this), value);
3660      });
3661    }
3662  };
3663
3664  // override jQuery scrollLeft
3665
3666  var _scrollLeft = jQuery.fn.scrollLeft; // preserve original function
3667
3668  $.cssHooks.pageXOffset = {
3669    get: function(elem, computed, extra) {
3670      var nice = $.data(elem, '__nicescroll') || false;
3671      return (nice && nice.ishwscroll) ? nice.getScrollLeft() : _scrollLeft.call(elem);
3672    },
3673    set: function(elem, value) {
3674      var nice = $.data(elem, '__nicescroll') || false;
3675      (nice && nice.ishwscroll) ? nice.setScrollLeft(parseInt(value)): _scrollLeft.call(elem, value);
3676      return this;
3677    }
3678  };
3679
3680  /*  
3681  $.fx.step["scrollLeft"] = function(fx){
3682    $.cssHooks["scrollLeft"].set( fx.elem, fx.now + fx.unit );
3683  };  
3684*/
3685
3686  jQuery.fn.scrollLeft = function(value) {
3687    if (value === undefined) {
3688      var nice = (this[0]) ? $.data(this[0], '__nicescroll') || false : false;
3689      return (nice && nice.ishwscroll) ? nice.getScrollLeft() : _scrollLeft.call(this);
3690    } else {
3691      return this.each(function() {
3692        var nice = $.data(this, '__nicescroll') || false;
3693        (nice && nice.ishwscroll) ? nice.setScrollLeft(parseInt(value)): _scrollLeft.call($(this), value);
3694      });
3695    }
3696  };
3697
3698  var NiceScrollArray = function(doms) {
3699    var self = this;
3700    this.length = 0;
3701    this.name = "nicescrollarray";
3702
3703    this.each = function(fn) {
3704      $.each(self, fn);
3705      return self;
3706    };
3707
3708    this.push = function(nice) {
3709      self[self.length] = nice;
3710      self.length++;
3711    };
3712
3713    this.eq = function(idx) {
3714      return self[idx];
3715    };
3716
3717    if (doms) {
3718      for (var a = 0; a < doms.length; a++) {
3719        var nice = $.data(doms[a], '__nicescroll') || false;
3720        if (nice) {
3721          this[this.length] = nice;
3722          this.length++;
3723        }
3724      }
3725    }
3726
3727    return this;
3728  };
3729
3730  function mplex(el, lst, fn) {
3731    for (var a = 0; a < lst.length; a++) fn(el, lst[a]);
3732  }
3733  mplex(
3734    NiceScrollArray.prototype, ['show', 'hide', 'toggle', 'onResize', 'resize', 'remove', 'stop', 'doScrollPos'],
3735    function(e, n) {
3736      e[n] = function() {
3737        var args = arguments;
3738        return this.each(function() {
3739          this[n].apply(this, args);
3740        });
3741      };
3742    }
3743  );
3744
3745  jQuery.fn.getNiceScroll = function(index) {
3746    if (index === undefined) {
3747      return new NiceScrollArray(this);
3748    } else {
3749      return this[index] && $.data(this[index], '__nicescroll') || false;
3750    }
3751  };
3752
3753  jQuery.expr[':'].nicescroll = function(a) {
3754    return $.data(a, '__nicescroll') !== undefined;
3755  };
3756
3757  $.fn.niceScroll = function(wrapper, opt) {
3758    if (opt === undefined && typeof wrapper == "object" && !("jquery" in wrapper)) {
3759      opt = wrapper;
3760      wrapper = false;
3761    }
3762    opt = $.extend({},opt); // cloning
3763    var ret = new NiceScrollArray();
3764    if (opt === undefined) opt = {};
3765
3766    if (wrapper || false) {
3767      opt.doc = $(wrapper);
3768      opt.win = $(this);
3769    }
3770    var docundef = !("doc" in opt);
3771    if (!docundef && !("win" in opt)) opt.win = $(this);
3772
3773    this.each(function() {
3774      var nice = $(this).data('__nicescroll') || false;
3775      if (!nice) {
3776        opt.doc = (docundef) ? $(this) : opt.doc;
3777        nice = new NiceScrollClass(opt, $(this));
3778        $(this).data('__nicescroll', nice);
3779      }
3780      ret.push(nice);
3781    });
3782    return (ret.length == 1) ? ret[0] : ret;
3783  };
3784
3785  window.NiceScroll = {
3786    getjQuery: function() {
3787      return jQuery;
3788    }
3789  };
3790
3791  if (!$.nicescroll) {
3792    $.nicescroll = new NiceScrollArray();
3793    $.nicescroll.options = _globaloptions;
3794  }
3795
3796}));
3797

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.