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