PageSourceSearch

https://mastersnakou.fr/assets/jquery.mCustomScrollbar.js

js mastersnakou.fr collected 2026-10-02 01:01:47 UTC 88,482 bytes, 2,368 lines download raw bytes

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

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.