PageSourceSearch

https://www.olivenholz.de/modules/leofeature/views/js/jquery.mCustomScrollbar.js

js olivenholz.de collected 2026-10-10 02:04:29 UTC 93,290 bytes, 2,472 lines download raw bytes

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

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.