PageSourceSearch

https://ntsk.ru/js/scrollbar/jquery.mCustomScrollbar.js

js ntsk.ru collected 2026-09-29 15:09:40 UTC 84,304 bytes, 2,169 lines download raw bytes

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

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.