vendor: 15,032 bytes, lines 1-469
1/* 2== malihu jquery custom scrollbar plugin == 3Version: 3.1.5 4Plugin URI: https://manos.malihu.gr/jquery-custom-content-scroller 5Author: malihu 6Author URI: https://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,658 bytes, lines 495-2458
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 if(o.axis!=="x"){ 1122 if(d.overflowed[0] && !disabled){ 1123 scrollbar[0].add(mCSB_dragger[0]).add(scrollbar[0].children("a")).css("display","block"); 1124 content.removeClass(classes[8]+" "+classes[10]); 1125 }else{ 1126 if(o.alwaysShowScrollbar){ 1127 if(o.alwaysShowScrollbar!==2){mCSB_dragger[0].css("display","none");} 1128 content.removeClass(classes[10]); 1129 }else{ 1130 scrollbar[0].css("display","none"); 1131 content.addClass(classes[10]); 1132 } 1133 content.addClass(classes[8]); 1134 } 1135 } 1136 if(o.axis!=="y"){ 1137 if(d.overflowed[1] && !disabled){ 1138 scrollbar[1].add(mCSB_dragger[1]).add(scrollbar[1].children("a")).css("display","block"); 1139 content.removeClass(classes[9]+" "+classes[11]); 1140 }else{ 1141 if(o.alwaysShowScrollbar){ 1142 if(o.alwaysShowScrollbar!==2){mCSB_dragger[1].css("display","none");} 1143 content.removeClass(classes[11]); 1144 }else{ 1145 scrollbar[1].css("display","none"); 1146 content.addClass(classes[11]); 1147 } 1148 content.addClass(classes[9]); 1149 } 1150 } 1151 if(!d.overflowed[0] && !d.overflowed[1]){ 1152 $this.addClass(classes[5]); 1153 }else{ 1154 $this.removeClass(classes[5]); 1155 } 1156 }, 1157 /* -------------------- */ 1158 1159 1160 /* returns input coordinates of pointer, touch and mouse events (relative to document) */ 1161 _coordinates=function(e){ 1162 var t=e.type,o=e.target.ownerDocument!==document && frameElement!==null ? [$(frameElement).offset().top,$(frameElement).offset().left] : null, 1163 io=_canAccessIFrame() && e.target.ownerDocument!==top.document && frameElement!==null ? [$(e.view.frameElement).offset().top,$(e.view.frameElement).offset().left] : [0,0]; 1164 switch(t){ 1165 case "pointerdown": case "MSPointerDown": case "pointermove": case "MSPointerMove": case "pointerup": case "MSPointerUp": 1166 return o ? [e.originalEvent.pageY-o[0]+io[0],e.originalEvent.pageX-o[1]+io[1],false] : [e.originalEvent.pageY,e.originalEvent.pageX,false]; 1167 break; 1168 case "touchstart": case "touchmove": case "touchend": 1169 var touch=e.originalEvent.touches[0] || e.originalEvent.changedTouches[0], 1170 touches=e.originalEvent.touches.length || e.originalEvent.changedTouches.length; 1171 return e.target.ownerDocument!==document ? [touch.screenY,touch.screenX,touches>1] : [touch.pageY,touch.pageX,touches>1]; 1172 break; 1173 default: 1174 return o ? [e.pageY-o[0]+io[0],e.pageX-o[1]+io[1],false] : [e.pageY,e.pageX,false]; 1175 } 1176 }, 1177 /* -------------------- */ 1178 1179 1180 /* 1181 SCROLLBAR DRAG EVENTS 1182 scrolls content via scrollbar dragging 1183 */ 1184 _draggable=function(){ 1185 var $this=$(this),d=$this.data(pluginPfx),o=d.opt, 1186 namespace=pluginPfx+"_"+d.idx, 1187 draggerId=["mCSB_"+d.idx+"_dragger_vertical","mCSB_"+d.idx+"_dragger_horizontal"], 1188 mCSB_container=$("#mCSB_"+d.idx+"_container"), 1189 mCSB_dragger=$("#"+draggerId[0]+",#"+draggerId[1]), 1190 draggable,dragY,dragX, 1191 rds=o.advanced.releaseDraggableSelectors ? mCSB_dragger.add($(o.advanced.releaseDraggableSelectors)) : mCSB_dragger, 1192 eds=o.advanced.extraDraggableSelectors ? $(!_canAccessIFrame() || top.document).add($(o.advanced.extraDraggableSelectors)) : $(!_canAccessIFrame() || top.document); 1193 mCSB_dragger.bind("contextmenu."+namespace,function(e){ 1194 e.preventDefault(); //prevent right click 1195 }).bind("mousedown."+namespace+" touchstart."+namespace+" pointerdown."+namespace+" MSPointerDown."+namespace,function(e){ 1196 e.stopImmediatePropagation(); 1197 e.preventDefault(); 1198 if(!_mouseBtnLeft(e)){return;} /* left mouse button only */ 1199 touchActive=true; 1200 if(oldIE){document.onselectstart=function(){return false;}} /* disable text selection for IE < 9 */ 1201 _iframe.call(mCSB_container,false); /* enable scrollbar dragging over iframes by disabling their events */ 1202 _stop($this); 1203 draggable=$(this); 1204 var offset=draggable.offset(),y=_coordinates(e)[0]-offset.top,x=_coordinates(e)[1]-offset.left, 1205 h=draggable.height()+offset.top,w=draggable.width()+offset.left; 1206 if(y<h && y>0 && x<w && x>0){ 1207 dragY=y; 1208 dragX=x; 1209 } 1210 _onDragClasses(draggable,"active",o.autoExpandScrollbar); 1211 }).bind("touchmove."+namespace,function(e){ 1212 e.stopImmediatePropagation(); 1213 e.preventDefault(); 1214 var offset=draggable.offset(),y=_coordinates(e)[0]-offset.top,x=_coordinates(e)[1]-offset.left; 1215 _drag(dragY,dragX,y,x); 1216 }); 1217 $(document).add(eds).bind("mousemove."+namespace+" pointermove."+namespace+" MSPointerMove."+namespace,function(e){ 1218 if(draggable){ 1219 var offset=draggable.offset(),y=_coordinates(e)[0]-offset.top,x=_coordinates(e)[1]-offset.left; 1220 if(dragY===y && dragX===x){return;} /* has it really moved? */ 1221 _drag(dragY,dragX,y,x); 1222 } 1223 }).add(rds).bind("mouseup."+namespace+" touchend."+namespace+" pointerup."+namespace+" MSPointerUp."+namespace,function(e){ 1224 if(draggable){ 1225 _onDragClasses(draggable,"active",o.autoExpandScrollbar); 1226 draggable=null; 1227 } 1228 touchActive=false; 1229 if(oldIE){document.onselectstart=null;} /* enable text selection for IE < 9 */ 1230 _iframe.call(mCSB_container,true); /* enable iframes events */ 1231 }); 1232 function _drag(dragY,dragX,y,x){ 1233 mCSB_container[0].idleTimer=o.scrollInertia<233 ? 250 : 0; 1234 if(draggable.attr("id")===draggerId[1]){ 1235 var dir="x",to=((draggable[0].offsetLeft-dragX)+x)*d.scrollRatio.x; 1236 }else{ 1237 var dir="y",to=((draggable[0].offsetTop-dragY)+y)*d.scrollRatio.y; 1238 } 1239 _scrollTo($this,to.toString(),{dir:dir,drag:true}); 1240 } 1241 }, 1242 /* -------------------- */ 1243 1244 1245 /* 1246 TOUCH SWIPE EVENTS 1247 scrolls content via touch swipe 1248 Emulates the native touch-swipe scrolling with momentum found in iOS, Android and WP devices 1249 */ 1250 _contentDraggable=function(){ 1251 var $this=$(this),d=$this.data(pluginPfx),o=d.opt, 1252 namespace=pluginPfx+"_"+d.idx, 1253 mCustomScrollBox=$("#mCSB_"+d.idx), 1254 mCSB_container=$("#mCSB_"+d.idx+"_container"), 1255 mCSB_dragger=[$("#mCSB_"+d.idx+"_dragger_vertical"),$("#mCSB_"+d.idx+"_dragger_horizontal")], 1256 draggable,dragY,dragX,touchStartY,touchStartX,touchMoveY=[],touchMoveX=[],startTime,runningTime,endTime,distance,speed,amount, 1257 durA=0,durB,overwrite=o.axis==="yx" ? "none" : "all",touchIntent=[],touchDrag,docDrag, 1258 iframe=mCSB_container.find("iframe"), 1259 events=[ 1260 "touchstart."+namespace+" pointerdown."+namespace+" MSPointerDown."+namespace, //start 1261 "touchmove."+namespace+" pointermove."+namespace+" MSPointerMove."+namespace, //move 1262 "touchend."+namespace+" pointerup."+namespace+" MSPointerUp."+namespace //end 1263 ], 1264 touchAction=document.body.style.touchAction!==undefined && document.body.style.touchAction!==""; 1265 mCSB_container.bind(events[0],function(e){ 1266 _onTouchstart(e); 1267 }).bind(events[1],function(e){ 1268 _onTouchmove(e); 1269 }); 1270 mCustomScrollBox.bind(events[0],function(e){ 1271 _onTouchstart2(e); 1272 }).bind(events[2],function(e){ 1273 _onTouchend(e); 1274 }); 1275 if(iframe.length){ 1276 iframe.each(function(){ 1277 $(this).bind("load",function(){ 1278 /* bind events on accessible iframes */ 1279 if(_canAccessIFrame(this)){ 1280 $(this.contentDocument || this.contentWindow.document).bind(events[0],function(e){ 1281 _onTouchstart(e); 1282 _onTouchstart2(e); 1283 }).bind(events[1],function(e){ 1284 _onTouchmove(e); 1285 }).bind(events[2],function(e){ 1286 _onTouchend(e); 1287 }); 1288 } 1289 }); 1290 }); 1291 } 1292 function _onTouchstart(e){ 1293 if(!_pointerTouch(e) || touchActive || _coordinates(e)[2]){touchable=0; return;} 1294 touchable=1; touchDrag=0; docDrag=0; draggable=1; 1295 $this.removeClass("mCS_touch_action"); 1296 var offset=mCSB_container.offset(); 1297 dragY=_coordinates(e)[0]-offset.top; 1298 dragX=_coordinates(e)[1]-offset.left; 1299 touchIntent=[_coordinates(e)[0],_coordinates(e)[1]]; 1300 } 1301 function _onTouchmove(e){ 1302 if(!_pointerTouch(e) || touchActive || _coordinates(e)[2]){return;} 1303 if(!o.documentTouchScroll){e.preventDefault();} 1304 e.stopImmediatePropagation(); 1305 if(docDrag && !touchDrag){return;} 1306 if(draggable){ 1307 runningTime=_getTime(); 1308 var offset=mCustomScrollBox.offset(),y=_coordinates(e)[0]-offset.top,x=_coordinates(e)[1]-offset.left, 1309 easing="mcsLinearOut"; 1310 touchMoveY.push(y); 1311 touchMoveX.push(x); 1312 touchIntent[2]=Math.abs(_coordinates(e)[0]-touchIntent[0]); touchIntent[3]=Math.abs(_coordinates(e)[1]-touchIntent[1]); 1313 if(d.overflowed[0]){ 1314 var limit=mCSB_dragger[0].parent().height()-mCSB_dragger[0].height(), 1315 prevent=((dragY-y)>0 && (y-dragY)>-(limit*d.scrollRatio.y) && (touchIntent[3]*2<touchIntent[2] || o.axis==="yx")); 1316 } 1317 if(d.overflowed[1]){ 1318 var limitX=mCSB_dragger[1].parent().width()-mCSB_dragger[1].width(), 1319 preventX=((dragX-x)>0 && (x-dragX)>-(limitX*d.scrollRatio.x) && (touchIntent[2]*2<touchIntent[3] || o.axis==="yx")); 1320 } 1321 if(prevent || preventX){ /* prevent native document scrolling */ 1322 if(!touchAction){e.preventDefault();} 1323 touchDrag=1; 1324 }else{ 1325 docDrag=1; 1326 $this.addClass("mCS_touch_action"); 1327 } 1328 if(touchAction){e.preventDefault();} 1329 amount=o.axis==="yx" ? [(dragY-y),(dragX-x)] : o.axis==="x" ? [null,(dragX-x)] : [(dragY-y),null]; 1330 mCSB_container[0].idleTimer=250; 1331 if(d.overflowed[0]){_drag(amount[0],durA,easing,"y","all",true);} 1332 if(d.overflowed[1]){_drag(amount[1],durA,easing,"x",overwrite,true);} 1333 } 1334 } 1335 function _onTouchstart2(e){ 1336 if(!_pointerTouch(e) || touchActive || _coordinates(e)[2]){touchable=0; return;} 1337 touchable=1; 1338 e.stopImmediatePropagation(); 1339 _stop($this); 1340 startTime=_getTime(); 1341 var offset=mCustomScrollBox.offset(); 1342 touchStartY=_coordinates(e)[0]-offset.top; 1343 touchStartX=_coordinates(e)[1]-offset.left; 1344 touchMoveY=[]; touchMoveX=[]; 1345 } 1346 function _onTouchend(e){ 1347 if(!_pointerTouch(e) || touchActive || _coordinates(e)[2]){return;} 1348 draggable=0; 1349 e.stopImmediatePropagation(); 1350 touchDrag=0; docDrag=0; 1351 endTime=_getTime(); 1352 var offset=mCustomScrollBox.offset(),y=_coordinates(e)[0]-offset.top,x=_coordinates(e)[1]-offset.left; 1353 if((endTime-runningTime)>30){return;} 1354 speed=1000/(endTime-startTime); 1355 var easing="mcsEaseOut",slow=speed<2.5, 1356 diff=slow ? [touchMoveY[touchMoveY.length-2],touchMoveX[touchMoveX.length-2]] : [0,0]; 1357 distance=slow ? [(y-diff[0]),(x-diff[1])] : [y-touchStartY,x-touchStartX]; 1358 var absDistance=[Math.abs(distance[0]),Math.abs(distance[1])]; 1359 speed=slow ? [Math.abs(distance[0]/4),Math.abs(distance[1]/4)] : [speed,speed]; 1360 var a=[ 1361 Math.abs(mCSB_container[0].offsetTop)-(distance[0]*_m((absDistance[0]/speed[0]),speed[0])), 1362 Math.abs(mCSB_container[0].offsetLeft)-(distance[1]*_m((absDistance[1]/speed[1]),speed[1])) 1363 ]; 1364 amount=o.axis==="yx" ? [a[0],a[1]] : o.axis==="x" ? [null,a[1]] : [a[0],null]; 1365 durB=[(absDistance[0]*4)+o.scrollInertia,(absDistance[1]*4)+o.scrollInertia]; 1366 var md=parseInt(o.contentTouchScroll) || 0; /* absolute minimum distance required */ 1367 amount[0]=absDistance[0]>md ? amount[0] : 0; 1368 amount[1]=absDistance[1]>md ? amount[1] : 0; 1369 if(d.overflowed[0]){_drag(amount[0],durB[0],easing,"y",overwrite,false);} 1370 if(d.overflowed[1]){_drag(amount[1],durB[1],easing,"x",overwrite,false);} 1371 } 1372 function _m(ds,s){ 1373 var r=[s*1.5,s*2,s/1.5,s/2]; 1374 if(ds>90){ 1375 return s>4 ? r[0] : r[3]; 1376 }else if(ds>60){ 1377 return s>3 ? r[3] : r[2]; 1378 }else if(ds>30){ 1379 return s>8 ? r[1] : s>6 ? r[0] : s>4 ? s : r[2]; 1380 }else{ 1381 return s>8 ? s : r[3]; 1382 } 1383 } 1384 function _drag(amount,dur,easing,dir,overwrite,drag){ 1385 if(!amount){return;} 1386 _scrollTo($this,amount.toString(),{dur:dur,scrollEasing:easing,dir:dir,overwrite:overwrite,drag:drag}); 1387 } 1388 }, 1389 /* -------------------- */ 1390 1391 1392 /* 1393 SELECT TEXT EVENTS 1394 scrolls content when text is selected 1395 */ 1396 _selectable=function(){ 1397 var $this=$(this),d=$this.data(pluginPfx),o=d.opt,seq=d.sequential, 1398 namespace=pluginPfx+"_"+d.idx, 1399 mCSB_container=$("#mCSB_"+d.idx+"_container"), 1400 wrapper=mCSB_container.parent(), 1401 action; 1402 mCSB_container.bind("mousedown."+namespace,function(e){ 1403 if(touchable){return;} 1404 if(!action){action=1; touchActive=true;} 1405 }).add(document).bind("mousemove."+namespace,function(e){ 1406 if(!touchable && action && _sel()){ 1407 var offset=mCSB_container.offset(), 1408 y=_coordinates(e)[0]-offset.top+mCSB_container[0].offsetTop,x=_coordinates(e)[1]-offset.left+mCSB_container[0].offsetLeft; 1409 if(y>0 && y<wrapper.height() && x>0 && x<wrapper.width()){ 1410 if(seq.step){_seq("off",null,"stepped");} 1411 }else{ 1412 if(o.axis!=="x" && d.overflowed[0]){ 1413 if(y<0){ 1414 _seq("on",38); 1415 }else if(y>wrapper.height()){ 1416 _seq("on",40); 1417 } 1418 } 1419 if(o.axis!=="y" && d.overflowed[1]){ 1420 if(x<0){ 1421 _seq("on",37); 1422 }else if(x>wrapper.width()){ 1423 _seq("on",39); 1424 } 1425 } 1426 } 1427 } 1428 }).bind("mouseup."+namespace+" dragend."+namespace,function(e){ 1429 if(touchable){return;} 1430 if(action){action=0; _seq("off",null);} 1431 touchActive=false; 1432 }); 1433 function _sel(){ 1434 return window.getSelection ? window.getSelection().toString() : 1435 document.selection && document.selection.type!="Control" ? document.selection.createRange().text : 0; 1436 } 1437 function _seq(a,c,s){ 1438 seq.type=s && action ? "stepped" : "stepless"; 1439 seq.scrollAmount=10; 1440 _sequentialScroll($this,a,c,"mcsLinearOut",s ? 60 : null); 1441 } 1442 }, 1443 /* -------------------- */ 1444 1445 1446 /* 1447 MOUSE WHEEL EVENT 1448 scrolls content via mouse-wheel 1449 via mouse-wheel plugin (https://github.com/brandonaaron/jquery-mousewheel) 1450 */ 1451 _mousewheel=function(){ 1452 if(!$(this).data(pluginPfx)){return;} /* Check if the scrollbar is ready to use mousewheel events (issue: #185) */ 1453 var $this=$(this),d=$this.data(pluginPfx),o=d.opt, 1454 namespace=pluginPfx+"_"+d.idx, 1455 mCustomScrollBox=$("#mCSB_"+d.idx), 1456 mCSB_dragger=[$("#mCSB_"+d.idx+"_dragger_vertical"),$("#mCSB_"+d.idx+"_dragger_horizontal")], 1457 iframe=$("#mCSB_"+d.idx+"_container").find("iframe"); 1458 if(iframe.length){ 1459 iframe.each(function(){ 1460 $(this).bind("load",function(){ 1461 /* bind events on accessible iframes */ 1462 if(_canAccessIFrame(this)){ 1463 $(this.contentDocument || this.contentWindow.document).bind("mousewheel."+namespace,function(e,delta){ 1464 _onMousewheel(e,delta); 1465 }); 1466 } 1467 }); 1468 }); 1469 } 1470 mCustomScrollBox.bind("mousewheel."+namespace,function(e,delta){ 1471 _onMousewheel(e,delta); 1472 }); 1473 function _onMousewheel(e,delta){ 1474 _stop($this); 1475 if(_disableMousewheel($this,e.target)){return;} /* disables mouse-wheel when hovering specific elements */ 1476 var deltaFactor=o.mouseWheel.deltaFactor!=="auto" ? parseInt(o.mouseWheel.deltaFactor) : (oldIE && e.deltaFactor<100) ? 100 : e.deltaFactor || 100, 1477 dur=o.scrollInertia; 1478 if(o.axis==="x" || o.mouseWheel.axis==="x"){ 1479 var dir="x", 1480 px=[Math.round(deltaFactor*d.scrollRatio.x),parseInt(o.mouseWheel.scrollAmount)], 1481 amount=o.mouseWheel.scrollAmount!=="auto" ? px[1] : px[0]>=mCustomScrollBox.width() ? mCustomScrollBox.width()*0.9 : px[0], 1482 contentPos=Math.abs($("#mCSB_"+d.idx+"_container")[0].offsetLeft), 1483 draggerPos=mCSB_dragger[1][0].offsetLeft, 1484 limit=mCSB_dragger[1].parent().width()-mCSB_dragger[1].width(), 1485 dlt=o.mouseWheel.axis==="y" ? (e.deltaY || delta) : e.deltaX; 1486 }else{ 1487 var dir="y", 1488 px=[Math.round(deltaFactor*d.scrollRatio.y),parseInt(o.mouseWheel.scrollAmount)], 1489 amount=o.mouseWheel.scrollAmount!=="auto" ? px[1] : px[0]>=mCustomScrollBox.height() ? mCustomScrollBox.height()*0.9 : px[0], 1490 contentPos=Math.abs($("#mCSB_"+d.idx+"_container")[0].offsetTop), 1491 draggerPos=mCSB_dragger[0][0].offsetTop, 1492 limit=mCSB_dragger[0].parent().height()-mCSB_dragger[0].height(), 1493 dlt=e.deltaY || delta; 1494 } 1495 if((dir==="y" && !d.overflowed[0]) || (dir==="x" && !d.overflowed[1])){return;} 1496 if(o.mouseWheel.invert || e.webkitDirectionInvertedFromDevice){dlt=-dlt;} 1497 if(o.mouseWheel.normalizeDelta){dlt=dlt<0 ? -1 : 1;} 1498 if((dlt>0 && draggerPos!==0) || (dlt<0 && draggerPos!==limit) || o.mouseWheel.preventDefault){ 1499 e.stopImmediatePropagation(); 1500 e.preventDefault(); 1501 } 1502 if(e.deltaFactor<5 && !o.mouseWheel.normalizeDelta){ 1503 //very low deltaFactor values mean some kind of delta acceleration (e.g. osx trackpad), so adjusting scrolling accordingly 1504 amount=e.deltaFactor; dur=17; 1505 } 1506 _scrollTo($this,(contentPos-(dlt*amount)).toString(),{dir:dir,dur:dur}); 1507 } 1508 }, 1509 /* -------------------- */ 1510 1511 1512 /* checks if iframe can be accessed */ 1513 _canAccessIFrameCache=new Object(), 1514 _canAccessIFrame=function(iframe){ 1515 var result=false,cacheKey=false,html=null; 1516 if(iframe===undefined){ 1517 cacheKey="#empty"; 1518 }else if($(iframe).attr("id")!==undefined){ 1519 cacheKey=$(iframe).attr("id"); 1520 } 1521 if(cacheKey!==false && _canAccessIFrameCache[cacheKey]!==undefined){ 1522 return _canAccessIFrameCache[cacheKey]; 1523 } 1524 if(!iframe){ 1525 try{ 1526 var doc=top.document; 1527 html=doc.body.innerHTML; 1528 }catch(err){/* do nothing */} 1529 result=(html!==null); 1530 }else{ 1531 try{ 1532 var doc=iframe.contentDocument || iframe.contentWindow.document; 1533 html=doc.body.innerHTML; 1534 }catch(err){/* do nothing */} 1535 result=(html!==null); 1536 } 1537 if(cacheKey!==false){_canAccessIFrameCache[cacheKey]=result;} 1538 return result; 1539 }, 1540 /* -------------------- */ 1541 1542 1543 /* switches iframe's pointer-events property (drag, mousewheel etc. over cross-domain iframes) */ 1544 _iframe=function(evt){ 1545 var el=this.find("iframe"); 1546 if(!el.length){return;} /* check if content contains iframes */ 1547 var val=!evt ? "none" : "auto"; 1548 el.css("pointer-events",val); /* for IE11, iframe's display property should not be "block" */ 1549 }, 1550 /* -------------------- */ 1551 1552 1553 /* disables mouse-wheel when hovering specific elements like select, datalist etc. */ 1554 _disableMousewheel=function(el,target){ 1555 var tag=target.nodeName.toLowerCase(), 1556 tags=el.data(pluginPfx).opt.mouseWheel.disableOver, 1557 /* elements that require focus */ 1558 focusTags=["select","textarea"]; 1559 return $.inArray(tag,tags) > -1 && !($.inArray(tag,focusTags) > -1 && !$(target).is(":focus")); 1560 }, 1561 /* -------------------- */ 1562 1563 1564 /* 1565 DRAGGER RAIL CLICK EVENT 1566 scrolls content via dragger rail 1567 */ 1568 _draggerRail=function(){ 1569 var $this=$(this),d=$this.data(pluginPfx), 1570 namespace=pluginPfx+"_"+d.idx, 1571 mCSB_container=$("#mCSB_"+d.idx+"_container"), 1572 wrapper=mCSB_container.parent(), 1573 mCSB_draggerContainer=$(".mCSB_"+d.idx+"_scrollbar ."+classes[12]), 1574 clickable; 1575 mCSB_draggerContainer.bind("mousedown."+namespace+" touchstart."+namespace+" pointerdown."+namespace+" MSPointerDown."+namespace,function(e){ 1576 touchActive=true; 1577 if(!$(e.target).hasClass("mCSB_dragger")){clickable=1;} 1578 }).bind("touchend."+namespace+" pointerup."+namespace+" MSPointerUp."+namespace,function(e){ 1579 touchActive=false; 1580 }).bind("click."+namespace,function(e){ 1581 if(!clickable){return;} 1582 clickable=0; 1583 if($(e.target).hasClass(classes[12]) || $(e.target).hasClass("mCSB_draggerRail")){ 1584 _stop($this); 1585 var el=$(this),mCSB_dragger=el.find(".mCSB_dragger"); 1586 if(el.parent(".mCSB_scrollTools_horizontal").length>0){ 1587 if(!d.overflowed[1]){return;} 1588 var dir="x", 1589 clickDir=e.pageX>mCSB_dragger.offset().left ? -1 : 1, 1590 to=Math.abs(mCSB_container[0].offsetLeft)-(clickDir*(wrapper.width()*0.9)); 1591 }else{ 1592 if(!d.overflowed[0]){return;} 1593 var dir="y", 1594 clickDir=e.pageY>mCSB_dragger.offset().top ? -1 : 1, 1595 to=Math.abs(mCSB_container[0].offsetTop)-(clickDir*(wrapper.height()*0.9)); 1596 } 1597 _scrollTo($this,to.toString(),{dir:dir,scrollEasing:"mcsEaseInOut"}); 1598 } 1599 }); 1600 }, 1601 /* -------------------- */ 1602 1603 1604 /* 1605 FOCUS EVENT 1606 scrolls content via element focus (e.g. clicking an input, pressing TAB key etc.) 1607 */ 1608 _focus=function(){ 1609 var $this=$(this),d=$this.data(pluginPfx),o=d.opt, 1610 namespace=pluginPfx+"_"+d.idx, 1611 mCSB_container=$("#mCSB_"+d.idx+"_container"), 1612 wrapper=mCSB_container.parent(); 1613 mCSB_container.bind("focusin."+namespace,function(e){ 1614 var el=$(document.activeElement), 1615 nested=mCSB_container.find(".mCustomScrollBox").length, 1616 dur=0; 1617 if(!el.is(o.advanced.autoScrollOnFocus)){return;} 1618 _stop($this); 1619 clearTimeout($this[0]._focusTimeout); 1620 $this[0]._focusTimer=nested ? (dur+17)*nested : 0; 1621 $this[0]._focusTimeout=setTimeout(function(){ 1622 var to=[_childPos(el)[0],_childPos(el)[1]], 1623 contentPos=[mCSB_container[0].offsetTop,mCSB_container[0].offsetLeft], 1624 isVisible=[ 1625 (contentPos[0]+to[0]>=0 && contentPos[0]+to[0]<wrapper.height()-el.outerHeight(false)), 1626 (contentPos[1]+to[1]>=0 && contentPos[0]+to[1]<wrapper.width()-el.outerWidth(false)) 1627 ], 1628 overwrite=(o.axis==="yx" && !isVisible[0] && !isVisible[1]) ? "none" : "all"; 1629 if(o.axis!=="x" && !isVisible[0]){ 1630 _scrollTo($this,to[0].toString(),{dir:"y",scrollEasing:"mcsEaseInOut",overwrite:overwrite,dur:dur}); 1631 } 1632 if(o.axis!=="y" && !isVisible[1]){ 1633 _scrollTo($this,to[1].toString(),{dir:"x",scrollEasing:"mcsEaseInOut",overwrite:overwrite,dur:dur}); 1634 } 1635 },$this[0]._focusTimer); 1636 }); 1637 }, 1638 /* -------------------- */ 1639 1640 1641 /* sets content wrapper scrollTop/scrollLeft always to 0 */ 1642 _wrapperScroll=function(){ 1643 var $this=$(this),d=$this.data(pluginPfx), 1644 namespace=pluginPfx+"_"+d.idx, 1645 wrapper=$("#mCSB_"+d.idx+"_container").parent(); 1646 wrapper.bind("scroll."+namespace,function(e){ 1647 if(wrapper.scrollTop()!==0 || wrapper.scrollLeft()!==0){ 1648 $(".mCSB_"+d.idx+"_scrollbar").css("visibility","hidden"); /* hide scrollbar(s) */ 1649 } 1650 }); 1651 }, 1652 /* -------------------- */ 1653 1654 1655 /* 1656 BUTTONS EVENTS 1657 scrolls content via up, down, left and right buttons 1658 */ 1659 _buttons=function(){ 1660 var $this=$(this),d=$this.data(pluginPfx),o=d.opt,seq=d.sequential, 1661 namespace=pluginPfx+"_"+d.idx, 1662 sel=".mCSB_"+d.idx+"_scrollbar", 1663 btn=$(sel+">a"); 1664 btn.bind("contextmenu."+namespace,function(e){ 1665 e.preventDefault(); //prevent right click 1666 }).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){ 1667 e.preventDefault(); 1668 if(!_mouseBtnLeft(e)){return;} /* left mouse button only */ 1669 var btnClass=$(this).attr("class"); 1670 seq.type=o.scrollButtons.scrollType; 1671 switch(e.type){ 1672 case "mousedown": case "touchstart": case "pointerdown": case "MSPointerDown": 1673 if(seq.type==="stepped"){return;} 1674 touchActive=true; 1675 d.tweenRunning=false; 1676 _seq("on",btnClass); 1677 break; 1678 case "mouseup": case "touchend": case "pointerup": case "MSPointerUp": 1679 case "mouseout": case "pointerout": case "MSPointerOut": 1680 if(seq.type==="stepped"){return;} 1681 touchActive=false; 1682 if(seq.dir){_seq("off",btnClass);} 1683 break; 1684 case "click": 1685 if(seq.type!=="stepped" || d.tweenRunning){return;} 1686 _seq("on",btnClass); 1687 break; 1688 } 1689 function _seq(a,c){ 1690 seq.scrollAmount=o.scrollButtons.scrollAmount; 1691 _sequentialScroll($this,a,c); 1692 } 1693 }); 1694 }, 1695 /* -------------------- */ 1696 1697 1698 /* 1699 KEYBOARD EVENTS 1700 scrolls content via keyboard 1701 Keys: up arrow, down arrow, left arrow, right arrow, PgUp, PgDn, Home, End 1702 */ 1703 _keyboard=function(){ 1704 var $this=$(this),d=$this.data(pluginPfx),o=d.opt,seq=d.sequential, 1705 namespace=pluginPfx+"_"+d.idx, 1706 mCustomScrollBox=$("#mCSB_"+d.idx), 1707 mCSB_container=$("#mCSB_"+d.idx+"_container"), 1708 wrapper=mCSB_container.parent(), 1709 editables="input,textarea,select,datalist,keygen,[contenteditable='true']", 1710 iframe=mCSB_container.find("iframe"), 1711 events=["blur."+namespace+" keydown."+namespace+" keyup."+namespace]; 1712 if(iframe.length){ 1713 iframe.each(function(){ 1714 $(this).bind("load",function(){ 1715 /* bind events on accessible iframes */ 1716 if(_canAccessIFrame(this)){ 1717 $(this.contentDocument || this.contentWindow.document).bind(events[0],function(e){ 1718 _onKeyboard(e); 1719 }); 1720 } 1721 }); 1722 }); 1723 } 1724 mCustomScrollBox.attr("tabindex","0").bind(events[0],function(e){ 1725 _onKeyboard(e); 1726 }); 1727 function _onKeyboard(e){ 1728 switch(e.type){ 1729 case "blur": 1730 if(d.tweenRunning && seq.dir){_seq("off",null);} 1731 break; 1732 case "keydown": case "keyup": 1733 var code=e.keyCode ? e.keyCode : e.which,action="on"; 1734 if((o.axis!=="x" && (code===38 || code===40)) || (o.axis!=="y" && (code===37 || code===39))){ 1735 /* up (38), down (40), left (37), right (39) arrows */ 1736 if(((code===38 || code===40) && !d.overflowed[0]) || ((code===37 || code===39) && !d.overflowed[1])){return;} 1737 if(e.type==="keyup"){action="off";} 1738 if(!$(document.activeElement).is(editables)){ 1739 e.preventDefault(); 1740 e.stopImmediatePropagation(); 1741 _seq(action,code); 1742 } 1743 }else if(code===33 || code===34){ 1744 /* PgUp (33), PgDn (34) */ 1745 if(d.overflowed[0] || d.overflowed[1]){ 1746 e.preventDefault(); 1747 e.stopImmediatePropagation(); 1748 } 1749 if(e.type==="keyup"){ 1750 _stop($this); 1751 var keyboardDir=code===34 ? -1 : 1; 1752 if(o.axis==="x" || (o.axis==="yx" && d.overflowed[1] && !d.overflowed[0])){ 1753 var dir="x",to=Math.abs(mCSB_container[0].offsetLeft)-(keyboardDir*(wrapper.width()*0.9)); 1754 }else{ 1755 var dir="y",to=Math.abs(mCSB_container[0].offsetTop)-(keyboardDir*(wrapper.height()*0.9)); 1756 } 1757 _scrollTo($this,to.toString(),{dir:dir,scrollEasing:"mcsEaseInOut"}); 1758 } 1759 }else if(code===35 || code===36){ 1760 /* End (35), Home (36) */ 1761 if(!$(document.activeElement).is(editables)){ 1762 if(d.overflowed[0] || d.overflowed[1]){ 1763 e.preventDefault(); 1764 e.stopImmediatePropagation(); 1765 } 1766 if(e.type==="keyup"){ 1767 if(o.axis==="x" || (o.axis==="yx" && d.overflowed[1] && !d.overflowed[0])){ 1768 var dir="x",to=code===35 ? Math.abs(wrapper.width()-mCSB_container.outerWidth(false)) : 0; 1769 }else{ 1770 var dir="y",to=code===35 ? Math.abs(wrapper.height()-mCSB_container.outerHeight(false)) : 0; 1771 } 1772 _scrollTo($this,to.toString(),{dir:dir,scrollEasing:"mcsEaseInOut"}); 1773 } 1774 } 1775 } 1776 break; 1777 } 1778 function _seq(a,c){ 1779 seq.type=o.keyboard.scrollType; 1780 seq.scrollAmount=o.keyboard.scrollAmount; 1781 if(seq.type==="stepped" && d.tweenRunning){return;} 1782 _sequentialScroll($this,a,c); 1783 } 1784 } 1785 }, 1786 /* -------------------- */ 1787 1788 1789 /* scrolls content sequentially (used when scrolling via buttons, keyboard arrows etc.) */ 1790 _sequentialScroll=function(el,action,trigger,e,s){ 1791 var d=el.data(pluginPfx),o=d.opt,seq=d.sequential, 1792 mCSB_container=$("#mCSB_"+d.idx+"_container"), 1793 once=seq.type==="stepped" ? true : false, 1794 steplessSpeed=o.scrollInertia < 26 ? 26 : o.scrollInertia, /* 26/1.5=17 */ 1795 steppedSpeed=o.scrollInertia < 1 ? 17 : o.scrollInertia; 1796 switch(action){ 1797 case "on": 1798 seq.dir=[ 1799 (trigger===classes[16] || trigger===classes[15] || trigger===39 || trigger===37 ? "x" : "y"), 1800 (trigger===classes[13] || trigger===classes[15] || trigger===38 || trigger===37 ? -1 : 1) 1801 ]; 1802 _stop(el); 1803 if(_isNumeric(trigger) && seq.type==="stepped"){return;} 1804 _on(once); 1805 break; 1806 case "off": 1807 _off(); 1808 if(once || (d.tweenRunning && seq.dir)){ 1809 _on(true); 1810 } 1811 break; 1812 } 1813 1814 /* starts sequence */ 1815 function _on(once){ 1816 if(o.snapAmount){seq.scrollAmount=!(o.snapAmount instanceof Array) ? o.snapAmount : seq.dir[0]==="x" ? o.snapAmount[1] : o.snapAmount[0];} /* scrolling snapping */ 1817 var c=seq.type!=="stepped", /* continuous scrolling */ 1818 t=s ? s : !once ? 1000/60 : c ? steplessSpeed/1.5 : steppedSpeed, /* timer */ 1819 m=!once ? 2.5 : c ? 7.5 : 40, /* multiplier */ 1820 contentPos=[Math.abs(mCSB_container[0].offsetTop),Math.abs(mCSB_container[0].offsetLeft)], 1821 ratio=[d.scrollRatio.y>10 ? 10 : d.scrollRatio.y,d.scrollRatio.x>10 ? 10 : d.scrollRatio.x], 1822 amount=seq.dir[0]==="x" ? contentPos[1]+(seq.dir[1]*(ratio[1]*m)) : contentPos[0]+(seq.dir[1]*(ratio[0]*m)), 1823 px=seq.dir[0]==="x" ? contentPos[1]+(seq.dir[1]*parseInt(seq.scrollAmount)) : contentPos[0]+(seq.dir[1]*parseInt(seq.scrollAmount)), 1824 to=seq.scrollAmount!=="auto" ? px : amount, 1825 easing=e ? e : !once ? "mcsLinear" : c ? "mcsLinearOut" : "mcsEaseInOut", 1826 onComplete=!once ? false : true; 1827 if(once && t<17){ 1828 to=seq.dir[0]==="x" ? contentPos[1] : contentPos[0]; 1829 } 1830 _scrollTo(el,to.toString(),{dir:seq.dir[0],scrollEasing:easing,dur:t,onComplete:onComplete}); 1831 if(once){ 1832 seq.dir=false; 1833 return; 1834 } 1835 clearTimeout(seq.step); 1836 seq.step=setTimeout(function(){ 1837 _on(); 1838 },t); 1839 } 1840 /* stops sequence */ 1841 function _off(){ 1842 clearTimeout(seq.step); 1843 _delete(seq,"step"); 1844 _stop(el); 1845 } 1846 }, 1847 /* -------------------- */ 1848 1849 1850 /* returns a yx array from value */ 1851 _arr=function(val){ 1852 var o=$(this).data(pluginPfx).opt,vals=[]; 1853 if(typeof val==="function"){val=val();} /* check if the value is a single anonymous function */ 1854 /* check if value is object or array, its length and create an array with yx values */ 1855 if(!(val instanceof Array)){ /* object value (e.g. {y:"100",x:"100"}, 100 etc.) */ 1856 vals[0]=val.y ? val.y : val.x || o.axis==="x" ? null : val; 1857 vals[1]=val.x ? val.x : val.y || o.axis==="y" ? null : val; 1858 }else{ /* array value (e.g. [100,100]) */ 1859 vals=val.length>1 ? [val[0],val[1]] : o.axis==="x" ? [null,val[0]] : [val[0],null]; 1860 } 1861 /* check if array values are anonymous functions */ 1862 if(typeof vals[0]==="function"){vals[0]=vals[0]();} 1863 if(typeof vals[1]==="function"){vals[1]=vals[1]();} 1864 return vals; 1865 }, 1866 /* -------------------- */ 1867 1868 1869 /* translates values (e.g. "top", 100, "100px", "#id") to actual scroll-to positions */ 1870 _to=function(val,dir){ 1871 if(val==null || typeof val=="undefined"){return;} 1872 var $this=$(this),d=$this.data(pluginPfx),o=d.opt, 1873 mCSB_container=$("#mCSB_"+d.idx+"_container"), 1874 wrapper=mCSB_container.parent(), 1875 t=typeof val; 1876 if(!dir){dir=o.axis==="x" ? "x" : "y";} 1877 var contentLength=dir==="x" ? mCSB_container.outerWidth(false)-wrapper.width() : mCSB_container.outerHeight(false)-wrapper.height(), 1878 contentPos=dir==="x" ? mCSB_container[0].offsetLeft : mCSB_container[0].offsetTop, 1879 cssProp=dir==="x" ? "left" : "top"; 1880 switch(t){ 1881 case "function": /* this currently is not used. Consider removing it */ 1882 return val(); 1883 break; 1884 case "object": /* js/jquery object */ 1885 var obj=val.jquery ? val : $(val); 1886 if(!obj.length){return;} 1887 return dir==="x" ? _childPos(obj)[1] : _childPos(obj)[0]; 1888 break; 1889 case "string": case "number": 1890 if(_isNumeric(val)){ /* numeric value */ 1891 return Math.abs(val); 1892 }else if(val.indexOf("%")!==-1){ /* percentage value */ 1893 return Math.abs(contentLength*parseInt(val)/100); 1894 }else if(val.indexOf("-=")!==-1){ /* decrease value */ 1895 return Math.abs(contentPos-parseInt(val.split("-=")[1])); 1896 }else if(val.indexOf("+=")!==-1){ /* inrease value */ 1897 var p=(contentPos+parseInt(val.split("+=")[1])); 1898 return p>=0 ? 0 : Math.abs(p); 1899 }else if(val.indexOf("px")!==-1 && _isNumeric(val.split("px")[0])){ /* pixels string value (e.g. "100px") */ 1900 return Math.abs(val.split("px")[0]); 1901 }else{ 1902 if(val==="top" || val==="left"){ /* special strings */ 1903 return 0; 1904 }else if(val==="bottom"){ 1905 return Math.abs(wrapper.height()-mCSB_container.outerHeight(false)); 1906 }else if(val==="right"){ 1907 return Math.abs(wrapper.width()-mCSB_container.outerWidth(false)); 1908 }else if(val==="first" || val==="last"){ 1909 var obj=mCSB_container.find(":"+val); 1910 return dir==="x" ? _childPos(obj)[1] : _childPos(obj)[0]; 1911 }else{ 1912 if($(val).length){ /* jquery selector */ 1913 return dir==="x" ? _childPos($(val))[1] : _childPos($(val))[0]; 1914 }else{ /* other values (e.g. "100em") */ 1915 mCSB_container.css(cssProp,val); 1916 methods.update.call(null,$this[0]); 1917 return; 1918 } 1919 } 1920 } 1921 break; 1922 } 1923 }, 1924 /* -------------------- */ 1925 1926 1927 /* calls the update method automatically */ 1928 _autoUpdate=function(rem){ 1929 var $this=$(this),d=$this.data(pluginPfx),o=d.opt, 1930 mCSB_container=$("#mCSB_"+d.idx+"_container"); 1931 if(rem){ 1932 /* 1933 removes autoUpdate timer 1934 usage: _autoUpdate.call(this,"remove"); 1935 */ 1936 clearTimeout(mCSB_container[0].autoUpdate); 1937 _delete(mCSB_container[0],"autoUpdate"); 1938 return; 1939 } 1940 upd(); 1941 function upd(){ 1942 clearTimeout(mCSB_container[0].autoUpdate); 1943 if($this.parents("html").length===0){ 1944 /* check element in dom tree */ 1945 $this=null; 1946 return; 1947 } 1948 mCSB_container[0].autoUpdate=setTimeout(function(){ 1949 /* update on specific selector(s) length and size change */ 1950 if(o.advanced.updateOnSelectorChange){ 1951 d.poll.change.n=sizesSum(); 1952 if(d.poll.change.n!==d.poll.change.o){ 1953 d.poll.change.o=d.poll.change.n; 1954 doUpd(3); 1955 return; 1956 } 1957 } 1958 /* update on main element and scrollbar size changes */ 1959 if(o.advanced.updateOnContentResize){ 1960 d.poll.size.n=$this[0].scrollHeight+$this[0].scrollWidth+mCSB_container[0].offsetHeight+$this[0].offsetHeight+$this[0].offsetWidth; 1961 if(d.poll.size.n!==d.poll.size.o){ 1962 d.poll.size.o=d.poll.size.n; 1963 doUpd(1); 1964 return; 1965 } 1966 } 1967 /* update on image load */ 1968 if(o.advanced.updateOnImageLoad){ 1969 if(!(o.advanced.updateOnImageLoad==="auto" && o.axis==="y")){ //by default, it doesn't run on vertical content 1970 d.poll.img.n=mCSB_container.find("img").length; 1971 if(d.poll.img.n!==d.poll.img.o){ 1972 d.poll.img.o=d.poll.img.n; 1973 mCSB_container.find("img").each(function(){ 1974 imgLoader(this); 1975 }); 1976 return; 1977 } 1978 } 1979 } 1980 if(o.advanced.updateOnSelectorChange || o.advanced.updateOnContentResize || o.advanced.updateOnImageLoad){upd();} 1981 },o.advanced.autoUpdateTimeout); 1982 } 1983 /* a tiny image loader */ 1984 function imgLoader(el){ 1985 if($(el).hasClass(classes[2])){doUpd(); return;} 1986 var img=new Image(); 1987 function createDelegate(contextObject,delegateMethod){ 1988 return function(){return delegateMethod.apply(contextObject,arguments);} 1989 } 1990 function imgOnLoad(){ 1991 this.onload=null; 1992 $(el).addClass(classes[2]); 1993 doUpd(2); 1994 } 1995 img.onload=createDelegate(img,imgOnLoad); 1996 img.src=el.src; 1997 } 1998 /* returns the total height and width sum of all elements matching the selector */ 1999 function sizesSum(){ 2000 if(o.advanced.updateOnSelectorChange===true){o.advanced.updateOnSelectorChange="*";} 2001 var total=0,sel=mCSB_container.find(o.advanced.updateOnSelectorChange); 2002 if(o.advanced.updateOnSelectorChange && sel.length>0){sel.each(function(){total+=this.offsetHeight+this.offsetWidth;});} 2003 return total; 2004 } 2005 /* calls the update method */ 2006 function doUpd(cb){ 2007 clearTimeout(mCSB_container[0].autoUpdate); 2008 methods.update.call(null,$this[0],cb); 2009 } 2010 }, 2011 /* -------------------- */ 2012 2013 2014 /* snaps scrolling to a multiple of a pixels number */ 2015 _snapAmount=function(to,amount,offset){ 2016 return (Math.round(to/amount)*amount-offset); 2017 }, 2018 /* -------------------- */ 2019 2020 2021 /* stops content and scrollbar animations */ 2022 _stop=function(el){ 2023 var d=el.data(pluginPfx), 2024 sel=$("#mCSB_"+d.idx+"_container,#mCSB_"+d.idx+"_container_wrapper,#mCSB_"+d.idx+"_dragger_vertical,#mCSB_"+d.idx+"_dragger_horizontal"); 2025 sel.each(function(){ 2026 _stopTween.call(this); 2027 }); 2028 }, 2029 /* -------------------- */ 2030 2031 2032 /* 2033 ANIMATES CONTENT 2034 This is where the actual scrolling happens 2035 */ 2036 _scrollTo=function(el,to,options){ 2037 var d=el.data(pluginPfx),o=d.opt, 2038 defaults={ 2039 trigger:"internal", 2040 dir:"y", 2041 scrollEasing:"mcsEaseOut", 2042 drag:false, 2043 dur:o.scrollInertia, 2044 overwrite:"all", 2045 callbacks:true, 2046 onStart:true, 2047 onUpdate:true, 2048 onComplete:true 2049 }, 2050 options=$.extend(defaults,options), 2051 dur=[options.dur,(options.drag ? 0 : options.dur)], 2052 mCustomScrollBox=$("#mCSB_"+d.idx), 2053 mCSB_container=$("#mCSB_"+d.idx+"_container"), 2054 wrapper=mCSB_container.parent(), 2055 totalScrollOffsets=o.callbacks.onTotalScrollOffset ? _arr.call(el,o.callbacks.onTotalScrollOffset) : [0,0], 2056 totalScrollBackOffsets=o.callbacks.onTotalScrollBackOffset ? _arr.call(el,o.callbacks.onTotalScrollBackOffset) : [0,0]; 2057 d.trigger=options.trigger; 2058 if(wrapper.scrollTop()!==0 || wrapper.scrollLeft()!==0){ /* always reset scrollTop/Left */ 2059 $(".mCSB_"+d.idx+"_scrollbar").css("visibility","visible"); 2060 wrapper.scrollTop(0).scrollLeft(0); 2061 } 2062 if(to==="_resetY" && !d.contentReset.y){ 2063 /* callbacks: onOverflowYNone */ 2064 if(_cb("onOverflowYNone")){o.callbacks.onOverflowYNone.call(el[0]);} 2065 d.contentReset.y=1; 2066 } 2067 if(to==="_resetX" && !d.contentReset.x){ 2068 /* callbacks: onOverflowXNone */ 2069 if(_cb("onOverflowXNone")){o.callbacks.onOverflowXNone.call(el[0]);} 2070 d.contentReset.x=1; 2071 } 2072 if(to==="_resetY" || to==="_resetX"){return;} 2073 if((d.contentReset.y || !el[0].mcs) && d.overflowed[0]){ 2074 /* callbacks: onOverflowY */ 2075 if(_cb("onOverflowY")){o.callbacks.onOverflowY.call(el[0]);} 2076 d.contentReset.x=null; 2077 } 2078 if((d.contentReset.x || !el[0].mcs) && d.overflowed[1]){ 2079 /* callbacks: onOverflowX */ 2080 if(_cb("onOverflowX")){o.callbacks.onOverflowX.call(el[0]);} 2081 d.contentReset.x=null; 2082 } 2083 if(o.snapAmount){ /* scrolling snapping */ 2084 var snapAmount=!(o.snapAmount instanceof Array) ? o.snapAmount : options.dir==="x" ? o.snapAmount[1] : o.snapAmount[0]; 2085 to=_snapAmount(to,snapAmount,o.snapOffset); 2086 } 2087 switch(options.dir){ 2088 case "x": 2089 var mCSB_dragger=$("#mCSB_"+d.idx+"_dragger_horizontal"), 2090 property="left", 2091 contentPos=mCSB_container[0].offsetLeft, 2092 limit=[ 2093 mCustomScrollBox.width()-mCSB_container.outerWidth(false), 2094 mCSB_dragger.parent().width()-mCSB_dragger.width() 2095 ], 2096 scrollTo=[to,to===0 ? 0 : (to/d.scrollRatio.x)], 2097 tso=totalScrollOffsets[1], 2098 tsbo=totalScrollBackOffsets[1], 2099 totalScrollOffset=tso>0 ? tso/d.scrollRatio.x : 0, 2100 totalScrollBackOffset=tsbo>0 ? tsbo/d.scrollRatio.x : 0; 2101 break; 2102 case "y": 2103 var mCSB_dragger=$("#mCSB_"+d.idx+"_dragger_vertical"), 2104 property="top", 2105 contentPos=mCSB_container[0].offsetTop, 2106 limit=[ 2107 mCustomScrollBox.height()-mCSB_container.outerHeight(false), 2108 mCSB_dragger.parent().height()-mCSB_dragger.height() 2109 ], 2110 scrollTo=[to,to===0 ? 0 : (to/d.scrollRatio.y)], 2111 tso=totalScrollOffsets[0], 2112 tsbo=totalScrollBackOffsets[0], 2113 totalScrollOffset=tso>0 ? tso/d.scrollRatio.y : 0, 2114 totalScrollBackOffset=tsbo>0 ? tsbo/d.scrollRatio.y : 0; 2115 break; 2116 } 2117 if(scrollTo[1]<0 || (scrollTo[0]===0 && scrollTo[1]===0)){ 2118 scrollTo=[0,0]; 2119 }else if(scrollTo[1]>=limit[1]){ 2120 scrollTo=[limit[0],limit[1]]; 2121 }else{ 2122 scrollTo[0]=-scrollTo[0]; 2123 } 2124 if(!el[0].mcs){ 2125 _mcs(); /* init mcs object (once) to make it available before callbacks */ 2126 if(_cb("onInit")){o.callbacks.onInit.call(el[0]);} /* callbacks: onInit */ 2127 } 2128 clearTimeout(mCSB_container[0].onCompleteTimeout); 2129 _tweenTo(mCSB_dragger[0],property,Math.round(scrollTo[1]),dur[1],options.scrollEasing); 2130 if(!d.tweenRunning && ((contentPos===0 && scrollTo[0]>=0) || (contentPos===limit[0] && scrollTo[0]<=limit[0]))){return;} 2131 _tweenTo(mCSB_container[0],property,Math.round(scrollTo[0]),dur[0],options.scrollEasing,options.overwrite,{ 2132 onStart:function(){ 2133 if(options.callbacks && options.onStart && !d.tweenRunning){ 2134 /* callbacks: onScrollStart */ 2135 if(_cb("onScrollStart")){_mcs(); o.callbacks.onScrollStart.call(el[0]);} 2136 d.tweenRunning=true; 2137 _onDragClasses(mCSB_dragger); 2138 d.cbOffsets=_cbOffsets(); 2139 } 2140 },onUpdate:function(){ 2141 if(options.callbacks && options.onUpdate){ 2142 /* callbacks: whileScrolling */ 2143 if(_cb("whileScrolling")){_mcs(); o.callbacks.whileScrolling.call(el[0]);} 2144 } 2145 },onComplete:function(){ 2146 if(options.callbacks && options.onComplete){ 2147 if(o.axis==="yx"){clearTimeout(mCSB_container[0].onCompleteTimeout);} 2148 var t=mCSB_container[0].idleTimer || 0; 2149 mCSB_container[0].onCompleteTimeout=setTimeout(function(){ 2150 /* callbacks: onScroll, onTotalScroll, onTotalScrollBack */ 2151 if(_cb("onScroll")){_mcs(); o.callbacks.onScroll.call(el[0]);} 2152 if(_cb("onTotalScroll") && scrollTo[1]>=limit[1]-totalScrollOffset && d.cbOffsets[0]){_mcs(); o.callbacks.onTotalScroll.call(el[0]);} 2153 if(_cb("onTotalScrollBack") && scrollTo[1]<=totalScrollBackOffset && d.cbOffsets[1]){_mcs(); o.callbacks.onTotalScrollBack.call(el[0]);} 2154 d.tweenRunning=false; 2155 mCSB_container[0].idleTimer=0; 2156 _onDragClasses(mCSB_dragger,"hide"); 2157 },t); 2158 } 2159 } 2160 }); 2161 /* checks if callback function exists */ 2162 function _cb(cb){ 2163 return d && o.callbacks[cb] && typeof o.callbacks[cb]==="function"; 2164 } 2165 /* checks whether callback offsets always trigger */ 2166 function _cbOffsets(){ 2167 return [o.callbacks.alwaysTriggerOffsets || contentPos>=limit[0]+tso,o.callbacks.alwaysTriggerOffsets || contentPos<=-tsbo]; 2168 } 2169 /* 2170 populates object with useful values for the user 2171 values: 2172 content: this.mcs.content 2173 content top position: this.mcs.top 2174 content left position: this.mcs.left 2175 dragger top position: this.mcs.draggerTop 2176 dragger left position: this.mcs.draggerLeft 2177 scrolling y percentage: this.mcs.topPct 2178 scrolling x percentage: this.mcs.leftPct 2179 scrolling direction: this.mcs.direction 2180 */ 2181 function _mcs(){ 2182 var cp=[mCSB_container[0].offsetTop,mCSB_container[0].offsetLeft], /* content position */ 2183 dp=[mCSB_dragger[0].offsetTop,mCSB_dragger[0].offsetLeft], /* dragger position */ 2184 cl=[mCSB_container.outerHeight(false),mCSB_container.outerWidth(false)], /* content length */ 2185 pl=[mCustomScrollBox.height(),mCustomScrollBox.width()]; /* content parent length */ 2186 el[0].mcs={ 2187 content:mCSB_container, /* original content wrapper as jquery object */ 2188 top:cp[0],left:cp[1],draggerTop:dp[0],draggerLeft:dp[1], 2189 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])), 2190 direction:options.dir 2191 }; 2192 /* 2193 this refers to the original element containing the scrollbar(s) 2194 usage: this.mcs.top, this.mcs.leftPct etc. 2195 */ 2196 } 2197 }, 2198 /* -------------------- */ 2199 2200 2201 /* 2202 CUSTOM JAVASCRIPT ANIMATION TWEEN 2203 Lighter and faster than jquery animate() and css transitions 2204 Animates top/left properties and includes easings 2205 */ 2206 _tweenTo=function(el,prop,to,duration,easing,overwrite,callbacks){ 2207 if(!el._mTween){el._mTween={top:{},left:{}};} 2208 var callbacks=callbacks || {}, 2209 onStart=callbacks.onStart || function(){},onUpdate=callbacks.onUpdate || function(){},onComplete=callbacks.onComplete || function(){}, 2210 startTime=_getTime(),_delay,progress=0,from=el.offsetTop,elStyle=el.style,_request,tobj=el._mTween[prop]; 2211 if(prop==="left"){from=el.offsetLeft;} 2212 var diff=to-from; 2213 tobj.stop=0; 2214 if(overwrite!=="none"){_cancelTween();} 2215 _startTween(); 2216 function _step(){ 2217 if(tobj.stop){return;} 2218 if(!progress){onStart.call();} 2219 progress=_getTime()-startTime; 2220 _tween(); 2221 if(progress>=tobj.time){ 2222 tobj.time=(progress>tobj.time) ? progress+_delay-(progress-tobj.time) : progress+_delay-1; 2223 if(tobj.time<progress+1){tobj.time=progress+1;} 2224 } 2225 if(tobj.time<duration){tobj.id=_request(_step);}else{onComplete.call();} 2226 } 2227 function _tween(){ 2228 if(duration>0){ 2229 tobj.currVal=_ease(tobj.time,from,diff,duration,easing); 2230 elStyle[prop]=Math.round(tobj.currVal)+"px"; 2231 }else{ 2232 elStyle[prop]=to+"px"; 2233 } 2234 onUpdate.call(); 2235 } 2236 function _startTween(){ 2237 _delay=1000/60; 2238 tobj.time=progress+_delay; 2239 _request=(!window.requestAnimationFrame) ? function(f){_tween(); return setTimeout(f,0.01);} : window.requestAnimationFrame; 2240 tobj.id=_request(_step); 2241 } 2242 function _cancelTween(){ 2243 if(tobj.id==null){return;} 2244 if(!window.requestAnimationFrame){clearTimeout(tobj.id); 2245 }else{window.cancelAnimationFrame(tobj.id);} 2246 tobj.id=null; 2247 } 2248 function _ease(t,b,c,d,type){ 2249 switch(type){ 2250 case "linear": case "mcsLinear": 2251 return c*t/d + b; 2252 break; 2253 case "mcsLinearOut": 2254 t/=d; t--; return c * Math.sqrt(1 - t*t) + b; 2255 break; 2256 case "easeInOutSmooth": 2257 t/=d/2; 2258 if(t<1) return c/2*t*t + b; 2259 t--; 2260 return -c/2 * (t*(t-2) - 1) + b; 2261 break; 2262 case "easeInOutStrong": 2263 t/=d/2; 2264 if(t<1) return c/2 * Math.pow( 2, 10 * (t - 1) ) + b; 2265 t--; 2266 return c/2 * ( -Math.pow( 2, -10 * t) + 2 ) + b; 2267 break; 2268 case "easeInOut": case "mcsEaseInOut": 2269 t/=d/2; 2270 if(t<1) return c/2*t*t*t + b; 2271 t-=2; 2272 return c/2*(t*t*t + 2) + b; 2273 break; 2274 case "easeOutSmooth": 2275 t/=d; t--; 2276 return -c * (t*t*t*t - 1) + b; 2277 break; 2278 case "easeOutStrong": 2279 return c * ( -Math.pow( 2, -10 * t/d ) + 1 ) + b; 2280 break; 2281 case "easeOut": case "mcsEaseOut": default: 2282 var ts=(t/=d)*t,tc=ts*t; 2283 return b+c*(0.499999999999997*tc*ts + -2.5*ts*ts + 5.5*tc + -6.5*ts + 4*t); 2284 } 2285 } 2286 }, 2287 /* -------------------- */ 2288 2289 2290 /* returns current time */ 2291 _getTime=function(){ 2292 if(window.performance && window.performance.now){ 2293 return window.performance.now(); 2294 }else{ 2295 if(window.performance && window.performance.webkitNow){ 2296 return window.performance.webkitNow(); 2297 }else{ 2298 if(Date.now){return Date.now();}else{return new Date().getTime();} 2299 } 2300 } 2301 }, 2302 /* -------------------- */ 2303 2304 2305 /* stops a tween */ 2306 _stopTween=function(){ 2307 var el=this; 2308 if(!el._mTween){el._mTween={top:{},left:{}};} 2309 var props=["top","left"]; 2310 for(var i=0; i<props.length; i++){ 2311 var prop=props[i]; 2312 if(el._mTween[prop].id){ 2313 if(!window.requestAnimationFrame){clearTimeout(el._mTween[prop].id); 2314 }else{window.cancelAnimationFrame(el._mTween[prop].id);} 2315 el._mTween[prop].id=null; 2316 el._mTween[prop].stop=1; 2317 } 2318 } 2319 }, 2320 /* -------------------- */ 2321 2322 2323 /* deletes a property (avoiding the exception thrown by IE) */ 2324 _delete=function(c,m){ 2325 try{delete c[m];}catch(e){c[m]=null;} 2326 }, 2327 /* -------------------- */ 2328 2329 2330 /* detects left mouse button */ 2331 _mouseBtnLeft=function(e){ 2332 return !(e.which && e.which!==1); 2333 }, 2334 /* -------------------- */ 2335 2336 2337 /* detects if pointer type event is touch */ 2338 _pointerTouch=function(e){ 2339 var t=e.originalEvent.pointerType; 2340 return !(t && t!=="touch" && t!==2); 2341 }, 2342 /* -------------------- */ 2343 2344 2345 /* checks if value is numeric */ 2346 _isNumeric=function(val){ 2347 return !isNaN(parseFloat(val)) && isFinite(val); 2348 }, 2349 /* -------------------- */ 2350 2351 2352 /* returns element position according to content */ 2353 _childPos=function(el){ 2354 var p=el.parents(".mCSB_container"); 2355 return [el.offset().top-p.offset().top,el.offset().left-p.offset().left]; 2356 }, 2357 /* -------------------- */ 2358 2359 2360 /* checks if browser tab is hidden/inactive via Page Visibility API */ 2361 _isTabHidden=function(){ 2362 var prop=_getHiddenProp(); 2363 if(!prop) return false; 2364 return document[prop]; 2365 function _getHiddenProp(){ 2366 var pfx=["webkit","moz","ms","o"]; 2367 if("hidden" in document) return "hidden"; //natively supported 2368 for(var i=0; i<pfx.length; i++){ //prefixed 2369 if((pfx[i]+"Hidden") in document) 2370 return pfx[i]+"Hidden"; 2371 } 2372 return null; //not supported 2373 } 2374 }; 2375 /* -------------------- */ 2376 2377 2378 2379 2380 2381 /* 2382 ---------------------------------------- 2383 PLUGIN SETUP 2384 ---------------------------------------- 2385 */ 2386 2387 /* plugin constructor functions */ 2388 $.fn[pluginNS]=function(method){ /* usage: $(selector).mCustomScrollbar(); */ 2389 if(methods[method]){ 2390 return methods[method].apply(this,Array.prototype.slice.call(arguments,1)); 2391 }else if(typeof method==="object" || !method){ 2392 return methods.init.apply(this,arguments); 2393 }else{ 2394 $.error("Method "+method+" does not exist"); 2395 } 2396 }; 2397 $[pluginNS]=function(method){ /* usage: $.mCustomScrollbar(); */ 2398 if(methods[method]){ 2399 return methods[method].apply(this,Array.prototype.slice.call(arguments,1)); 2400 }else if(typeof method==="object" || !method){ 2401 return methods.init.apply(this,arguments); 2402 }else{ 2403 $.error("Method "+method+" does not exist"); 2404 } 2405 }; 2406 2407 /* 2408 allow setting plugin default options. 2409 usage: $.mCustomScrollbar.defaults.scrollInertia=500; 2410 to apply any changed default options on default selectors (below), use inside document ready fn 2411 e.g.: $(document).ready(function(){ $.mCustomScrollbar.defaults.scrollInertia=500; }); 2412 */ 2413 $[pluginNS].defaults=defaults; 2414 2415 /* 2416 add window object (window.mCustomScrollbar) 2417 usage: if(window.mCustomScrollbar){console.log("custom scrollbar plugin loaded");} 2418 */ 2419 window[pluginNS]=true; 2420 2421 $(window).bind("load",function(){ 2422 2423 $(defaultSelector)[pluginNS](); /* add scrollbars automatically on default selector */ 2424 2425 /* extend jQuery expressions */ 2426 $.extend($.expr[":"],{ 2427 /* checks if element is within scrollable viewport */ 2428 mcsInView:$.expr[":"].mcsInView || function(el){ 2429 var $el=$(el),content=$el.parents(".mCSB_container"),wrapper,cPos; 2430 if(!content.length){return;} 2431 wrapper=content.parent(); 2432 cPos=[content[0].offsetTop,content[0].offsetLeft]; 2433 return cPos[0]+_childPos($el)[0]>=0 && cPos[0]+_childPos($el)[0]<wrapper.height()-$el.outerHeight(false) && 2434 cPos[1]+_childPos($el)[1]>=0 && cPos[1]+_childPos($el)[1]<wrapper.width()-$el.outerWidth(false); 2435 }, 2436 /* checks if element or part of element is in view of scrollable viewport */ 2437 mcsInSight:$.expr[":"].mcsInSight || function(el,i,m){ 2438 var $el=$(el),elD,content=$el.parents(".mCSB_container"),wrapperView,pos,wrapperViewPct, 2439 pctVals=m[3]==="exact" ? [[1,0],[1,0]] : [[0.9,0.1],[0.6,0.4]]; 2440 if(!content.length){return;} 2441 elD=[$el.outerHeight(false),$el.outerWidth(false)]; 2442 pos=[content[0].offsetTop+_childPos($el)[0],content[0].offsetLeft+_childPos($el)[1]]; 2443 wrapperView=[content.parent()[0].offsetHeight,content.parent()[0].offsetWidth]; 2444 wrapperViewPct=[elD[0]<wrapperView[0] ? pctVals[0] : pctVals[1],elD[1]<wrapperView[1] ? pctVals[0] : pctVals[1]]; 2445 return pos[0]-(wrapperView[0]*wrapperViewPct[0][0])<0 && pos[0]+elD[0]-(wrapperView[0]*wrapperViewPct[0][1])>=0 && 2446 pos[1]-(wrapperView[1]*wrapperViewPct[1][0])<0 && pos[1]+elD[1]-(wrapperView[1]*wrapperViewPct[1][1])>=0; 2447 }, 2448 /* checks if element is overflowed having visible scrollbar(s) */ 2449 mcsOverflow:$.expr[":"].mcsOverflow || function(el){ 2450 var d=$(el).data(pluginPfx); 2451 if(!d){return;} 2452 return d.overflowed[0] || d.overflowed[1]; 2453 } 2454 }); 2455 2456 }); 2457 2458}))}));
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.