PageSourceSearch

https://sib-tatu.com/common/scroll/jquery.mCustomScrollbar.js

js sib-tatu.com collected 2026-10-04 09:51:58 UTC 92,672 bytes, 2,478 lines download raw bytes

vendor: 14,887 bytes, lines 1-469
1/*
2== malihu jquery custom scrollbar plugin ==
3Version: 3.1.5
4Plugin URI: http://manos.malihu.gr/jquery-custom-content-scroller
5Author: malihu
6Author URI: http://manos.malihu.gr
7License: MIT License (MIT)
8*/
9
10/*
11Copyright Manos Malihutsakis (email: [email protected])
12
13Permission is hereby granted, free of charge, to any person obtaining a copy
14of this software and associated documentation files (the "Software"), to deal
15in the Software without restriction, including without limitation the rights
16to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17copies of the Software, and to permit persons to whom the Software is
18furnished to do so, subject to the following conditions:
19
20The above copyright notice and this permission notice shall be included in
21all copies or substantial portions of the Software.
22
23THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29THE SOFTWARE.
30*/
31
32/*
33The code below is fairly long, fully commented and should be normally used in development.
34For production, use either the minified jquery.mCustomScrollbar.min.js script or
35the production-ready jquery.mCustomScrollbar.concat.min.js which contains the plugin
36and dependencies (minified).
37*/
38
39(function(factory){
40	if(typeof define==="function" && define.amd){
41		define(["jquery"],factory);
42	}else if(typeof module!=="undefined" && module.exports){
43		module.exports=factory;
44	}else{
45		factory(jQuery,window,document);
46	}
47}(function($){
48(function(init){
49	var _rjs=typeof define==="function" && define.amd, /* RequireJS */
50		_njs=typeof module !== "undefined" && module.exports, /* NodeJS */
51		_dlp=("https:"==document.location.protocol) ? "https:" : "http:", /* location protocol */
52		_url="cdnjs.cloudflare.com/ajax/libs/jquery-mousewheel/3.1.13/jquery.mousewheel.min.js";
53	if(!_rjs){
54		if(_njs){
55			require("jquery-mousewheel")($);
56		}else{
57			/* load jquery-mousewheel plugin (via CDN) if it's not present or not loaded via RequireJS
58			(works when mCustomScrollbar fn is called on window load) */
59			$.event.special.mousewheel || $("head").append(decodeURI("%3Cscript src="+_dlp+"//"+_url+"%3E%3C/script%3E"));
60		}
61	}
62	init();
63}(function(){
64
65	/*
66	----------------------------------------
67	PLUGIN NAMESPACE, PREFIX, DEFAULT SELECTOR(S)
68	----------------------------------------
69	*/
70
71	var pluginNS="mCustomScrollbar",
72		pluginPfx="mCS",
73		defaultSelector=".mCustomScrollbar",
74
75
76
77
78
79	/*
80	----------------------------------------
81	DEFAULT OPTIONS
82	----------------------------------------
83	*/
84
85		defaults={
86			/*
87			set element/content width/height programmatically
88			values: boolean, pixels, percentage
89				option						default
90				-------------------------------------
91				setWidth					false
92				setHeight					false
93			*/
94			/*
95			set the initial css top property of content
96			values: string (e.g. "-100px", "10%" etc.)
97			*/
98			setTop:0,
99			/*
100			set the initial css left property of content
101			values: string (e.g. "-100px", "10%" etc.)
102			*/
103			setLeft:0,
104			/*
105			scrollbar axis (vertical and/or horizontal scrollbars)
106			values (string): "y", "x", "yx"
107			*/
108			axis:"y",
109			/*
110			position of scrollbar relative to content
111			values (string): "inside", "outside" ("outside" requires elements with position:relative)
112			*/
113			scrollbarPosition:"inside",
114			/*
115			scrolling inertia
116			values: integer (milliseconds)
117			*/
118			scrollInertia:950,
119			/*
120			auto-adjust scrollbar dragger length
121			values: boolean
122			*/
123			autoDraggerLength:true,
124			/*
125			auto-hide scrollbar when idle
126			values: boolean
127				option						default
128				-------------------------------------
129				autoHideScrollbar			false
130			*/
131			/*
132			auto-expands scrollbar on mouse-over and dragging
133			values: boolean
134				option						default
135				-------------------------------------
136				autoExpandScrollbar			false
137			*/
138			/*
139			always show scrollbar, even when there's nothing to scroll
140			values: integer (0=disable, 1=always show dragger rail and buttons, 2=always show dragger rail, dragger and buttons), boolean
141			*/
142			alwaysShowScrollbar:0,
143			/*
144			scrolling always snaps to a multiple of this number in pixels
145			values: integer, array ([y,x])
146				option						default
147				-------------------------------------
148				snapAmount					null
149			*/
150			/*
151			when snapping, snap with this number in pixels as an offset
152			values: integer
153			*/
154			snapOffset:0,
155			/*
156			mouse-wheel scrolling
157			*/
158			mouseWheel:{
159				/*
160				enable mouse-wheel scrolling
161				values: boolean
162				*/
163				enable:true,
164				/*
165				scrolling amount in pixels
166				values: "auto", integer
167				*/
168				scrollAmount:"auto",
169				/*
170				mouse-wheel scrolling axis
171				the default scrolling direction when both vertical and horizontal scrollbars are present
172				values (string): "y", "x"
173				*/
174				axis:"y",
175				/*
176				prevent the default behaviour which automatically scrolls the parent element(s) when end of scrolling is reached
177				values: boolean
178					option						default
179					-------------------------------------
180					preventDefault				null
181				*/
182				/*
183				the reported mouse-wheel delta value. The number of lines (translated to pixels) one wheel notch scrolls.
184				values: "auto", integer
185				"auto" uses the default OS/browser value
186				*/
187				deltaFactor:"auto",
188				/*
189				normalize mouse-wheel delta to -1 or 1 (disables mouse-wheel acceleration)
190				values: boolean
191					option						default
192					-------------------------------------
193					normalizeDelta				null
194				*/
195				/*
196				invert mouse-wheel scrolling direction
197				values: boolean
198					option						default
199					-------------------------------------
200					invert						null
201				*/
202				/*
203				the tags that disable mouse-wheel when cursor is over them
204				*/
205				disableOver:["select","option","keygen","datalist","textarea"]
206			},
207			/*
208			scrollbar buttons
209			*/
210			scrollButtons:{
211				/*
212				enable scrollbar buttons
213				values: boolean
214					option						default
215					-------------------------------------
216					enable						null
217				*/
218				/*
219				scrollbar buttons scrolling type
220				values (string): "stepless", "stepped"
221				*/
222				scrollType:"stepless",
223				/*
224				scrolling amount in pixels
225				values: "auto", integer
226				*/
227				scrollAmount:"auto"
228				/*
229				tabindex of the scrollbar buttons
230				values: false, integer
231					option						default
232					-------------------------------------
233					tabindex					null
234				*/
235			},
236			/*
237			keyboard scrolling
238			*/
239			keyboard:{
240				/*
241				enable scrolling via keyboard
242				values: boolean
243				*/
244				enable:true,
245				/*
246				keyboard scrolling type
247				values (string): "stepless", "stepped"
248				*/
249				scrollType:"stepless",
250				/*
251				scrolling amount in pixels
252				values: "auto", integer
253				*/
254				scrollAmount:"auto"
255			},
256			/*
257			enable content touch-swipe scrolling
258			values: boolean, integer, string (number)
259			integer values define the axis-specific minimum amount required for scrolling momentum
260			*/
261			contentTouchScroll:25,
262			/*
263			enable/disable document (default) touch-swipe scrolling
264			*/
265			documentTouchScroll:true,
266			/*
267			advanced option parameters
268			*/
269			advanced:{
270				/*
271				auto-expand content horizontally (for "x" or "yx" axis)
272				values: boolean, integer (the value 2 forces the non scrollHeight/scrollWidth method, the value 3 forces the scrollHeight/scrollWidth method)
273					option						default
274					-------------------------------------
275					autoExpandHorizontalScroll	null
276				*/
277				/*
278				auto-scroll to elements with focus
279				*/
280				autoScrollOnFocus:"input,textarea,select,button,datalist,keygen,a[tabindex],area,object,[contenteditable='true']",
281				/*
282				auto-update scrollbars on content, element or viewport resize
283				should be true for fluid layouts/elements, adding/removing content dynamically, hiding/showing elements, content with images etc.
284				values: boolean
285				*/
286				updateOnContentResize:true,
287				/*
288				auto-update scrollbars each time each image inside the element is fully loaded
289				values: "auto", boolean
290				*/
291				updateOnImageLoad:"auto",
292				/*
293				auto-update scrollbars based on the amount and size changes of specific selectors
294				useful when you need to update the scrollbar(s) automatically, each time a type of element is added, removed or changes its size
295				values: boolean, string (e.g. "ul li" will auto-update scrollbars each time list-items inside the element are changed)
296				a value of true (boolean) will auto-update scrollbars each time any element is changed
297					option						default
298					-------------------------------------
299					updateOnSelectorChange		null
300				*/
301				/*
302				extra selectors that'll allow scrollbar dragging upon mousemove/up, pointermove/up, touchend etc. (e.g. "selector-1, selector-2")
303					option						default
304					-------------------------------------
305					extraDraggableSelectors		null
306				*/
307				/*
308				extra selectors that'll release scrollbar dragging upon mouseup, pointerup, touchend etc. (e.g. "selector-1, selector-2")
309					option						default
310					-------------------------------------
311					releaseDraggableSelectors	null
312				*/
313				/*
314				auto-update timeout
315				values: integer (milliseconds)
316				*/
317				autoUpdateTimeout:60
318			},
319			/*
320			scrollbar theme
321			values: string (see CSS/plugin URI for a list of ready-to-use themes)
322			*/
323			theme:"light",
324			/*
325			user defined callback functions
326			*/
327			callbacks:{
328				/*
329				Available callbacks:
330					callback					default
331					-------------------------------------
332					onCreate					null
333					onInit						null
334					onScrollStart				null
335					onScroll					null
336					onTotalScroll				null
337					onTotalScrollBack			null
338					whileScrolling				null
339					onOverflowY					null
340					onOverflowX					null
341					onOverflowYNone				null
342					onOverflowXNone				null
343					onImageLoad					null
344					onSelectorChange			null
345					onBeforeUpdate				null
346					onUpdate					null
347				*/
348				onTotalScrollOffset:0,
349				onTotalScrollBackOffset:0,
350				alwaysTriggerOffsets:true
351			}
352			/*
353			add scrollbar(s) on all elements matching the current selector, now and in the future
354			values: boolean, string
355			string values: "on" (enable), "once" (disable after first invocation), "off" (disable)
356			liveSelector values: string (selector)
357				option						default
358				-------------------------------------
359				live						false
360				liveSelector				null
361			*/
362		},
363
364
365
366
367
368	/*
369	----------------------------------------
370	VARS, CONSTANTS
371	----------------------------------------
372	*/
373
374		totalInstances=0, /* plugin instances amount */
375		liveTimers={}, /* live option timers */
376		oldIE=(window.attachEvent && !window.addEventListener) ? 1 : 0, /* detect IE < 9 */
377		touchActive=false,touchable, /* global touch vars (for touch and pointer events) */
378		/* general plugin classes */
379		classes=[
380			"mCSB_dragger_onDrag","mCSB_scrollTools_onDrag","mCS_img_loaded","mCS_disabled","mCS_destroyed","mCS_no_scrollbar",
381			"mCS-autoHide","mCS-dir-rtl","mCS_no_scrollbar_y","mCS_no_scrollbar_x","mCS_y_hidden","mCS_x_hidden","mCSB_draggerContainer",
382			"mCSB_buttonUp","mCSB_buttonDown","mCSB_buttonLeft","mCSB_buttonRight"
383		],
384
385
386
387
388
389	/*
390	----------------------------------------
391	METHODS
392	----------------------------------------
393	*/
394
395		methods={
396
397			/*
398			plugin initialization method
399			creates the scrollbar(s), plugin data object and options
400			----------------------------------------
401			*/
402
403			init:function(options){
404
405				var options=$.extend(true,{},defaults,options),
406					selector=_selector.call(this); /* validate selector */
407
408				/*
409				if live option is enabled, monitor for elements matching the current selector and
410				apply scrollbar(s) when found (now and in the future)
411				*/
412				if(options.live){
413					var liveSelector=options.liveSelector || this.selector || defaultSelector, /* live selector(s) */
414						$liveSelector=$(liveSelector); /* live selector(s) as jquery object */
415					if(options.live==="off"){
416						/*
417						disable live if requested
418						usage: $(selector).mCustomScrollbar({live:"off"});
419						*/
420						removeLiveTimers(liveSelector);
421						return;
422					}
423					liveTimers[liveSelector]=setTimeout(function(){
424						/* call mCustomScrollbar fn on live selector(s) every half-second */
425						$liveSelector.mCustomScrollbar(options);
426						if(options.live==="once" && $liveSelector.length){
427							/* disable live after first invocation */
428							removeLiveTimers(liveSelector);
429						}
430					},500);
431				}else{
432					removeLiveTimers(liveSelector);
433				}
434
435				/* options backward compatibility (for versions < 3.0.0) and normalization */
436				options.setWidth=(options.set_width) ? options.set_width : options.setWidth;
437				options.setHeight=(options.set_height) ? options.set_height : options.setHeight;
438				options.axis=(options.horizontalScroll) ? "x" : _findAxis(options.axis);
439				options.scrollInertia=options.scrollInertia>0 && options.scrollInertia<17 ? 17 : options.scrollInertia;
440				if(typeof options.mouseWheel!=="object" &&  options.mouseWheel==true){ /* old school mouseWheel option (non-object) */
441					options.mouseWheel={enable:true,scrollAmount:"auto",axis:"y",preventDefault:false,deltaFactor:"auto",normalizeDelta:false,invert:false}
442				}
443				options.mouseWheel.scrollAmount=!options.mouseWheelPixels ? options.mouseWheel.scrollAmount : options.mouseWheelPixels;
444				options.mouseWheel.normalizeDelta=!options.advanced.normalizeMouseWheelDelta ? options.mouseWheel.normalizeDelta : options.advanced.normalizeMouseWheelDelta;
445				options.scrollButtons.scrollType=_findScrollButtonsType(options.scrollButtons.scrollType);
446
447				_theme(options); /* theme-specific options */
448
449				/* plugin constructor */
450				return $(selector).each(function(){
451
452					var $this=$(this);
453
454					if(!$this.data(pluginPfx)){ /* prevent multiple instantiations */
455
456						/* store options and create objects in jquery data */
457						$this.data(pluginPfx,{
458							idx:++totalInstances, /* instance index */
459							opt:options, /* options */
460							scrollRatio:{y:null,x:null}, /* scrollbar to content ratio */
461							overflowed:null, /* overflowed axis */
462							contentReset:{y:null,x:null}, /* object to check when content resets */
463							bindEvents:false, /* object to check if events are bound */
464							tweenRunning:false, /* object to check if tween is running */
465							sequential:{}, /* sequential scrolling object */
466							langDir:$this.css("direction"), /* detect/store direction (ltr or rtl) */
467							cbOffsets:null, /* object to check whether callback offsets always trigger */
468							/*
469							object to check how scrolling events where last triggered
470							"internal" (default - triggered by this script), "external" (triggered by other scripts, e.g. via scrollTo method)
471							usage: object.data("mCS").trigger
472							*/
473							trigger:null,
474							/*
475							object to check for changes in elements in order to call the update method automatically
476							*/
477							poll:{size:{o:0,n:0},img:{o:0,n:0},change:{o:0,n:0}}
478						});
479
480						var d=$this.data(pluginPfx),o=d.opt,
481							/* HTML data attributes */
482							htmlDataAxis=$this.data("mcs-axis"),htmlDataSbPos=$this.data("mcs-scrollbar-position"),htmlDataTheme=$this.data("mcs-theme");
483
484						if(htmlDataAxis){o.axis=htmlDataAxis;} /* usage example: data-mcs-axis="y" */
485						if(htmlDataSbPos){o.scrollbarPosition=htmlDataSbPos;} /* usage example: data-mcs-scrollbar-position="outside" */
486						if(htmlDataTheme){ /* usage example: data-mcs-theme="minimal" */
487							o.theme=htmlDataTheme;
488							_theme(o); /* theme-specific options */
489						}
490
491						_pluginMarkup.call(this); /* add plugin markup */
492
493						if(d && o.callbacks.onCreate && typeof o.callbacks.onCreate==="function"){o.callbacks.onCreate.call(this);} /* callbacks: onCreate */
494
495						$("#mCSB_"+d.idx+"_container img:not(."+classes[2]+")").addClass(classe
vendor: 76,558 bytes, lines 495-2478
495s[2]); /* flag loaded images */
496
497						methods.update.call(null,$this); /* call the update method */
498
499					}
500
501				});
502
503			},
504			/* ---------------------------------------- */
505
506
507
508			/*
509			plugin update method
510			updates content and scrollbar(s) values, events and status
511			----------------------------------------
512			usage: $(selector).mCustomScrollbar("update");
513			*/
514
515			update:function(el,cb){
516
517				var selector=el || _selector.call(this); /* validate selector */
518
519				return $(selector).each(function(){
520
521					var $this=$(this);
522
523					if($this.data(pluginPfx)){ /* check if plugin has initialized */
524
525						var d=$this.data(pluginPfx),o=d.opt,
526							mCSB_container=$("#mCSB_"+d.idx+"_container"),
527							mCustomScrollBox=$("#mCSB_"+d.idx),
528							mCSB_dragger=[$("#mCSB_"+d.idx+"_dragger_vertical"),$("#mCSB_"+d.idx+"_dragger_horizontal")];
529
530						if(!mCSB_container.length){return;}
531
532						if(d.tweenRunning){_stop($this);} /* stop any running tweens while updating */
533
534						if(cb && d && o.callbacks.onBeforeUpdate && typeof o.callbacks.onBeforeUpdate==="function"){o.callbacks.onBeforeUpdate.call(this);} /* callbacks: onBeforeUpdate */
535
536						/* if element was disabled or destroyed, remove class(es) */
537						if($this.hasClass(classes[3])){$this.removeClass(classes[3]);}
538						if($this.hasClass(classes[4])){$this.removeClass(classes[4]);}
539
540						/* css flexbox fix, detect/set max-height */
541						mCustomScrollBox.css("max-height","none");
542						if(mCustomScrollBox.height()!==$this.height()){mCustomScrollBox.css("max-height",$this.height());}
543
544						_expandContentHorizontally.call(this); /* expand content horizontally */
545
546						if(o.axis!=="y" && !o.advanced.autoExpandHorizontalScroll){
547							mCSB_container.css("width",_contentWidth(mCSB_container));
548						}
549
550						d.overflowed=_overflowed.call(this); /* determine if scrolling is required */
551
552						_scrollbarVisibility.call(this); /* show/hide scrollbar(s) */
553
554						/* auto-adjust scrollbar dragger length analogous to content */
555						if(o.autoDraggerLength){_setDraggerLength.call(this);}
556
557						_scrollRatio.call(this); /* calculate and store scrollbar to content ratio */
558
559						_bindEvents.call(this); /* bind scrollbar events */
560
561						/* reset scrolling position and/or events */
562						var to=[Math.abs(mCSB_container[0].offsetTop),Math.abs(mCSB_container[0].offsetLeft)];
563						if(o.axis!=="x"){ /* y/yx axis */
564							if(!d.overflowed[0]){ /* y scrolling is not required */
565								_resetContentPosition.call(this); /* reset content position */
566								if(o.axis==="y"){
567									_unbindEvents.call(this);
568								}else if(o.axis==="yx" && d.overflowed[1]){
569									_scrollTo($this,to[1].toString(),{dir:"x",dur:0,overwrite:"none"});
570								}
571							}else if(mCSB_dragger[0].height()>mCSB_dragger[0].parent().height()){
572								_resetContentPosition.call(this); /* reset content position */
573							}else{ /* y scrolling is required */
574								_scrollTo($this,to[0].toString(),{dir:"y",dur:0,overwrite:"none"});
575								d.contentReset.y=null;
576							}
577						}
578						if(o.axis!=="y"){ /* x/yx axis */
579							if(!d.overflowed[1]){ /* x scrolling is not required */
580								_resetContentPosition.call(this); /* reset content position */
581								if(o.axis==="x"){
582									_unbindEvents.call(this);
583								}else if(o.axis==="yx" && d.overflowed[0]){
584									_scrollTo($this,to[0].toString(),{dir:"y",dur:0,overwrite:"none"});
585								}
586							}else if(mCSB_dragger[1].width()>mCSB_dragger[1].parent().width()){
587								_resetContentPosition.call(this); /* reset content position */
588							}else{ /* x scrolling is required */
589								_scrollTo($this,to[1].toString(),{dir:"x",dur:0,overwrite:"none"});
590								d.contentReset.x=null;
591							}
592						}
593
594						/* callbacks: onImageLoad, onSelectorChange, onUpdate */
595						if(cb && d){
596							if(cb===2 && o.callbacks.onImageLoad && typeof o.callbacks.onImageLoad==="function"){
597								o.callbacks.onImageLoad.call(this);
598							}else if(cb===3 && o.callbacks.onSelectorChange && typeof o.callbacks.onSelectorChange==="function"){
599								o.callbacks.onSelectorChange.call(this);
600							}else if(o.callbacks.onUpdate && typeof o.callbacks.onUpdate==="function"){
601								o.callbacks.onUpdate.call(this);
602							}
603						}
604
605						_autoUpdate.call(this); /* initialize automatic updating (for dynamic content, fluid layouts etc.) */
606
607					}
608
609				});
610
611			},
612			/* ---------------------------------------- */
613
614
615
616			/*
617			plugin scrollTo method
618			triggers a scrolling event to a specific value
619			----------------------------------------
620			usage: $(selector).mCustomScrollbar("scrollTo",value,options);
621			*/
622
623			scrollTo:function(val,options){
624
625				/* prevent silly things like $(selector).mCustomScrollbar("scrollTo",undefined); */
626				if(typeof val=="undefined" || val==null){return;}
627
628				var selector=_selector.call(this); /* validate selector */
629
630				return $(selector).each(function(){
631
632					var $this=$(this);
633
634					if($this.data(pluginPfx)){ /* check if plugin has initialized */
635
636						var d=$this.data(pluginPfx),o=d.opt,
637							/* method default options */
638							methodDefaults={
639								trigger:"external", /* method is by default triggered externally (e.g. from other scripts) */
640								scrollInertia:o.scrollInertia, /* scrolling inertia (animation duration) */
641								scrollEasing:"mcsEaseInOut", /* animation easing */
642								moveDragger:false, /* move dragger instead of content */
643								timeout:60, /* scroll-to delay */
644								callbacks:true, /* enable/disable callbacks */
645								onStart:true,
646								onUpdate:true,
647								onComplete:true
648							},
649							methodOptions=$.extend(true,{},methodDefaults,options),
650							to=_arr.call(this,val),dur=methodOptions.scrollInertia>0 && methodOptions.scrollInertia<17 ? 17 : methodOptions.scrollInertia;
651
652						/* translate yx values to actual scroll-to positions */
653						to[0]=_to.call(this,to[0],"y");
654						to[1]=_to.call(this,to[1],"x");
655
656						/*
657						check if scroll-to value moves the dragger instead of content.
658						Only pixel values apply on dragger (e.g. 100, "100px", "-=100" etc.)
659						*/
660						if(methodOptions.moveDragger){
661							to[0]*=d.scrollRatio.y;
662							to[1]*=d.scrollRatio.x;
663						}
664
665						methodOptions.dur=_isTabHidden() ? 0 : dur; //skip animations if browser tab is hidden
666
667						setTimeout(function(){
668							/* do the scrolling */
669							if(to[0]!==null && typeof to[0]!=="undefined" && o.axis!=="x" && d.overflowed[0]){ /* scroll y */
670								methodOptions.dir="y";
671								methodOptions.overwrite="all";
672								_scrollTo($this,to[0].toString(),methodOptions);
673							}
674							if(to[1]!==null && typeof to[1]!=="undefined" && o.axis!=="y" && d.overflowed[1]){ /* scroll x */
675								methodOptions.dir="x";
676								methodOptions.overwrite="none";
677								_scrollTo($this,to[1].toString(),methodOptions);
678							}
679						},methodOptions.timeout);
680
681					}
682
683				});
684
685			},
686			/* ---------------------------------------- */
687
688
689
690			/*
691			plugin stop method
692			stops scrolling animation
693			----------------------------------------
694			usage: $(selector).mCustomScrollbar("stop");
695			*/
696			stop:function(){
697
698				var selector=_selector.call(this); /* validate selector */
699
700				return $(selector).each(function(){
701
702					var $this=$(this);
703
704					if($this.data(pluginPfx)){ /* check if plugin has initialized */
705
706						_stop($this);
707
708					}
709
710				});
711
712			},
713			/* ---------------------------------------- */
714
715
716
717			/*
718			plugin disable method
719			temporarily disables the scrollbar(s)
720			----------------------------------------
721			usage: $(selector).mCustomScrollbar("disable",reset);
722			reset (boolean): resets content position to 0
723			*/
724			disable:function(r){
725
726				var selector=_selector.call(this); /* validate selector */
727
728				return $(selector).each(function(){
729
730					var $this=$(this);
731
732					if($this.data(pluginPfx)){ /* check if plugin has initialized */
733
734						var d=$this.data(pluginPfx);
735
736						_autoUpdate.call(this,"remove"); /* remove automatic updating */
737
738						_unbindEvents.call(this); /* unbind events */
739
740						if(r){_resetContentPosition.call(this);} /* reset content position */
741
742						_scrollbarVisibility.call(this,true); /* show/hide scrollbar(s) */
743
744						$this.addClass(classes[3]); /* add disable class */
745
746					}
747
748				});
749
750			},
751			/* ---------------------------------------- */
752
753
754
755			/*
756			plugin destroy method
757			completely removes the scrollbar(s) and returns the element to its original state
758			----------------------------------------
759			usage: $(selector).mCustomScrollbar("destroy");
760			*/
761			destroy:function(){
762
763				var selector=_selector.call(this); /* validate selector */
764
765				return $(selector).each(function(){
766
767					var $this=$(this);
768
769					if($this.data(pluginPfx)){ /* check if plugin has initialized */
770
771						var d=$this.data(pluginPfx),o=d.opt,
772							mCustomScrollBox=$("#mCSB_"+d.idx),
773							mCSB_container=$("#mCSB_"+d.idx+"_container"),
774							scrollbar=$(".mCSB_"+d.idx+"_scrollbar");
775
776						if(o.live){removeLiveTimers(o.liveSelector || $(selector).selector);} /* remove live timers */
777
778						_autoUpdate.call(this,"remove"); /* remove automatic updating */
779
780						_unbindEvents.call(this); /* unbind events */
781
782						_resetContentPosition.call(this); /* reset content position */
783
784						$this.removeData(pluginPfx); /* remove plugin data object */
785
786						_delete(this,"mcs"); /* delete callbacks object */
787
788						/* remove plugin markup */
789						scrollbar.remove(); /* remove scrollbar(s) first (those can be either inside or outside plugin's inner wrapper) */
790						mCSB_container.find("img."+classes[2]).removeClass(classes[2]); /* remove loaded images flag */
791						mCustomScrollBox.replaceWith(mCSB_container.contents()); /* replace plugin's inner wrapper with the original content */
792						/* remove plugin classes from the element and add destroy class */
793						$this.removeClass(pluginNS+" _"+pluginPfx+"_"+d.idx+" "+classes[6]+" "+classes[7]+" "+classes[5]+" "+classes[3]).addClass(classes[4]);
794
795					}
796
797				});
798
799			}
800			/* ---------------------------------------- */
801
802		},
803
804
805
806
807
808	/*
809	----------------------------------------
810	FUNCTIONS
811	----------------------------------------
812	*/
813
814		/* validates selector (if selector is invalid or undefined uses the default one) */
815		_selector=function(){
816			return (typeof $(this)!=="object" || $(this).length<1) ? defaultSelector : this;
817		},
818		/* -------------------- */
819
820
821		/* changes options according to theme */
822		_theme=function(obj){
823			var fixedSizeScrollbarThemes=["rounded","rounded-dark","rounded-dots","rounded-dots-dark"],
824				nonExpandedScrollbarThemes=["rounded-dots","rounded-dots-dark","3d","3d-dark","3d-thick","3d-thick-dark","inset","inset-dark","inset-2","inset-2-dark","inset-3","inset-3-dark"],
825				disabledScrollButtonsThemes=["minimal","minimal-dark"],
826				enabledAutoHideScrollbarThemes=["minimal","minimal-dark"],
827				scrollbarPositionOutsideThemes=["minimal","minimal-dark"];
828			obj.autoDraggerLength=$.inArray(obj.theme,fixedSizeScrollbarThemes) > -1 ? false : obj.autoDraggerLength;
829			obj.autoExpandScrollbar=$.inArray(obj.theme,nonExpandedScrollbarThemes) > -1 ? false : obj.autoExpandScrollbar;
830			obj.scrollButtons.enable=$.inArray(obj.theme,disabledScrollButtonsThemes) > -1 ? false : obj.scrollButtons.enable;
831			obj.autoHideScrollbar=$.inArray(obj.theme,enabledAutoHideScrollbarThemes) > -1 ? true : obj.autoHideScrollbar;
832			obj.scrollbarPosition=$.inArray(obj.theme,scrollbarPositionOutsideThemes) > -1 ? "outside" : obj.scrollbarPosition;
833		},
834		/* -------------------- */
835
836
837		/* live option timers removal */
838		removeLiveTimers=function(selector){
839			if(liveTimers[selector]){
840				clearTimeout(liveTimers[selector]);
841				_delete(liveTimers,selector);
842			}
843		},
844		/* -------------------- */
845
846
847		/* normalizes axis option to valid values: "y", "x", "yx" */
848		_findAxis=function(val){
849			return (val==="yx" || val==="xy" || val==="auto") ? "yx" : (val==="x" || val==="horizontal") ? "x" : "y";
850		},
851		/* -------------------- */
852
853
854		/* normalizes scrollButtons.scrollType option to valid values: "stepless", "stepped" */
855		_findScrollButtonsType=function(val){
856			return (val==="stepped" || val==="pixels" || val==="step" || val==="click") ? "stepped" : "stepless";
857		},
858		/* -------------------- */
859
860
861		/* generates plugin markup */
862		_pluginMarkup=function(){
863			var $this=$(this),d=$this.data(pluginPfx),o=d.opt,
864				expandClass=o.autoExpandScrollbar ? " "+classes[1]+"_expand" : "",
865				scrollbar=["<div id='mCSB_"+d.idx+"_scrollbar_vertical' class='mCSB_scrollTools mCSB_"+d.idx+"_scrollbar mCS-"+o.theme+" mCSB_scrollTools_vertical"+expandClass+"'><div class='"+classes[12]+"'><div id='mCSB_"+d.idx+"_dragger_vertical' class='mCSB_dragger' style='position:absolute;'><div class='mCSB_dragger_bar' /></div><div class='mCSB_draggerRail' /></div></div>","<div id='mCSB_"+d.idx+"_scrollbar_horizontal' class='mCSB_scrollTools mCSB_"+d.idx+"_scrollbar mCS-"+o.theme+" mCSB_scrollTools_horizontal"+expandClass+"'><div class='"+classes[12]+"'><div id='mCSB_"+d.idx+"_dragger_horizontal' class='mCSB_dragger' style='position:absolute;'><div class='mCSB_dragger_bar' /></div><div class='mCSB_draggerRail' /></div></div>"],
866				wrapperClass=o.axis==="yx" ? "mCSB_vertical_horizontal" : o.axis==="x" ? "mCSB_horizontal" : "mCSB_vertical",
867				scrollbars=o.axis==="yx" ? scrollbar[0]+scrollbar[1] : o.axis==="x" ? scrollbar[1] : scrollbar[0],
868				contentWrapper=o.axis==="yx" ? "<div id='mCSB_"+d.idx+"_container_wrapper' class='mCSB_container_wrapper' />" : "",
869				autoHideClass=o.autoHideScrollbar ? " "+classes[6] : "",
870				scrollbarDirClass=(o.axis!=="x" && d.langDir==="rtl") ? " "+classes[7] : "";
871			if(o.setWidth){$this.css("width",o.setWidth);} /* set element width */
872			if(o.setHeight){$this.css("height",o.setHeight);} /* set element height */
873			o.setLeft=(o.axis!=="y" && d.langDir==="rtl") ? "989999px" : o.setLeft; /* adjust left position for rtl direction */
874			$this.addClass(pluginNS+" _"+pluginPfx+"_"+d.idx+autoHideClass+scrollbarDirClass).wrapInner("<div id='mCSB_"+d.idx+"' class='mCustomScrollBox mCS-"+o.theme+" "+wrapperClass+"'><div id='mCSB_"+d.idx+"_container' class='mCSB_container' style='position:relative; top:"+o.setTop+"; left:"+o.setLeft+";' dir='"+d.langDir+"' /></div>");
875			var mCustomScrollBox=$("#mCSB_"+d.idx),
876				mCSB_container=$("#mCSB_"+d.idx+"_container");
877			if(o.axis!=="y" && !o.advanced.autoExpandHorizontalScroll){
878				mCSB_container.css("width",_contentWidth(mCSB_container));
879			}
880			if(o.scrollbarPosition==="outside"){
881				if($this.css("position")==="static"){ /* requires elements with non-static position */
882					$this.css("position","relative");
883				}
884				$this.css("overflow","visible");
885				mCustomScrollBox.addClass("mCSB_outside").after(scrollbars);
886			}else{
887				mCustomScrollBox.addClass("mCSB_inside").append(scrollbars);
888				mCSB_container.wrap(contentWrapper);
889			}
890			_scrollButtons.call(this); /* add scrollbar buttons */
891			/* minimum dragger length */
892			var mCSB_dragger=[$("#mCSB_"+d.idx+"_dragger_vertical"),$("#mCSB_"+d.idx+"_dragger_horizontal")];
893			mCSB_dragger[0].css("min-height",mCSB_dragger[0].height());
894			mCSB_dragger[1].css("min-width",mCSB_dragger[1].width());
895		},
896		/* -------------------- */
897
898
899		/* calculates content width */
900		_contentWidth=function(el){
901			var val=[el[0].scrollWidth,Math.max.apply(Math,el.children().map(function(){return $(this).outerWidth(true);}).get())],w=el.parent().width();
902			return val[0]>w ? val[0] : val[1]>w ? val[1] : "100%";
903		},
904		/* -------------------- */
905
906
907		/* expands content horizontally */
908		_expandContentHorizontally=function(){
909			var $this=$(this),d=$this.data(pluginPfx),o=d.opt,
910				mCSB_container=$("#mCSB_"+d.idx+"_container");
911			if(o.advanced.autoExpandHorizontalScroll && o.axis!=="y"){
912				/* calculate scrollWidth */
913				mCSB_container.css({"width":"auto","min-width":0,"overflow-x":"scroll"});
914				var w=Math.ceil(mCSB_container[0].scrollWidth);
915				if(o.advanced.autoExpandHorizontalScroll===3 || (o.advanced.autoExpandHorizontalScroll!==2 && w>mCSB_container.parent().width())){
916					mCSB_container.css({"width":w,"min-width":"100%","overflow-x":"inherit"});
917				}else{
918					/*
919					wrap content with an infinite width div and set its position to absolute and width to auto.
920					Setting width to auto before calculating the actual width is important!
921					We must let the browser set the width as browser zoom values are impossible to calculate.
922					*/
923					mCSB_container.css({"overflow-x":"inherit","position":"absolute"})
924						.wrap("<div class='mCSB_h_wrapper' style='position:relative; left:0; width:999999px;' />")
925						.css({ /* set actual width, original position and un-wrap */
926							/*
927							get the exact width (with decimals) and then round-up.
928							Using jquery outerWidth() will round the width value which will mess up with inner elements that have non-integer width
929							*/
930							"width":(Math.ceil(mCSB_container[0].getBoundingClientRect().right+0.4)-Math.floor(mCSB_container[0].getBoundingClientRect().left)),
931							"min-width":"100%",
932							"position":"relative"
933						}).unwrap();
934				}
935			}
936		},
937		/* -------------------- */
938
939
940		/* adds scrollbar buttons */
941		_scrollButtons=function(){
942			var $this=$(this),d=$this.data(pluginPfx),o=d.opt,
943				mCSB_scrollTools=$(".mCSB_"+d.idx+"_scrollbar:first"),
944				tabindex=!_isNumeric(o.scrollButtons.tabindex) ? "" : "tabindex='"+o.scrollButtons.tabindex+"'",
945				btnHTML=[
946					"<a href='#' class='"+classes[13]+"' "+tabindex+" />",
947					"<a href='#' class='"+classes[14]+"' "+tabindex+" />",
948					"<a href='#' class='"+classes[15]+"' "+tabindex+" />",
949					"<a href='#' class='"+classes[16]+"' "+tabindex+" />"
950				],
951				btn=[(o.axis==="x" ? btnHTML[2] : btnHTML[0]),(o.axis==="x" ? btnHTML[3] : btnHTML[1]),btnHTML[2],btnHTML[3]];
952			if(o.scrollButtons.enable){
953				mCSB_scrollTools.prepend(btn[0]).append(btn[1]).next(".mCSB_scrollTools").prepend(btn[2]).append(btn[3]);
954			}
955		},
956		/* -------------------- */
957
958
959		/* auto-adjusts scrollbar dragger length */
960		_setDraggerLength=function(){
961			var $this=$(this),d=$this.data(pluginPfx),
962				mCustomScrollBox=$("#mCSB_"+d.idx),
963				mCSB_container=$("#mCSB_"+d.idx+"_container"),
964				mCSB_dragger=[$("#mCSB_"+d.idx+"_dragger_vertical"),$("#mCSB_"+d.idx+"_dragger_horizontal")],
965				ratio=[mCustomScrollBox.height()/mCSB_container.outerHeight(false),mCustomScrollBox.width()/mCSB_container.outerWidth(false)],
966				l=[
967					parseInt(mCSB_dragger[0].css("min-height")),Math.round(ratio[0]*mCSB_dragger[0].parent().height()),
968					parseInt(mCSB_dragger[1].css("min-width")),Math.round(ratio[1]*mCSB_dragger[1].parent().width())
969				],
970				h=oldIE && (l[1]<l[0]) ? l[0] : l[1],w=oldIE && (l[3]<l[2]) ? l[2] : l[3];
971			mCSB_dragger[0].css({
972				"height":h,"max-height":(mCSB_dragger[0].parent().height()-10)
973			}).find(".mCSB_dragger_bar").css({"line-height":l[0]+"px"});
974			mCSB_dragger[1].css({
975				"width":w,"max-width":(mCSB_dragger[1].parent().width()-10)
976			});
977		},
978		/* -------------------- */
979
980
981		/* calculates scrollbar to content ratio */
982		_scrollRatio=function(){
983			var $this=$(this),d=$this.data(pluginPfx),
984				mCustomScrollBox=$("#mCSB_"+d.idx),
985				mCSB_container=$("#mCSB_"+d.idx+"_container"),
986				mCSB_dragger=[$("#mCSB_"+d.idx+"_dragger_vertical"),$("#mCSB_"+d.idx+"_dragger_horizontal")],
987				scrollAmount=[mCSB_container.outerHeight(false)-mCustomScrollBox.height(),mCSB_container.outerWidth(false)-mCustomScrollBox.width()],
988				ratio=[
989					scrollAmount[0]/(mCSB_dragger[0].parent().height()-mCSB_dragger[0].height()),
990					scrollAmount[1]/(mCSB_dragger[1].parent().width()-mCSB_dragger[1].width())
991				];
992			d.scrollRatio={y:ratio[0],x:ratio[1]};
993		},
994		/* -------------------- */
995
996
997		/* toggles scrolling classes */
998		_onDragClasses=function(el,action,xpnd){
999			var expandClass=xpnd ? classes[0]+"_expanded" : "",
1000				scrollbar=el.closest(".mCSB_scrollTools");
1001			if(action==="active"){
1002				el.toggleClass(classes[0]+" "+expandClass); scrollbar.toggleClass(classes[1]);
1003				el[0]._draggable=el[0]._draggable ? 0 : 1;
1004			}else{
1005				if(!el[0]._draggable){
1006					if(action==="hide"){
1007						el.removeClass(classes[0]); scrollbar.removeClass(classes[1]);
1008					}else{
1009						el.addClass(classes[0]); scrollbar.addClass(classes[1]);
1010					}
1011				}
1012			}
1013		},
1014		/* -------------------- */
1015
1016
1017		/* checks if content overflows its container to determine if scrolling is required */
1018		_overflowed=function(){
1019			var $this=$(this),d=$this.data(pluginPfx),
1020				mCustomScrollBox=$("#mCSB_"+d.idx),
1021				mCSB_container=$("#mCSB_"+d.idx+"_container"),
1022				contentHeight=d.overflowed==null ? mCSB_container.height() : mCSB_container.outerHeight(false),
1023				contentWidth=d.overflowed==null ? mCSB_container.width() : mCSB_container.outerWidth(false),
1024				h=mCSB_container[0].scrollHeight,w=mCSB_container[0].scrollWidth;
1025			if(h>contentHeight){contentHeight=h;}
1026			if(w>contentWidth){contentWidth=w;}
1027			return [contentHeight>mCustomScrollBox.height(),contentWidth>mCustomScrollBox.width()];
1028		},
1029		/* -------------------- */
1030
1031
1032		/* resets content position to 0 */
1033		_resetContentPosition=function(){
1034			var $this=$(this),d=$this.data(pluginPfx),o=d.opt,
1035				mCustomScrollBox=$("#mCSB_"+d.idx),
1036				mCSB_container=$("#mCSB_"+d.idx+"_container"),
1037				mCSB_dragger=[$("#mCSB_"+d.idx+"_dragger_vertical"),$("#mCSB_"+d.idx+"_dragger_horizontal")];
1038			_stop($this); /* stop any current scrolling before resetting */
1039			if((o.axis!=="x" && !d.overflowed[0]) || (o.axis==="y" && d.overflowed[0])){ /* reset y */
1040				mCSB_dragger[0].add(mCSB_container).css("top",0);
1041				_scrollTo($this,"_resetY");
1042			}
1043			if((o.axis!=="y" && !d.overflowed[1]) || (o.axis==="x" && d.overflowed[1])){ /* reset x */
1044				var cx=dx=0;
1045				if(d.langDir==="rtl"){ /* adjust left position for rtl direction */
1046					cx=mCustomScrollBox.width()-mCSB_container.outerWidth(false);
1047					dx=Math.abs(cx/d.scrollRatio.x);
1048				}
1049				mCSB_container.css("left",cx);
1050				mCSB_dragger[1].css("left",dx);
1051				_scrollTo($this,"_resetX");
1052			}
1053		},
1054		/* -------------------- */
1055
1056
1057		/* binds scrollbar events */
1058		_bindEvents=function(){
1059			var $this=$(this),d=$this.data(pluginPfx),o=d.opt;
1060			if(!d.bindEvents){ /* check if events are already bound */
1061				_draggable.call(this);
1062				if(o.contentTouchScroll){_contentDraggable.call(this);}
1063				_selectable.call(this);
1064				if(o.mouseWheel.enable){ /* bind mousewheel fn when plugin is available */
1065					function _mwt(){
1066						mousewheelTimeout=setTimeout(function(){
1067							if(!$.event.special.mousewheel){
1068								_mwt();
1069							}else{
1070								clearTimeout(mousewheelTimeout);
1071								_mousewheel.call($this[0]);
1072							}
1073						},100);
1074					}
1075					var mousewheelTimeout;
1076					_mwt();
1077				}
1078				_draggerRail.call(this);
1079				_wrapperScroll.call(this);
1080				if(o.advanced.autoScrollOnFocus){_focus.call(this);}
1081				if(o.scrollButtons.enable){_buttons.call(this);}
1082				if(o.keyboard.enable){_keyboard.call(this);}
1083				d.bindEvents=true;
1084			}
1085		},
1086		/* -------------------- */
1087
1088
1089		/* unbinds scrollbar events */
1090		_unbindEvents=function(){
1091			var $this=$(this),d=$this.data(pluginPfx),o=d.opt,
1092				namespace=pluginPfx+"_"+d.idx,
1093				sb=".mCSB_"+d.idx+"_scrollbar",
1094				sel=$("#mCSB_"+d.idx+",#mCSB_"+d.idx+"_container,#mCSB_"+d.idx+"_container_wrapper,"+sb+" ."+classes[12]+",#mCSB_"+d.idx+"_dragger_vertical,#mCSB_"+d.idx+"_dragger_horizontal,"+sb+">a"),
1095				mCSB_container=$("#mCSB_"+d.idx+"_container");
1096			if(o.advanced.releaseDraggableSelectors){sel.add($(o.advanced.releaseDraggableSelectors));}
1097			if(o.advanced.extraDraggableSelectors){sel.add($(o.advanced.extraDraggableSelectors));}
1098			if(d.bindEvents){ /* check if events are bound */
1099				/* unbind namespaced events from document/selectors */
1100				$(document).add($(!_canAccessIFrame() || top.document)).unbind("."+namespace);
1101				sel.each(function(){
1102					$(this).unbind("."+namespace);
1103				});
1104				/* clear and delete timeouts/objects */
1105				clearTimeout($this[0]._focusTimeout); _delete($this[0],"_focusTimeout");
1106				clearTimeout(d.sequential.step); _delete(d.sequential,"step");
1107				clearTimeout(mCSB_container[0].onCompleteTimeout); _delete(mCSB_container[0],"onCompleteTimeout");
1108				d.bindEvents=false;
1109			}
1110		},
1111		/* -------------------- */
1112
1113
1114		/* toggles scrollbar visibility */
1115		_scrollbarVisibility=function(disabled){
1116			var $this=$(this),d=$this.data(pluginPfx),o=d.opt,
1117				contentWrapper=$("#mCSB_"+d.idx+"_container_wrapper"),
1118				content=contentWrapper.length ? contentWrapper : $("#mCSB_"+d.idx+"_container"),
1119				scrollbar=[$("#mCSB_"+d.idx+"_scrollbar_vertical"),$("#mCSB_"+d.idx+"_scrollbar_horizontal")],
1120				mCSB_dragger=[scrollbar[0].find(".mCSB_dragger"),scrollbar[1].find(".mCSB_dragger")];
1121			var scrollY=$this.find(".mCSB_scrollTools_vertical");
1122			var scrollX=$this.find(".mCSB_scrollTools_horizontal");
1123			if(o.axis!=="x"){
1124				if(d.overflowed[0] && !disabled){
1125					scrollbar[0].add(mCSB_dragger[0]).add(scrollbar[0].children("a")).css("display","block");
1126					content.removeClass(classes[8]+" "+classes[10]);
1127				}else{
1128					if(o.alwaysShowScrollbar){
1129						if(o.alwaysShowScrollbar!==2){mCSB_dragger[0].css("display","none");}
1130						content.removeClass(classes[10]);
1131					}else{
1132						scrollbar[0].css("display","none");
1133						content.addClass(classes[10]);
1134					}
1135					content.addClass(classes[8]);
1136				}
1137			}
1138			if(o.axis!=="y"){
1139				if(d.overflowed[1] && !disabled){
1140					scrollbar[1].add(mCSB_dragger[1]).add(scrollbar[1].children("a")).css("display","block");
1141					content.removeClass(classes[9]+" "+classes[11]);
1142				}else{
1143					if(o.alwaysShowScrollbar){
1144						if(o.alwaysShowScrollbar!==2){mCSB_dragger[1].css("display","none");}
1145						content.removeClass(classes[11]);
1146					}else{
1147						scrollbar[1].css("display","none");
1148						content.addClass(classes[11]);
1149					}
1150					content.addClass(classes[9]);
1151				}
1152			}
1153			if(!d.overflowed[0] && !d.overflowed[1]){
1154				$this.addClass(classes[5]);
1155        if(scrollY.css("display") == "none"){
1156            $this.addClass(classes[8]);
1157        } else {
1158        }
1159				if(scrollX.css("display") == "none"){
1160            $this.addClass(classes[9]);
1161        } else {
1162        }
1163			}else{
1164				$this.removeClass(classes[5]);
1165        if(scrollY.css("display") == "block"){
1166            $this.removeClass(classes[8]);
1167        } else {
1168						$this.addClass(classes[8]);
1169        }
1170				if(scrollX.css("display") == "block"){
1171            $this.removeClass(classes[9]);
1172        } else {
1173						  $this.addClass(classes[9]);
1174        }
1175			}
1176		},
1177		/* -------------------- */
1178
1179
1180		/* returns input coordinates of pointer, touch and mouse events (relative to document) */
1181		_coordinates=function(e){
1182			var t=e.type,o=e.target.ownerDocument!==document && frameElement!==null ? [$(frameElement).offset().top,$(frameElement).offset().left] : null,
1183				io=_canAccessIFrame() && e.target.ownerDocument!==top.document && frameElement!==null ? [$(e.view.frameElement).offset().top,$(e.view.frameElement).offset().left] : [0,0];
1184			switch(t){
1185				case "pointerdown": case "MSPointerDown": case "pointermove": case "MSPointerMove": case "pointerup": case "MSPointerUp":
1186					return o ? [e.originalEvent.pageY-o[0]+io[0],e.originalEvent.pageX-o[1]+io[1],false] : [e.originalEvent.pageY,e.originalEvent.pageX,false];
1187					break;
1188				case "touchstart": case "touchmove": case "touchend":
1189					var touch=e.originalEvent.touches[0] || e.originalEvent.changedTouches[0],
1190						touches=e.originalEvent.touches.length || e.originalEvent.changedTouches.length;
1191					return e.target.ownerDocument!==document ? [touch.screenY,touch.screenX,touches>1] : [touch.pageY,touch.pageX,touches>1];
1192					break;
1193				default:
1194					return o ? [e.pageY-o[0]+io[0],e.pageX-o[1]+io[1],false] : [e.pageY,e.pageX,false];
1195			}
1196		},
1197		/* -------------------- */
1198
1199
1200		/*
1201		SCROLLBAR DRAG EVENTS
1202		scrolls content via scrollbar dragging
1203		*/
1204		_draggable=function(){
1205			var $this=$(this),d=$this.data(pluginPfx),o=d.opt,
1206				namespace=pluginPfx+"_"+d.idx,
1207				draggerId=["mCSB_"+d.idx+"_dragger_vertical","mCSB_"+d.idx+"_dragger_horizontal"],
1208				mCSB_container=$("#mCSB_"+d.idx+"_container"),
1209				mCSB_dragger=$("#"+draggerId[0]+",#"+draggerId[1]),
1210				draggable,dragY,dragX,
1211				rds=o.advanced.releaseDraggableSelectors ? mCSB_dragger.add($(o.advanced.releaseDraggableSelectors)) : mCSB_dragger,
1212				eds=o.advanced.extraDraggableSelectors ? $(!_canAccessIFrame() || top.document).add($(o.advanced.extraDraggableSelectors)) : $(!_canAccessIFrame() || top.document);
1213			mCSB_dragger.bind("contextmenu."+namespace,function(e){
1214				e.preventDefault(); //prevent right click
1215			}).bind("mousedown."+namespace+" touchstart."+namespace+" pointerdown."+namespace+" MSPointerDown."+namespace,function(e){
1216				e.stopImmediatePropagation();
1217				e.preventDefault();
1218				if(!_mouseBtnLeft(e)){return;} /* left mouse button only */
1219				touchActive=true;
1220				if(oldIE){document.onselectstart=function(){return false;}} /* disable text selection for IE < 9 */
1221				_iframe.call(mCSB_container,false); /* enable scrollbar dragging over iframes by disabling their events */
1222				_stop($this);
1223				draggable=$(this);
1224				var offset=draggable.offset(),y=_coordinates(e)[0]-offset.top,x=_coordinates(e)[1]-offset.left,
1225					h=draggable.height()+offset.top,w=draggable.width()+offset.left;
1226				if(y<h && y>0 && x<w && x>0){
1227					dragY=y;
1228					dragX=x;
1229				}
1230				_onDragClasses(draggable,"active",o.autoExpandScrollbar);
1231			}).bind("touchmove."+namespace,function(e){
1232				e.stopImmediatePropagation();
1233				e.preventDefault();
1234				var offset=draggable.offset(),y=_coordinates(e)[0]-offset.top,x=_coordinates(e)[1]-offset.left;
1235				_drag(dragY,dragX,y,x);
1236			});
1237			$(document).add(eds).bind("mousemove."+namespace+" pointermove."+namespace+" MSPointerMove."+namespace,function(e){
1238				if(draggable){
1239					var offset=draggable.offset(),y=_coordinates(e)[0]-offset.top,x=_coordinates(e)[1]-offset.left;
1240					if(dragY===y && dragX===x){return;} /* has it really moved? */
1241					_drag(dragY,dragX,y,x);
1242				}
1243			}).add(rds).bind("mouseup."+namespace+" touchend."+namespace+" pointerup."+namespace+" MSPointerUp."+namespace,function(e){
1244				if(draggable){
1245					_onDragClasses(draggable,"active",o.autoExpandScrollbar);
1246					draggable=null;
1247				}
1248				touchActive=false;
1249				if(oldIE){document.onselectstart=null;} /* enable text selection for IE < 9 */
1250				_iframe.call(mCSB_container,true); /* enable iframes events */
1251			});
1252			function _drag(dragY,dragX,y,x){
1253				mCSB_container[0].idleTimer=o.scrollInertia<233 ? 250 : 0;
1254				if(draggable.attr("id")===draggerId[1]){
1255					var dir="x",to=((draggable[0].offsetLeft-dragX)+x)*d.scrollRatio.x;
1256				}else{
1257					var dir="y",to=((draggable[0].offsetTop-dragY)+y)*d.scrollRatio.y;
1258				}
1259				_scrollTo($this,to.toString(),{dir:dir,drag:true});
1260			}
1261		},
1262		/* -------------------- */
1263
1264
1265		/*
1266		TOUCH SWIPE EVENTS
1267		scrolls content via touch swipe
1268		Emulates the native touch-swipe scrolling with momentum found in iOS, Android and WP devices
1269		*/
1270		_contentDraggable=function(){
1271			var $this=$(this),d=$this.data(pluginPfx),o=d.opt,
1272				namespace=pluginPfx+"_"+d.idx,
1273				mCustomScrollBox=$("#mCSB_"+d.idx),
1274				mCSB_container=$("#mCSB_"+d.idx+"_container"),
1275				mCSB_dragger=[$("#mCSB_"+d.idx+"_dragger_vertical"),$("#mCSB_"+d.idx+"_dragger_horizontal")],
1276				draggable,dragY,dragX,touchStartY,touchStartX,touchMoveY=[],touchMoveX=[],startTime,runningTime,endTime,distance,speed,amount,
1277				durA=0,durB,overwrite=o.axis==="yx" ? "none" : "all",touchIntent=[],touchDrag,docDrag,
1278				iframe=mCSB_container.find("iframe"),
1279				events=[
1280					"touchstart."+namespace+" pointerdown."+namespace+" MSPointerDown."+namespace, //start
1281					"touchmove."+namespace+" pointermove."+namespace+" MSPointerMove."+namespace, //move
1282					"touchend."+namespace+" pointerup."+namespace+" MSPointerUp."+namespace //end
1283				],
1284				touchAction=document.body.style.touchAction!==undefined && document.body.style.touchAction!=="";
1285			mCSB_container.bind(events[0],function(e){
1286				_onTouchstart(e);
1287			}).bind(events[1],function(e){
1288				_onTouchmove(e);
1289			});
1290			mCustomScrollBox.bind(events[0],function(e){
1291				_onTouchstart2(e);
1292			}).bind(events[2],function(e){
1293				_onTouchend(e);
1294			});
1295			if(iframe.length){
1296				iframe.each(function(){
1297					$(this).bind("load",function(){
1298						/* bind events on accessible iframes */
1299						if(_canAccessIFrame(this)){
1300							$(this.contentDocument || this.contentWindow.document).bind(events[0],function(e){
1301								_onTouchstart(e);
1302								_onTouchstart2(e);
1303							}).bind(events[1],function(e){
1304								_onTouchmove(e);
1305							}).bind(events[2],function(e){
1306								_onTouchend(e);
1307							});
1308						}
1309					});
1310				});
1311			}
1312			function _onTouchstart(e){
1313				if(!_pointerTouch(e) || touchActive || _coordinates(e)[2]){touchable=0; return;}
1314				touchable=1; touchDrag=0; docDrag=0; draggable=1;
1315				$this.removeClass("mCS_touch_action");
1316				var offset=mCSB_container.offset();
1317				dragY=_coordinates(e)[0]-offset.top;
1318				dragX=_coordinates(e)[1]-offset.left;
1319				touchIntent=[_coordinates(e)[0],_coordinates(e)[1]];
1320			}
1321			function _onTouchmove(e){
1322				if(!_pointerTouch(e) || touchActive || _coordinates(e)[2]){return;}
1323				if(!o.documentTouchScroll){e.preventDefault();}
1324				e.stopImmediatePropagation();
1325				if(docDrag && !touchDrag){return;}
1326				if(draggable){
1327					runningTime=_getTime();
1328					var offset=mCustomScrollBox.offset(),y=_coordinates(e)[0]-offset.top,x=_coordinates(e)[1]-offset.left,
1329						easing="mcsLinearOut";
1330					touchMoveY.push(y);
1331					touchMoveX.push(x);
1332					touchIntent[2]=Math.abs(_coordinates(e)[0]-touchIntent[0]); touchIntent[3]=Math.abs(_coordinates(e)[1]-touchIntent[1]);
1333					if(d.overflowed[0]){
1334						var limit=mCSB_dragger[0].parent().height()-mCSB_dragger[0].height(),
1335							prevent=((dragY-y)>0 && (y-dragY)>-(limit*d.scrollRatio.y) && (touchIntent[3]*2<touchIntent[2] || o.axis==="yx"));
1336					}
1337					if(d.overflowed[1]){
1338						var limitX=mCSB_dragger[1].parent().width()-mCSB_dragger[1].width(),
1339							preventX=((dragX-x)>0 && (x-dragX)>-(limitX*d.scrollRatio.x) && (touchIntent[2]*2<touchIntent[3] || o.axis==="yx"));
1340					}
1341					if(prevent || preventX){ /* prevent native document scrolling */
1342						if(!touchAction){e.preventDefault();}
1343						touchDrag=1;
1344					}else{
1345						docDrag=1;
1346						$this.addClass("mCS_touch_action");
1347					}
1348					if(touchAction){e.preventDefault();}
1349					amount=o.axis==="yx" ? [(dragY-y),(dragX-x)] : o.axis==="x" ? [null,(dragX-x)] : [(dragY-y),null];
1350					mCSB_container[0].idleTimer=250;
1351					if(d.overflowed[0]){_drag(amount[0],durA,easing,"y","all",true);}
1352					if(d.overflowed[1]){_drag(amount[1],durA,easing,"x",overwrite,true);}
1353				}
1354			}
1355			function _onTouchstart2(e){
1356				if(!_pointerTouch(e) || touchActive || _coordinates(e)[2]){touchable=0; return;}
1357				touchable=1;
1358				e.stopImmediatePropagation();
1359				_stop($this);
1360				startTime=_getTime();
1361				var offset=mCustomScrollBox.offset();
1362				touchStartY=_coordinates(e)[0]-offset.top;
1363				touchStartX=_coordinates(e)[1]-offset.left;
1364				touchMoveY=[]; touchMoveX=[];
1365			}
1366			function _onTouchend(e){
1367				if(!_pointerTouch(e) || touchActive || _coordinates(e)[2]){return;}
1368				draggable=0;
1369				e.stopImmediatePropagation();
1370				touchDrag=0; docDrag=0;
1371				endTime=_getTime();
1372				var offset=mCustomScrollBox.offset(),y=_coordinates(e)[0]-offset.top,x=_coordinates(e)[1]-offset.left;
1373				if((endTime-runningTime)>30){return;}
1374				speed=1000/(endTime-startTime);
1375				var easing="mcsEaseOut",slow=speed<2.5,
1376					diff=slow ? [touchMoveY[touchMoveY.length-2],touchMoveX[touchMoveX.length-2]] : [0,0];
1377				distance=slow ? [(y-diff[0]),(x-diff[1])] : [y-touchStartY,x-touchStartX];
1378				var absDistance=[Math.abs(distance[0]),Math.abs(distance[1])];
1379				speed=slow ? [Math.abs(distance[0]/4),Math.abs(distance[1]/4)] : [speed,speed];
1380				var a=[
1381					Math.abs(mCSB_container[0].offsetTop)-(distance[0]*_m((absDistance[0]/speed[0]),speed[0])),
1382					Math.abs(mCSB_container[0].offsetLeft)-(distance[1]*_m((absDistance[1]/speed[1]),speed[1]))
1383				];
1384				amount=o.axis==="yx" ? [a[0],a[1]] : o.axis==="x" ? [null,a[1]] : [a[0],null];
1385				durB=[(absDistance[0]*4)+o.scrollInertia,(absDistance[1]*4)+o.scrollInertia];
1386				var md=parseInt(o.contentTouchScroll) || 0; /* absolute minimum distance required */
1387				amount[0]=absDistance[0]>md ? amount[0] : 0;
1388				amount[1]=absDistance[1]>md ? amount[1] : 0;
1389				if(d.overflowed[0]){_drag(amount[0],durB[0],easing,"y",overwrite,false);}
1390				if(d.overflowed[1]){_drag(amount[1],durB[1],easing,"x",overwrite,false);}
1391			}
1392			function _m(ds,s){
1393				var r=[s*1.5,s*2,s/1.5,s/2];
1394				if(ds>90){
1395					return s>4 ? r[0] : r[3];
1396				}else if(ds>60){
1397					return s>3 ? r[3] : r[2];
1398				}else if(ds>30){
1399					return s>8 ? r[1] : s>6 ? r[0] : s>4 ? s : r[2];
1400				}else{
1401					return s>8 ? s : r[3];
1402				}
1403			}
1404			function _drag(amount,dur,easing,dir,overwrite,drag){
1405				if(!amount){return;}
1406				_scrollTo($this,amount.toString(),{dur:dur,scrollEasing:easing,dir:dir,overwrite:overwrite,drag:drag});
1407			}
1408		},
1409		/* -------------------- */
1410
1411
1412		/*
1413		SELECT TEXT EVENTS
1414		scrolls content when text is selected
1415		*/
1416		_selectable=function(){
1417			var $this=$(this),d=$this.data(pluginPfx),o=d.opt,seq=d.sequential,
1418				namespace=pluginPfx+"_"+d.idx,
1419				mCSB_container=$("#mCSB_"+d.idx+"_container"),
1420				wrapper=mCSB_container.parent(),
1421				action;
1422			mCSB_container.bind("mousedown."+namespace,function(e){
1423				if(touchable){return;}
1424				if(!action){action=1; touchActive=true;}
1425			}).add(document).bind("mousemove."+namespace,function(e){
1426				if(!touchable && action && _sel()){
1427					var offset=mCSB_container.offset(),
1428						y=_coordinates(e)[0]-offset.top+mCSB_container[0].offsetTop,x=_coordinates(e)[1]-offset.left+mCSB_container[0].offsetLeft;
1429					if(y>0 && y<wrapper.height() && x>0 && x<wrapper.width()){
1430						if(seq.step){_seq("off",null,"stepped");}
1431					}else{
1432						if(o.axis!=="x" && d.overflowed[0]){
1433							if(y<0){
1434								_seq("on",38);
1435							}else if(y>wrapper.height()){
1436								_seq("on",40);
1437							}
1438						}
1439						if(o.axis!=="y" && d.overflowed[1]){
1440							if(x<0){
1441								_seq("on",37);
1442							}else if(x>wrapper.width()){
1443								_seq("on",39);
1444							}
1445						}
1446					}
1447				}
1448			}).bind("mouseup."+namespace+" dragend."+namespace,function(e){
1449				if(touchable){return;}
1450				if(action){action=0; _seq("off",null);}
1451				touchActive=false;
1452			});
1453			function _sel(){
1454				return 	window.getSelection ? window.getSelection().toString() :
1455						document.selection && document.selection.type!="Control" ? document.selection.createRange().text : 0;
1456			}
1457			function _seq(a,c,s){
1458				seq.type=s && action ? "stepped" : "stepless";
1459				seq.scrollAmount=10;
1460				_sequentialScroll($this,a,c,"mcsLinearOut",s ? 60 : null);
1461			}
1462		},
1463		/* -------------------- */
1464
1465
1466		/*
1467		MOUSE WHEEL EVENT
1468		scrolls content via mouse-wheel
1469		via mouse-wheel plugin (https://github.com/brandonaaron/jquery-mousewheel)
1470		*/
1471		_mousewheel=function(){
1472			if(!$(this).data(pluginPfx)){return;} /* Check if the scrollbar is ready to use mousewheel events (issue: #185) */
1473			var $this=$(this),d=$this.data(pluginPfx),o=d.opt,
1474				namespace=pluginPfx+"_"+d.idx,
1475				mCustomScrollBox=$("#mCSB_"+d.idx),
1476				mCSB_dragger=[$("#mCSB_"+d.idx+"_dragger_vertical"),$("#mCSB_"+d.idx+"_dragger_horizontal")],
1477				iframe=$("#mCSB_"+d.idx+"_container").find("iframe");
1478			if(iframe.length){
1479				iframe.each(function(){
1480					$(this).bind("load",function(){
1481						/* bind events on accessible iframes */
1482						if(_canAccessIFrame(this)){
1483							$(this.contentDocument || this.contentWindow.document).bind("mousewheel."+namespace,function(e,delta){
1484								_onMousewheel(e,delta);
1485							});
1486						}
1487					});
1488				});
1489			}
1490			mCustomScrollBox.bind("mousewheel."+namespace,function(e,delta){
1491				_onMousewheel(e,delta);
1492			});
1493			function _onMousewheel(e,delta){
1494				_stop($this);
1495				if(_disableMousewheel($this,e.target)){return;} /* disables mouse-wheel when hovering specific elements */
1496				var deltaFactor=o.mouseWheel.deltaFactor!=="auto" ? parseInt(o.mouseWheel.deltaFactor) : (oldIE && e.deltaFactor<100) ? 100 : e.deltaFactor || 100,
1497					dur=o.scrollInertia;
1498				if(o.axis==="x" || o.mouseWheel.axis==="x"){
1499					var dir="x",
1500						px=[Math.round(deltaFactor*d.scrollRatio.x),parseInt(o.mouseWheel.scrollAmount)],
1501						amount=o.mouseWheel.scrollAmount!=="auto" ? px[1] : px[0]>=mCustomScrollBox.width() ? mCustomScrollBox.width()*0.9 : px[0],
1502						contentPos=Math.abs($("#mCSB_"+d.idx+"_container")[0].offsetLeft),
1503						draggerPos=mCSB_dragger[1][0].offsetLeft,
1504						limit=mCSB_dragger[1].parent().width()-mCSB_dragger[1].width(),
1505						dlt=o.mouseWheel.axis==="y" ? (e.deltaY || delta) : e.deltaX;
1506				}else{
1507					var dir="y",
1508						px=[Math.round(deltaFactor*d.scrollRatio.y),parseInt(o.mouseWheel.scrollAmount)],
1509						amount=o.mouseWheel.scrollAmount!=="auto" ? px[1] : px[0]>=mCustomScrollBox.height() ? mCustomScrollBox.height()*0.9 : px[0],
1510						contentPos=Math.abs($("#mCSB_"+d.idx+"_container")[0].offsetTop),
1511						draggerPos=mCSB_dragger[0][0].offsetTop,
1512						limit=mCSB_dragger[0].parent().height()-mCSB_dragger[0].height(),
1513						dlt=e.deltaY || delta;
1514				}
1515				if((dir==="y" && !d.overflowed[0]) || (dir==="x" && !d.overflowed[1])){return;}
1516				if(o.mouseWheel.invert || e.webkitDirectionInvertedFromDevice){dlt=-dlt;}
1517				if(o.mouseWheel.normalizeDelta){dlt=dlt<0 ? -1 : 1;}
1518				if((dlt>0 && draggerPos!==0) || (dlt<0 && draggerPos!==limit) || o.mouseWheel.preventDefault){
1519					e.stopImmediatePropagation();
1520					e.preventDefault();
1521				}
1522				if(e.deltaFactor<5 && !o.mouseWheel.normalizeDelta){
1523					//very low deltaFactor values mean some kind of delta acceleration (e.g. osx trackpad), so adjusting scrolling accordingly
1524					amount=e.deltaFactor; dur=17;
1525				}
1526				_scrollTo($this,(contentPos-(dlt*amount)).toString(),{dir:dir,dur:dur});
1527			}
1528		},
1529		/* -------------------- */
1530
1531
1532		/* checks if iframe can be accessed */
1533		_canAccessIFrameCache=new Object(),
1534		_canAccessIFrame=function(iframe){
1535		    var result=false,cacheKey=false,html=null;
1536		    if(iframe===undefined){
1537				cacheKey="#empty";
1538		    }else if($(iframe).attr("id")!==undefined){
1539				cacheKey=$(iframe).attr("id");
1540		    }
1541			if(cacheKey!==false && _canAccessIFrameCache[cacheKey]!==undefined){
1542				return _canAccessIFrameCache[cacheKey];
1543			}
1544			if(!iframe){
1545				try{
1546					var doc=top.document;
1547					html=doc.body.innerHTML;
1548				}catch(err){/* do nothing */}
1549				result=(html!==null);
1550			}else{
1551				try{
1552					var doc=iframe.contentDocument || iframe.contentWindow.document;
1553					html=doc.body.innerHTML;
1554				}catch(err){/* do nothing */}
1555				result=(html!==null);
1556			}
1557			if(cacheKey!==false){_canAccessIFrameCache[cacheKey]=result;}
1558			return result;
1559		},
1560		/* -------------------- */
1561
1562
1563		/* switches iframe's pointer-events property (drag, mousewheel etc. over cross-domain iframes) */
1564		_iframe=function(evt){
1565			var el=this.find("iframe");
1566			if(!el.length){return;} /* check if content contains iframes */
1567			var val=!evt ? "none" : "auto";
1568			el.css("pointer-events",val); /* for IE11, iframe's display property should not be "block" */
1569		},
1570		/* -------------------- */
1571
1572
1573		/* disables mouse-wheel when hovering specific elements like select, datalist etc. */
1574		_disableMousewheel=function(el,target){
1575			var tag=target.nodeName.toLowerCase(),
1576				tags=el.data(pluginPfx).opt.mouseWheel.disableOver,
1577				/* elements that require focus */
1578				focusTags=["select","textarea"];
1579			return $.inArray(tag,tags) > -1 && !($.inArray(tag,focusTags) > -1 && !$(target).is(":focus"));
1580		},
1581		/* -------------------- */
1582
1583
1584		/*
1585		DRAGGER RAIL CLICK EVENT
1586		scrolls content via dragger rail
1587		*/
1588		_draggerRail=function(){
1589			var $this=$(this),d=$this.data(pluginPfx),
1590				namespace=pluginPfx+"_"+d.idx,
1591				mCSB_container=$("#mCSB_"+d.idx+"_container"),
1592				wrapper=mCSB_container.parent(),
1593				mCSB_draggerContainer=$(".mCSB_"+d.idx+"_scrollbar ."+classes[12]),
1594				clickable;
1595			mCSB_draggerContainer.bind("mousedown."+namespace+" touchstart."+namespace+" pointerdown."+namespace+" MSPointerDown."+namespace,function(e){
1596				touchActive=true;
1597				if(!$(e.target).hasClass("mCSB_dragger")){clickable=1;}
1598			}).bind("touchend."+namespace+" pointerup."+namespace+" MSPointerUp."+namespace,function(e){
1599				touchActive=false;
1600			}).bind("click."+namespace,function(e){
1601				if(!clickable){return;}
1602				clickable=0;
1603				if($(e.target).hasClass(classes[12]) || $(e.target).hasClass("mCSB_draggerRail")){
1604					_stop($this);
1605					var el=$(this),mCSB_dragger=el.find(".mCSB_dragger");
1606					if(el.parent(".mCSB_scrollTools_horizontal").length>0){
1607						if(!d.overflowed[1]){return;}
1608						var dir="x",
1609							clickDir=e.pageX>mCSB_dragger.offset().left ? -1 : 1,
1610							to=Math.abs(mCSB_container[0].offsetLeft)-(clickDir*(wrapper.width()*0.9));
1611					}else{
1612						if(!d.overflowed[0]){return;}
1613						var dir="y",
1614							clickDir=e.pageY>mCSB_dragger.offset().top ? -1 : 1,
1615							to=Math.abs(mCSB_container[0].offsetTop)-(clickDir*(wrapper.height()*0.9));
1616					}
1617					_scrollTo($this,to.toString(),{dir:dir,scrollEasing:"mcsEaseInOut"});
1618				}
1619			});
1620		},
1621		/* -------------------- */
1622
1623
1624		/*
1625		FOCUS EVENT
1626		scrolls content via element focus (e.g. clicking an input, pressing TAB key etc.)
1627		*/
1628		_focus=function(){
1629			var $this=$(this),d=$this.data(pluginPfx),o=d.opt,
1630				namespace=pluginPfx+"_"+d.idx,
1631				mCSB_container=$("#mCSB_"+d.idx+"_container"),
1632				wrapper=mCSB_container.parent();
1633			mCSB_container.bind("focusin."+namespace,function(e){
1634				var el=$(document.activeElement),
1635					nested=mCSB_container.find(".mCustomScrollBox").length,
1636					dur=0;
1637				if(!el.is(o.advanced.autoScrollOnFocus)){return;}
1638				_stop($this);
1639				clearTimeout($this[0]._focusTimeout);
1640				$this[0]._focusTimer=nested ? (dur+17)*nested : 0;
1641				$this[0]._focusTimeout=setTimeout(function(){
1642					var	to=[_childPos(el)[0],_childPos(el)[1]],
1643						contentPos=[mCSB_container[0].offsetTop,mCSB_container[0].offsetLeft],
1644						isVisible=[
1645							(contentPos[0]+to[0]>=0 && contentPos[0]+to[0]<wrapper.height()-el.outerHeight(false)),
1646							(contentPos[1]+to[1]>=0 && contentPos[0]+to[1]<wrapper.width()-el.outerWidth(false))
1647						],
1648						overwrite=(o.axis==="yx" && !isVisible[0] && !isVisible[1]) ? "none" : "all";
1649					if(o.axis!=="x" && !isVisible[0]){
1650						_scrollTo($this,to[0].toString(),{dir:"y",scrollEasing:"mcsEaseInOut",overwrite:overwrite,dur:dur});
1651					}
1652					if(o.axis!=="y" && !isVisible[1]){
1653						_scrollTo($this,to[1].toString(),{dir:"x",scrollEasing:"mcsEaseInOut",overwrite:overwrite,dur:dur});
1654					}
1655				},$this[0]._focusTimer);
1656			});
1657		},
1658		/* -------------------- */
1659
1660
1661		/* sets content wrapper scrollTop/scrollLeft always to 0 */
1662		_wrapperScroll=function(){
1663			var $this=$(this),d=$this.data(pluginPfx),
1664				namespace=pluginPfx+"_"+d.idx,
1665				wrapper=$("#mCSB_"+d.idx+"_container").parent();
1666			wrapper.bind("scroll."+namespace,function(e){
1667				if(wrapper.scrollTop()!==0 || wrapper.scrollLeft()!==0){
1668					$(".mCSB_"+d.idx+"_scrollbar").css("visibility","hidden"); /* hide scrollbar(s) */
1669				}
1670			});
1671		},
1672		/* -------------------- */
1673
1674
1675		/*
1676		BUTTONS EVENTS
1677		scrolls content via up, down, left and right buttons
1678		*/
1679		_buttons=function(){
1680			var $this=$(this),d=$this.data(pluginPfx),o=d.opt,seq=d.sequential,
1681				namespace=pluginPfx+"_"+d.idx,
1682				sel=".mCSB_"+d.idx+"_scrollbar",
1683				btn=$(sel+">a");
1684			btn.bind("contextmenu."+namespace,function(e){
1685				e.preventDefault(); //prevent right click
1686			}).bind("mousedown."+namespace+" touchstart."+namespace+" pointerdown."+namespace+" MSPointerDown."+namespace+" mouseup."+namespace+" touchend."+namespace+" pointerup."+namespace+" MSPointerUp."+namespace+" mouseout."+namespace+" pointerout."+namespace+" MSPointerOut."+namespace+" click."+namespace,function(e){
1687				e.preventDefault();
1688				if(!_mouseBtnLeft(e)){return;} /* left mouse button only */
1689				var btnClass=$(this).attr("class");
1690				seq.type=o.scrollButtons.scrollType;
1691				switch(e.type){
1692					case "mousedown": case "touchstart": case "pointerdown": case "MSPointerDown":
1693						if(seq.type==="stepped"){return;}
1694						touchActive=true;
1695						d.tweenRunning=false;
1696						_seq("on",btnClass);
1697						break;
1698					case "mouseup": case "touchend": case "pointerup": case "MSPointerUp":
1699					case "mouseout": case "pointerout": case "MSPointerOut":
1700						if(seq.type==="stepped"){return;}
1701						touchActive=false;
1702						if(seq.dir){_seq("off",btnClass);}
1703						break;
1704					case "click":
1705						if(seq.type!=="stepped" || d.tweenRunning){return;}
1706						_seq("on",btnClass);
1707						break;
1708				}
1709				function _seq(a,c){
1710					seq.scrollAmount=o.scrollButtons.scrollAmount;
1711					_sequentialScroll($this,a,c);
1712				}
1713			});
1714		},
1715		/* -------------------- */
1716
1717
1718		/*
1719		KEYBOARD EVENTS
1720		scrolls content via keyboard
1721		Keys: up arrow, down arrow, left arrow, right arrow, PgUp, PgDn, Home, End
1722		*/
1723		_keyboard=function(){
1724			var $this=$(this),d=$this.data(pluginPfx),o=d.opt,seq=d.sequential,
1725				namespace=pluginPfx+"_"+d.idx,
1726				mCustomScrollBox=$("#mCSB_"+d.idx),
1727				mCSB_container=$("#mCSB_"+d.idx+"_container"),
1728				wrapper=mCSB_container.parent(),
1729				editables="input,textarea,select,datalist,keygen,[contenteditable='true']",
1730				iframe=mCSB_container.find("iframe"),
1731				events=["blur."+namespace+" keydown."+namespace+" keyup."+namespace];
1732			if(iframe.length){
1733				iframe.each(function(){
1734					$(this).bind("load",function(){
1735						/* bind events on accessible iframes */
1736						if(_canAccessIFrame(this)){
1737							$(this.contentDocument || this.contentWindow.document).bind(events[0],function(e){
1738								_onKeyboard(e);
1739							});
1740						}
1741					});
1742				});
1743			}
1744			mCustomScrollBox.attr("tabindex","0").bind(events[0],function(e){
1745				_onKeyboard(e);
1746			});
1747			function _onKeyboard(e){
1748				switch(e.type){
1749					case "blur":
1750						if(d.tweenRunning && seq.dir){_seq("off",null);}
1751						break;
1752					case "keydown": case "keyup":
1753						var code=e.keyCode ? e.keyCode : e.which,action="on";
1754						if((o.axis!=="x" && (code===38 || code===40)) || (o.axis!=="y" && (code===37 || code===39))){
1755							/* up (38), down (40), left (37), right (39) arrows */
1756							if(((code===38 || code===40) && !d.overflowed[0]) || ((code===37 || code===39) && !d.overflowed[1])){return;}
1757							if(e.type==="keyup"){action="off";}
1758							if(!$(document.activeElement).is(editables)){
1759								e.preventDefault();
1760								e.stopImmediatePropagation();
1761								_seq(action,code);
1762							}
1763						}else if(code===33 || code===34){
1764							/* PgUp (33), PgDn (34) */
1765							if(d.overflowed[0] || d.overflowed[1]){
1766								e.preventDefault();
1767								e.stopImmediatePropagation();
1768							}
1769							if(e.type==="keyup"){
1770								_stop($this);
1771								var keyboardDir=code===34 ? -1 : 1;
1772								if(o.axis==="x" || (o.axis==="yx" && d.overflowed[1] && !d.overflowed[0])){
1773									var dir="x",to=Math.abs(mCSB_container[0].offsetLeft)-(keyboardDir*(wrapper.width()*0.9));
1774								}else{
1775									var dir="y",to=Math.abs(mCSB_container[0].offsetTop)-(keyboardDir*(wrapper.height()*0.9));
1776								}
1777								_scrollTo($this,to.toString(),{dir:dir,scrollEasing:"mcsEaseInOut"});
1778							}
1779						}else if(code===35 || code===36){
1780							/* End (35), Home (36) */
1781							if(!$(document.activeElement).is(editables)){
1782								if(d.overflowed[0] || d.overflowed[1]){
1783									e.preventDefault();
1784									e.stopImmediatePropagation();
1785								}
1786								if(e.type==="keyup"){
1787									if(o.axis==="x" || (o.axis==="yx" && d.overflowed[1] && !d.overflowed[0])){
1788										var dir="x",to=code===35 ? Math.abs(wrapper.width()-mCSB_container.outerWidth(false)) : 0;
1789									}else{
1790										var dir="y",to=code===35 ? Math.abs(wrapper.height()-mCSB_container.outerHeight(false)) : 0;
1791									}
1792									_scrollTo($this,to.toString(),{dir:dir,scrollEasing:"mcsEaseInOut"});
1793								}
1794							}
1795						}
1796						break;
1797				}
1798				function _seq(a,c){
1799					seq.type=o.keyboard.scrollType;
1800					seq.scrollAmount=o.keyboard.scrollAmount;
1801					if(seq.type==="stepped" && d.tweenRunning){return;}
1802					_sequentialScroll($this,a,c);
1803				}
1804			}
1805		},
1806		/* -------------------- */
1807
1808
1809		/* scrolls content sequentially (used when scrolling via buttons, keyboard arrows etc.) */
1810		_sequentialScroll=function(el,action,trigger,e,s){
1811			var d=el.data(pluginPfx),o=d.opt,seq=d.sequential,
1812				mCSB_container=$("#mCSB_"+d.idx+"_container"),
1813				once=seq.type==="stepped" ? true : false,
1814				steplessSpeed=o.scrollInertia < 26 ? 26 : o.scrollInertia, /* 26/1.5=17 */
1815				steppedSpeed=o.scrollInertia < 1 ? 17 : o.scrollInertia;
1816			switch(action){
1817				case "on":
1818					seq.dir=[
1819						(trigger===classes[16] || trigger===classes[15] || trigger===39 || trigger===37 ? "x" : "y"),
1820						(trigger===classes[13] || trigger===classes[15] || trigger===38 || trigger===37 ? -1 : 1)
1821					];
1822					_stop(el);
1823					if(_isNumeric(trigger) && seq.type==="stepped"){return;}
1824					_on(once);
1825					break;
1826				case "off":
1827					_off();
1828					if(once || (d.tweenRunning && seq.dir)){
1829						_on(true);
1830					}
1831					break;
1832			}
1833
1834			/* starts sequence */
1835			function _on(once){
1836				if(o.snapAmount){seq.scrollAmount=!(o.snapAmount instanceof Array) ? o.snapAmount : seq.dir[0]==="x" ? o.snapAmount[1] : o.snapAmount[0];} /* scrolling snapping */
1837				var c=seq.type!=="stepped", /* continuous scrolling */
1838					t=s ? s : !once ? 1000/60 : c ? steplessSpeed/1.5 : steppedSpeed, /* timer */
1839					m=!once ? 2.5 : c ? 7.5 : 40, /* multiplier */
1840					contentPos=[Math.abs(mCSB_container[0].offsetTop),Math.abs(mCSB_container[0].offsetLeft)],
1841					ratio=[d.scrollRatio.y>10 ? 10 : d.scrollRatio.y,d.scrollRatio.x>10 ? 10 : d.scrollRatio.x],
1842					amount=seq.dir[0]==="x" ? contentPos[1]+(seq.dir[1]*(ratio[1]*m)) : contentPos[0]+(seq.dir[1]*(ratio[0]*m)),
1843					px=seq.dir[0]==="x" ? contentPos[1]+(seq.dir[1]*parseInt(seq.scrollAmount)) : contentPos[0]+(seq.dir[1]*parseInt(seq.scrollAmount)),
1844					to=seq.scrollAmount!=="auto" ? px : amount,
1845					easing=e ? e : !once ? "mcsLinear" : c ? "mcsLinearOut" : "mcsEaseInOut",
1846					onComplete=!once ? false : true;
1847				if(once && t<17){
1848					to=seq.dir[0]==="x" ? contentPos[1] : contentPos[0];
1849				}
1850				_scrollTo(el,to.toString(),{dir:seq.dir[0],scrollEasing:easing,dur:t,onComplete:onComplete});
1851				if(once){
1852					seq.dir=false;
1853					return;
1854				}
1855				clearTimeout(seq.step);
1856				seq.step=setTimeout(function(){
1857					_on();
1858				},t);
1859			}
1860			/* stops sequence */
1861			function _off(){
1862				clearTimeout(seq.step);
1863				_delete(seq,"step");
1864				_stop(el);
1865			}
1866		},
1867		/* -------------------- */
1868
1869
1870		/* returns a yx array from value */
1871		_arr=function(val){
1872			var o=$(this).data(pluginPfx).opt,vals=[];
1873			if(typeof val==="function"){val=val();} /* check if the value is a single anonymous function */
1874			/* check if value is object or array, its length and create an array with yx values */
1875			if(!(val instanceof Array)){ /* object value (e.g. {y:"100",x:"100"}, 100 etc.) */
1876				vals[0]=val.y ? val.y : val.x || o.axis==="x" ? null : val;
1877				vals[1]=val.x ? val.x : val.y || o.axis==="y" ? null : val;
1878			}else{ /* array value (e.g. [100,100]) */
1879				vals=val.length>1 ? [val[0],val[1]] : o.axis==="x" ? [null,val[0]] : [val[0],null];
1880			}
1881			/* check if array values are anonymous functions */
1882			if(typeof vals[0]==="function"){vals[0]=vals[0]();}
1883			if(typeof vals[1]==="function"){vals[1]=vals[1]();}
1884			return vals;
1885		},
1886		/* -------------------- */
1887
1888
1889		/* translates values (e.g. "top", 100, "100px", "#id") to actual scroll-to positions */
1890		_to=function(val,dir){
1891			if(val==null || typeof val=="undefined"){return;}
1892			var $this=$(this),d=$this.data(pluginPfx),o=d.opt,
1893				mCSB_container=$("#mCSB_"+d.idx+"_container"),
1894				wrapper=mCSB_container.parent(),
1895				t=typeof val;
1896			if(!dir){dir=o.axis==="x" ? "x" : "y";}
1897			var contentLength=dir==="x" ? mCSB_container.outerWidth(false)-wrapper.width() : mCSB_container.outerHeight(false)-wrapper.height(),
1898				contentPos=dir==="x" ? mCSB_container[0].offsetLeft : mCSB_container[0].offsetTop,
1899				cssProp=dir==="x" ? "left" : "top";
1900			switch(t){
1901				case "function": /* this currently is not used. Consider removing it */
1902					return val();
1903					break;
1904				case "object": /* js/jquery object */
1905					var obj=val.jquery ? val : $(val);
1906					if(!obj.length){return;}
1907					return dir==="x" ? _childPos(obj)[1] : _childPos(obj)[0];
1908					break;
1909				case "string": case "number":
1910					if(_isNumeric(val)){ /* numeric value */
1911						return Math.abs(val);
1912					}else if(val.indexOf("%")!==-1){ /* percentage value */
1913						return Math.abs(contentLength*parseInt(val)/100);
1914					}else if(val.indexOf("-=")!==-1){ /* decrease value */
1915						return Math.abs(contentPos-parseInt(val.split("-=")[1]));
1916					}else if(val.indexOf("+=")!==-1){ /* inrease value */
1917						var p=(contentPos+parseInt(val.split("+=")[1]));
1918						return p>=0 ? 0 : Math.abs(p);
1919					}else if(val.indexOf("px")!==-1 && _isNumeric(val.split("px")[0])){ /* pixels string value (e.g. "100px") */
1920						return Math.abs(val.split("px")[0]);
1921					}else{
1922						if(val==="top" || val==="left"){ /* special strings */
1923							return 0;
1924						}else if(val==="bottom"){
1925							return Math.abs(wrapper.height()-mCSB_container.outerHeight(false));
1926						}else if(val==="right"){
1927							return Math.abs(wrapper.width()-mCSB_container.outerWidth(false));
1928						}else if(val==="first" || val==="last"){
1929							var obj=mCSB_container.find(":"+val);
1930							return dir==="x" ? _childPos(obj)[1] : _childPos(obj)[0];
1931						}else{
1932							if($(val).length){ /* jquery selector */
1933								return dir==="x" ? _childPos($(val))[1] : _childPos($(val))[0];
1934							}else{ /* other values (e.g. "100em") */
1935								mCSB_container.css(cssProp,val);
1936								methods.update.call(null,$this[0]);
1937								return;
1938							}
1939						}
1940					}
1941					break;
1942			}
1943		},
1944		/* -------------------- */
1945
1946
1947		/* calls the update method automatically */
1948		_autoUpdate=function(rem){
1949			var $this=$(this),d=$this.data(pluginPfx),o=d.opt,
1950				mCSB_container=$("#mCSB_"+d.idx+"_container");
1951			if(rem){
1952				/*
1953				removes autoUpdate timer
1954				usage: _autoUpdate.call(this,"remove");
1955				*/
1956				clearTimeout(mCSB_container[0].autoUpdate);
1957				_delete(mCSB_container[0],"autoUpdate");
1958				return;
1959			}
1960			upd();
1961			function upd(){
1962				clearTimeout(mCSB_container[0].autoUpdate);
1963				if($this.parents("html").length===0){
1964					/* check element in dom tree */
1965					$this=null;
1966					return;
1967				}
1968				mCSB_container[0].autoUpdate=setTimeout(function(){
1969					/* update on specific selector(s) length and size change */
1970					if(o.advanced.updateOnSelectorChange){
1971						d.poll.change.n=sizesSum();
1972						if(d.poll.change.n!==d.poll.change.o){
1973							d.poll.change.o=d.poll.change.n;
1974							doUpd(3);
1975							return;
1976						}
1977					}
1978					/* update on main element and scrollbar size changes */
1979					if(o.advanced.updateOnContentResize){
1980						d.poll.size.n=$this[0].scrollHeight+$this[0].scrollWidth+mCSB_container[0].offsetHeight+$this[0].offsetHeight+$this[0].offsetWidth;
1981						if(d.poll.size.n!==d.poll.size.o){
1982							d.poll.size.o=d.poll.size.n;
1983							doUpd(1);
1984							return;
1985						}
1986					}
1987					/* update on image load */
1988					if(o.advanced.updateOnImageLoad){
1989						if(!(o.advanced.updateOnImageLoad==="auto" && o.axis==="y")){ //by default, it doesn't run on vertical content
1990							d.poll.img.n=mCSB_container.find("img").length;
1991							if(d.poll.img.n!==d.poll.img.o){
1992								d.poll.img.o=d.poll.img.n;
1993								mCSB_container.find("img").each(function(){
1994									imgLoader(this);
1995								});
1996								return;
1997							}
1998						}
1999					}
2000					if(o.advanced.updateOnSelectorChange || o.advanced.updateOnContentResize || o.advanced.updateOnImageLoad){upd();}
2001				},o.advanced.autoUpdateTimeout);
2002			}
2003			/* a tiny image loader */
2004			function imgLoader(el){
2005				if($(el).hasClass(classes[2])){doUpd(); return;}
2006				var img=new Image();
2007				function createDelegate(contextObject,delegateMethod){
2008					return function(){return delegateMethod.apply(contextObject,arguments);}
2009				}
2010				function imgOnLoad(){
2011					this.onload=null;
2012					$(el).addClass(classes[2]);
2013					doUpd(2);
2014				}
2015				img.onload=createDelegate(img,imgOnLoad);
2016				img.src=el.src;
2017			}
2018			/* returns the total height and width sum of all elements matching the selector */
2019			function sizesSum(){
2020				if(o.advanced.updateOnSelectorChange===true){o.advanced.updateOnSelectorChange="*";}
2021				var total=0,sel=mCSB_container.find(o.advanced.updateOnSelectorChange);
2022				if(o.advanced.updateOnSelectorChange && sel.length>0){sel.each(function(){total+=this.offsetHeight+this.offsetWidth;});}
2023				return total;
2024			}
2025			/* calls the update method */
2026			function doUpd(cb){
2027				clearTimeout(mCSB_container[0].autoUpdate);
2028				methods.update.call(null,$this[0],cb);
2029			}
2030		},
2031		/* -------------------- */
2032
2033
2034		/* snaps scrolling to a multiple of a pixels number */
2035		_snapAmount=function(to,amount,offset){
2036			return (Math.round(to/amount)*amount-offset);
2037		},
2038		/* -------------------- */
2039
2040
2041		/* stops content and scrollbar animations */
2042		_stop=function(el){
2043			var d=el.data(pluginPfx),
2044				sel=$("#mCSB_"+d.idx+"_container,#mCSB_"+d.idx+"_container_wrapper,#mCSB_"+d.idx+"_dragger_vertical,#mCSB_"+d.idx+"_dragger_horizontal");
2045			sel.each(function(){
2046				_stopTween.call(this);
2047			});
2048		},
2049		/* -------------------- */
2050
2051
2052		/*
2053		ANIMATES CONTENT
2054		This is where the actual scrolling happens
2055		*/
2056		_scrollTo=function(el,to,options){
2057			var d=el.data(pluginPfx),o=d.opt,
2058				defaults={
2059					trigger:"internal",
2060					dir:"y",
2061					scrollEasing:"mcsEaseOut",
2062					drag:false,
2063					dur:o.scrollInertia,
2064					overwrite:"all",
2065					callbacks:true,
2066					onStart:true,
2067					onUpdate:true,
2068					onComplete:true
2069				},
2070				options=$.extend(defaults,options),
2071				dur=[options.dur,(options.drag ? 0 : options.dur)],
2072				mCustomScrollBox=$("#mCSB_"+d.idx),
2073				mCSB_container=$("#mCSB_"+d.idx+"_container"),
2074				wrapper=mCSB_container.parent(),
2075				totalScrollOffsets=o.callbacks.onTotalScrollOffset ? _arr.call(el,o.callbacks.onTotalScrollOffset) : [0,0],
2076				totalScrollBackOffsets=o.callbacks.onTotalScrollBackOffset ? _arr.call(el,o.callbacks.onTotalScrollBackOffset) : [0,0];
2077			d.trigger=options.trigger;
2078			if(wrapper.scrollTop()!==0 || wrapper.scrollLeft()!==0){ /* always reset scrollTop/Left */
2079				$(".mCSB_"+d.idx+"_scrollbar").css("visibility","visible");
2080				wrapper.scrollTop(0).scrollLeft(0);
2081			}
2082			if(to==="_resetY" && !d.contentReset.y){
2083				/* callbacks: onOverflowYNone */
2084				if(_cb("onOverflowYNone")){o.callbacks.onOverflowYNone.call(el[0]);}
2085				d.contentReset.y=1;
2086			}
2087			if(to==="_resetX" && !d.contentReset.x){
2088				/* callbacks: onOverflowXNone */
2089				if(_cb("onOverflowXNone")){o.callbacks.onOverflowXNone.call(el[0]);}
2090				d.contentReset.x=1;
2091			}
2092			if(to==="_resetY" || to==="_resetX"){return;}
2093			if((d.contentReset.y || !el[0].mcs) && d.overflowed[0]){
2094				/* callbacks: onOverflowY */
2095				if(_cb("onOverflowY")){o.callbacks.onOverflowY.call(el[0]);}
2096				d.contentReset.x=null;
2097			}
2098			if((d.contentReset.x || !el[0].mcs) && d.overflowed[1]){
2099				/* callbacks: onOverflowX */
2100				if(_cb("onOverflowX")){o.callbacks.onOverflowX.call(el[0]);}
2101				d.contentReset.x=null;
2102			}
2103			if(o.snapAmount){ /* scrolling snapping */
2104				var snapAmount=!(o.snapAmount instanceof Array) ? o.snapAmount : options.dir==="x" ? o.snapAmount[1] : o.snapAmount[0];
2105				to=_snapAmount(to,snapAmount,o.snapOffset);
2106			}
2107			switch(options.dir){
2108				case "x":
2109					var mCSB_dragger=$("#mCSB_"+d.idx+"_dragger_horizontal"),
2110						property="left",
2111						contentPos=mCSB_container[0].offsetLeft,
2112						limit=[
2113							mCustomScrollBox.width()-mCSB_container.outerWidth(false),
2114							mCSB_dragger.parent().width()-mCSB_dragger.width()
2115						],
2116						scrollTo=[to,to===0 ? 0 : (to/d.scrollRatio.x)],
2117						tso=totalScrollOffsets[1],
2118						tsbo=totalScrollBackOffsets[1],
2119						totalScrollOffset=tso>0 ? tso/d.scrollRatio.x : 0,
2120						totalScrollBackOffset=tsbo>0 ? tsbo/d.scrollRatio.x : 0;
2121					break;
2122				case "y":
2123					var mCSB_dragger=$("#mCSB_"+d.idx+"_dragger_vertical"),
2124						property="top",
2125						contentPos=mCSB_container[0].offsetTop,
2126						limit=[
2127							mCustomScrollBox.height()-mCSB_container.outerHeight(false),
2128							mCSB_dragger.parent().height()-mCSB_dragger.height()
2129						],
2130						scrollTo=[to,to===0 ? 0 : (to/d.scrollRatio.y)],
2131						tso=totalScrollOffsets[0],
2132						tsbo=totalScrollBackOffsets[0],
2133						totalScrollOffset=tso>0 ? tso/d.scrollRatio.y : 0,
2134						totalScrollBackOffset=tsbo>0 ? tsbo/d.scrollRatio.y : 0;
2135					break;
2136			}
2137			if(scrollTo[1]<0 || (scrollTo[0]===0 && scrollTo[1]===0)){
2138				scrollTo=[0,0];
2139			}else if(scrollTo[1]>=limit[1]){
2140				scrollTo=[limit[0],limit[1]];
2141			}else{
2142				scrollTo[0]=-scrollTo[0];
2143			}
2144			if(!el[0].mcs){
2145				_mcs();  /* init mcs object (once) to make it available before callbacks */
2146				if(_cb("onInit")){o.callbacks.onInit.call(el[0]);} /* callbacks: onInit */
2147			}
2148			clearTimeout(mCSB_container[0].onCompleteTimeout);
2149			_tweenTo(mCSB_dragger[0],property,Math.round(scrollTo[1]),dur[1],options.scrollEasing);
2150			if(!d.tweenRunning && ((contentPos===0 && scrollTo[0]>=0) || (contentPos===limit[0] && scrollTo[0]<=limit[0]))){return;}
2151			_tweenTo(mCSB_container[0],property,Math.round(scrollTo[0]),dur[0],options.scrollEasing,options.overwrite,{
2152				onStart:function(){
2153					if(options.callbacks && options.onStart && !d.tweenRunning){
2154						/* callbacks: onScrollStart */
2155						if(_cb("onScrollStart")){_mcs(); o.callbacks.onScrollStart.call(el[0]);}
2156						d.tweenRunning=true;
2157						_onDragClasses(mCSB_dragger);
2158						d.cbOffsets=_cbOffsets();
2159					}
2160				},onUpdate:function(){
2161					if(options.callbacks && options.onUpdate){
2162						/* callbacks: whileScrolling */
2163						if(_cb("whileScrolling")){_mcs(); o.callbacks.whileScrolling.call(el[0]);}
2164					}
2165				},onComplete:function(){
2166					if(options.callbacks && options.onComplete){
2167						if(o.axis==="yx"){clearTimeout(mCSB_container[0].onCompleteTimeout);}
2168						var t=mCSB_container[0].idleTimer || 0;
2169						mCSB_container[0].onCompleteTimeout=setTimeout(function(){
2170							/* callbacks: onScroll, onTotalScroll, onTotalScrollBack */
2171							if(_cb("onScroll")){_mcs(); o.callbacks.onScroll.call(el[0]);}
2172							if(_cb("onTotalScroll") && scrollTo[1]>=limit[1]-totalScrollOffset && d.cbOffsets[0]){_mcs(); o.callbacks.onTotalScroll.call(el[0]);}
2173							if(_cb("onTotalScrollBack") && scrollTo[1]<=totalScrollBackOffset && d.cbOffsets[1]){_mcs(); o.callbacks.onTotalScrollBack.call(el[0]);}
2174							d.tweenRunning=false;
2175							mCSB_container[0].idleTimer=0;
2176							_onDragClasses(mCSB_dragger,"hide");
2177						},t);
2178					}
2179				}
2180			});
2181			/* checks if callback function exists */
2182			function _cb(cb){
2183				return d && o.callbacks[cb] && typeof o.callbacks[cb]==="function";
2184			}
2185			/* checks whether callback offsets always trigger */
2186			function _cbOffsets(){
2187				return [o.callbacks.alwaysTriggerOffsets || contentPos>=limit[0]+tso,o.callbacks.alwaysTriggerOffsets || contentPos<=-tsbo];
2188			}
2189			/*
2190			populates object with useful values for the user
2191			values:
2192				content: this.mcs.content
2193				content top position: this.mcs.top
2194				content left position: this.mcs.left
2195				dragger top position: this.mcs.draggerTop
2196				dragger left position: this.mcs.draggerLeft
2197				scrolling y percentage: this.mcs.topPct
2198				scrolling x percentage: this.mcs.leftPct
2199				scrolling direction: this.mcs.direction
2200			*/
2201			function _mcs(){
2202				var cp=[mCSB_container[0].offsetTop,mCSB_container[0].offsetLeft], /* content position */
2203					dp=[mCSB_dragger[0].offsetTop,mCSB_dragger[0].offsetLeft], /* dragger position */
2204					cl=[mCSB_container.outerHeight(false),mCSB_container.outerWidth(false)], /* content length */
2205					pl=[mCustomScrollBox.height(),mCustomScrollBox.width()]; /* content parent length */
2206				el[0].mcs={
2207					content:mCSB_container, /* original content wrapper as jquery object */
2208					top:cp[0],left:cp[1],draggerTop:dp[0],draggerLeft:dp[1],
2209					topPct:Math.round((100*Math.abs(cp[0]))/(Math.abs(cl[0])-pl[0])),leftPct:Math.round((100*Math.abs(cp[1]))/(Math.abs(cl[1])-pl[1])),
2210					direction:options.dir
2211				};
2212				/*
2213				this refers to the original element containing the scrollbar(s)
2214				usage: this.mcs.top, this.mcs.leftPct etc.
2215				*/
2216			}
2217		},
2218		/* -------------------- */
2219
2220
2221		/*
2222		CUSTOM JAVASCRIPT ANIMATION TWEEN
2223		Lighter and faster than jquery animate() and css transitions
2224		Animates top/left properties and includes easings
2225		*/
2226		_tweenTo=function(el,prop,to,duration,easing,overwrite,callbacks){
2227			if(!el._mTween){el._mTween={top:{},left:{}};}
2228			var callbacks=callbacks || {},
2229				onStart=callbacks.onStart || function(){},onUpdate=callbacks.onUpdate || function(){},onComplete=callbacks.onComplete || function(){},
2230				startTime=_getTime(),_delay,progress=0,from=el.offsetTop,elStyle=el.style,_request,tobj=el._mTween[prop];
2231			if(prop==="left"){from=el.offsetLeft;}
2232			var diff=to-from;
2233			tobj.stop=0;
2234			if(overwrite!=="none"){_cancelTween();}
2235			_startTween();
2236			function _step(){
2237				if(tobj.stop){return;}
2238				if(!progress){onStart.call();}
2239				progress=_getTime()-startTime;
2240				_tween();
2241				if(progress>=tobj.time){
2242					tobj.time=(progress>tobj.time) ? progress+_delay-(progress-tobj.time) : progress+_delay-1;
2243					if(tobj.time<progress+1){tobj.time=progress+1;}
2244				}
2245				if(tobj.time<duration){tobj.id=_request(_step);}else{onComplete.call();}
2246			}
2247			function _tween(){
2248				if(duration>0){
2249					tobj.currVal=_ease(tobj.time,from,diff,duration,easing);
2250					elStyle[prop]=Math.round(tobj.currVal)+"px";
2251				}else{
2252					elStyle[prop]=to+"px";
2253				}
2254				onUpdate.call();
2255			}
2256			function _startTween(){
2257				_delay=1000/60;
2258				tobj.time=progress+_delay;
2259				_request=(!window.requestAnimationFrame) ? function(f){_tween(); return setTimeout(f,0.01);} : window.requestAnimationFrame;
2260				tobj.id=_request(_step);
2261			}
2262			function _cancelTween(){
2263				if(tobj.id==null){return;}
2264				if(!window.requestAnimationFrame){clearTimeout(tobj.id);
2265				}else{window.cancelAnimationFrame(tobj.id);}
2266				tobj.id=null;
2267			}
2268			function _ease(t,b,c,d,type){
2269				switch(type){
2270					case "linear": case "mcsLinear":
2271						return c*t/d + b;
2272						break;
2273					case "mcsLinearOut":
2274						t/=d; t--; return c * Math.sqrt(1 - t*t) + b;
2275						break;
2276					case "easeInOutSmooth":
2277						t/=d/2;
2278						if(t<1) return c/2*t*t + b;
2279						t--;
2280						return -c/2 * (t*(t-2) - 1) + b;
2281						break;
2282					case "easeInOutStrong":
2283						t/=d/2;
2284						if(t<1) return c/2 * Math.pow( 2, 10 * (t - 1) ) + b;
2285						t--;
2286						return c/2 * ( -Math.pow( 2, -10 * t) + 2 ) + b;
2287						break;
2288					case "easeInOut": case "mcsEaseInOut":
2289						t/=d/2;
2290						if(t<1) return c/2*t*t*t + b;
2291						t-=2;
2292						return c/2*(t*t*t + 2) + b;
2293						break;
2294					case "easeOutSmooth":
2295						t/=d; t--;
2296						return -c * (t*t*t*t - 1) + b;
2297						break;
2298					case "easeOutStrong":
2299						return c * ( -Math.pow( 2, -10 * t/d ) + 1 ) + b;
2300						break;
2301					case "easeOut": case "mcsEaseOut": default:
2302						var ts=(t/=d)*t,tc=ts*t;
2303						return b+c*(0.499999999999997*tc*ts + -2.5*ts*ts + 5.5*tc + -6.5*ts + 4*t);
2304				}
2305			}
2306		},
2307		/* -------------------- */
2308
2309
2310		/* returns current time */
2311		_getTime=function(){
2312			if(window.performance && window.performance.now){
2313				return window.performance.now();
2314			}else{
2315				if(window.performance && window.performance.webkitNow){
2316					return window.performance.webkitNow();
2317				}else{
2318					if(Date.now){return Date.now();}else{return new Date().getTime();}
2319				}
2320			}
2321		},
2322		/* -------------------- */
2323
2324
2325		/* stops a tween */
2326		_stopTween=function(){
2327			var el=this;
2328			if(!el._mTween){el._mTween={top:{},left:{}};}
2329			var props=["top","left"];
2330			for(var i=0; i<props.length; i++){
2331				var prop=props[i];
2332				if(el._mTween[prop].id){
2333					if(!window.requestAnimationFrame){clearTimeout(el._mTween[prop].id);
2334					}else{window.cancelAnimationFrame(el._mTween[prop].id);}
2335					el._mTween[prop].id=null;
2336					el._mTween[prop].stop=1;
2337				}
2338			}
2339		},
2340		/* -------------------- */
2341
2342
2343		/* deletes a property (avoiding the exception thrown by IE) */
2344		_delete=function(c,m){
2345			try{delete c[m];}catch(e){c[m]=null;}
2346		},
2347		/* -------------------- */
2348
2349
2350		/* detects left mouse button */
2351		_mouseBtnLeft=function(e){
2352			return !(e.which && e.which!==1);
2353		},
2354		/* -------------------- */
2355
2356
2357		/* detects if pointer type event is touch */
2358		_pointerTouch=function(e){
2359			var t=e.originalEvent.pointerType;
2360			return !(t && t!=="touch" && t!==2);
2361		},
2362		/* -------------------- */
2363
2364
2365		/* checks if value is numeric */
2366		_isNumeric=function(val){
2367			return !isNaN(parseFloat(val)) && isFinite(val);
2368		},
2369		/* -------------------- */
2370
2371
2372		/* returns element position according to content */
2373		_childPos=function(el){
2374			var p=el.parents(".mCSB_container");
2375			return [el.offset().top-p.offset().top,el.offset().left-p.offset().left];
2376		},
2377		/* -------------------- */
2378
2379
2380		/* checks if browser tab is hidden/inactive via Page Visibility API */
2381		_isTabHidden=function(){
2382			var prop=_getHiddenProp();
2383			if(!prop) return false;
2384			return document[prop];
2385			function _getHiddenProp(){
2386				var pfx=["webkit","moz","ms","o"];
2387				if("hidden" in document) return "hidden"; //natively supported
2388				for(var i=0; i<pfx.length; i++){ //prefixed
2389				    if((pfx[i]+"Hidden") in document)
2390				        return pfx[i]+"Hidden";
2391				}
2392				return null; //not supported
2393			}
2394		};
2395		/* -------------------- */
2396
2397
2398
2399
2400
2401	/*
2402	----------------------------------------
2403	PLUGIN SETUP
2404	----------------------------------------
2405	*/
2406
2407	/* plugin constructor functions */
2408	$.fn[pluginNS]=function(method){ /* usage: $(selector).mCustomScrollbar(); */
2409		if(methods[method]){
2410			return methods[method].apply(this,Array.prototype.slice.call(arguments,1));
2411		}else if(typeof method==="object" || !method){
2412			return methods.init.apply(this,arguments);
2413		}else{
2414			$.error("Method "+method+" does not exist");
2415		}
2416	};
2417	$[pluginNS]=function(method){ /* usage: $.mCustomScrollbar(); */
2418		if(methods[method]){
2419			return methods[method].apply(this,Array.prototype.slice.call(arguments,1));
2420		}else if(typeof method==="object" || !method){
2421			return methods.init.apply(this,arguments);
2422		}else{
2423			$.error("Method "+method+" does not exist");
2424		}
2425	};
2426
2427	/*
2428	allow setting plugin default options.
2429	usage: $.mCustomScrollbar.defaults.scrollInertia=500;
2430	to apply any changed default options on default selectors (below), use inside document ready fn
2431	e.g.: $(document).ready(function(){ $.mCustomScrollbar.defaults.scrollInertia=500; });
2432	*/
2433	$[pluginNS].defaults=defaults;
2434
2435	/*
2436	add window object (window.mCustomScrollbar)
2437	usage: if(window.mCustomScrollbar){console.log("custom scrollbar plugin loaded");}
2438	*/
2439	window[pluginNS]=true;
2440
2441	$(window).bind("load",function(){
2442
2443		$(defaultSelector)[pluginNS](); /* add scrollbars automatically on default selector */
2444
2445		/* extend jQuery expressions */
2446		$.extend($.expr[":"],{
2447			/* checks if element is within scrollable viewport */
2448			mcsInView:$.expr[":"].mcsInView || function(el){
2449				var $el=$(el),content=$el.parents(".mCSB_container"),wrapper,cPos;
2450				if(!content.length){return;}
2451				wrapper=content.parent();
2452				cPos=[content[0].offsetTop,content[0].offsetLeft];
2453				return 	cPos[0]+_childPos($el)[0]>=0 && cPos[0]+_childPos($el)[0]<wrapper.height()-$el.outerHeight(false) &&
2454						cPos[1]+_childPos($el)[1]>=0 && cPos[1]+_childPos($el)[1]<wrapper.width()-$el.outerWidth(false);
2455			},
2456			/* checks if element or part of element is in view of scrollable viewport */
2457			mcsInSight:$.expr[":"].mcsInSight || function(el,i,m){
2458				var $el=$(el),elD,content=$el.parents(".mCSB_container"),wrapperView,pos,wrapperViewPct,
2459					pctVals=m[3]==="exact" ? [[1,0],[1,0]] : [[0.9,0.1],[0.6,0.4]];
2460				if(!content.length){return;}
2461				elD=[$el.outerHeight(false),$el.outerWidth(false)];
2462				pos=[content[0].offsetTop+_childPos($el)[0],content[0].offsetLeft+_childPos($el)[1]];
2463				wrapperView=[content.parent()[0].offsetHeight,content.parent()[0].offsetWidth];
2464				wrapperViewPct=[elD[0]<wrapperView[0] ? pctVals[0] : pctVals[1],elD[1]<wrapperView[1] ? pctVals[0] : pctVals[1]];
2465				return 	pos[0]-(wrapperView[0]*wrapperViewPct[0][0])<0 && pos[0]+elD[0]-(wrapperView[0]*wrapperViewPct[0][1])>=0 &&
2466						pos[1]-(wrapperView[1]*wrapperViewPct[1][0])<0 && pos[1]+elD[1]-(wrapperView[1]*wrapperViewPct[1][1])>=0;
2467			},
2468			/* checks if element is overflowed having visible scrollbar(s) */
2469			mcsOverflow:$.expr[":"].mcsOverflow || function(el){
2470				var d=$(el).data(pluginPfx);
2471				if(!d){return;}
2472				return d.overflowed[0] || d.overflowed[1];
2473			}
2474		});
2475
2476	});
2477
2478}))}));

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.