vendor: 32,106 bytes, lines 1-780
1/** 2 * jQuery CSS Customizable Scrollbar 3 * 4 * Copyright 2015, Yuriy Khabarov 5 * Dual licensed under the MIT or GPL Version 2 licenses. 6 * 7 * 8 * @author Yuriy Khabarov aka Gromo 9 * @version 0.2.10 10 * @url https://github.com/gromo/jquery.scrollbar/ 11 * 12 */ 13; 14(function (root, factory) { 15 if (typeof define === 'function' && define.amd) { 16 define(['jquery'], factory); 17 } else { 18 factory(root.jQuery); 19 } 20}(this, function ($) { 21 'use strict'; 22 23 // init flags & variables 24 var debug = false; 25 26 var browser = { 27 data: { 28 index: 0, 29 name: 'scrollbar' 30 }, 31 macosx: /mac/i.test(navigator.platform), 32 mobile: /android|webos|iphone|ipad|ipod|blackberry/i.test(navigator.userAgent), 33 overlay: null, 34 scroll: null, 35 scrolls: [], 36 webkit: /webkit/i.test(navigator.userAgent) && !/edge\/\d+/i.test(navigator.userAgent) 37 }; 38 39 browser.scrolls.add = function (instance) { 40 this.remove(instance).push(instance); 41 }; 42 browser.scrolls.remove = function (instance) { 43 while ($.inArray(instance, this) >= 0) { 44 this.splice($.inArray(instance, this), 1); 45 } 46 return this; 47 }; 48 49 var defaults = { 50 "autoScrollSize": true, // automatically calculate scrollsize 51 "autoUpdate": true, // update scrollbar if content/container size changed 52 "debug": false, // debug mode 53 "disableBodyScroll": false, // disable body scroll if mouse over container 54 "duration": 200, // scroll animate duration in ms 55 "ignoreMobile": false, // ignore mobile devices 56 "ignoreOverlay": false, // ignore browsers with overlay scrollbars (mobile, MacOS) 57 "scrollStep": 30, // scroll step for scrollbar arrows 58 "showArrows": false, // add class to show arrows 59 "stepScrolling": true, // when scrolling to scrollbar mousedown position 60 61 "scrollx": null, // horizontal scroll element 62 "scrolly": null, // vertical scroll element 63 64 "onDestroy": null, // callback function on destroy, 65 "onInit": null, // callback function on first initialization 66 "onScroll": null, // callback function on content scrolling 67 "onUpdate": null // callback function on init/resize (before scrollbar size calculation) 68 }; 69 70 71 var BaseScrollbar = function (container) { 72 73 if (!browser.scroll) { 74 browser.overlay = isScrollOverlaysContent(); 75 browser.scroll = getBrowserScrollSize(); 76 updateScrollbars(); 77 78 $(window).resize(function () { 79 var forceUpdate = false; 80 if (browser.scroll && (browser.scroll.height || browser.scroll.width)) { 81 var scroll = getBrowserScrollSize(); 82 if (scroll.height !== browser.scroll.height || scroll.width !== browser.scroll.width) { 83 browser.scroll = scroll; 84 forceUpdate = true; // handle page zoom 85 } 86 } 87 updateScrollbars(forceUpdate); 88 }); 89 } 90 91 this.container = container; 92 this.namespace = '.scrollbar_' + browser.data.index++; 93 this.options = $.extend({}, defaults, window.jQueryScrollbarOptions || {}); 94 this.scrollTo = null; 95 this.scrollx = {}; 96 this.scrolly = {}; 97 98 container.data(browser.data.name, this); 99 browser.scrolls.add(this); 100 }; 101 102 BaseScrollbar.prototype = { 103 104 destroy: function () { 105 106 if (!this.wrapper) { 107 return; 108 } 109 110 this.container.removeData(browser.data.name); 111 browser.scrolls.remove(this); 112 113 // init variables 114 var scrollLeft = this.container.scrollLeft(); 115 var scrollTop = this.container.scrollTop(); 116 117 this.container.insertBefore(this.wrapper).css({ 118 "height": "", 119 "margin": "", 120 "max-height": "" 121 }) 122 .removeClass('scroll-content scroll-scrollx_visible scroll-scrolly_visible') 123 .off(this.namespace) 124 .scrollLeft(scrollLeft) 125 .scrollTop(scrollTop); 126 127 this.scrollx.scroll.removeClass('scroll-scrollx_visible').find('div').addBack().off(this.namespace); 128 this.scrolly.scroll.removeClass('scroll-scrolly_visible').find('div').addBack().off(this.namespace); 129 130 this.wrapper.remove(); 131 132 $(document).add('body').off(this.namespace); 133 134 if ($.isFunction(this.options.onDestroy)){ 135 this.options.onDestroy.apply(this, [this.container]); 136 } 137 }, 138 init: function (options) { 139 140 // init variables 141 var S = this, 142 c = this.container, 143 cw = this.containerWrapper || c, 144 namespace = this.namespace, 145 o = $.extend(this.options, options || {}), 146 s = {x: this.scrollx, y: this.scrolly}, 147 w = this.wrapper; 148 149 var initScroll = { 150 "scrollLeft": c.scrollLeft(), 151 "scrollTop": c.scrollTop() 152 }; 153 154 // do not init if in ignorable browser 155 if ((browser.mobile && o.ignoreMobile) 156 || (browser.overlay && o.ignoreOverlay) 157 || (browser.macosx && !browser.webkit) // still required to ignore nonWebKit browsers on Mac 158 ) { 159 return false; 160 } 161 162 // init scroll container 163 if (!w) { 164 this.wrapper = w = $('<div>').addClass('scroll-wrapper').addClass(c.attr('class')) 165 //.css('position', c.css('position') == 'absolute' ? 'absolute' : 'relative') 166 .insertBefore(c).append(c); 167 168 if (c.is('textarea')) { 169 this.containerWrapper = cw = $('<div>').insertBefore(c).append(c); 170 w.addClass('scroll-textarea'); 171 } 172 173 cw.addClass('scroll-content').css({ 174 "height": "auto", 175 "margin-bottom": browser.scroll.height * -1 + 'px', 176 "margin-right": browser.scroll.width * -1 + 'px', 177 "max-height": "" 178 }); 179 180 c.on('scroll' + namespace, function (event) { 181 if ($.isFunction(o.onScroll)) { 182 o.onScroll.call(S, { 183 "maxScroll": s.y.maxScrollOffset, 184 "scroll": c.scrollTop(), 185 "size": s.y.size, 186 "visible": s.y.visible 187 }, { 188 "maxScroll": s.x.maxScrollOffset, 189 "scroll": c.scrollLeft(), 190 "size": s.x.size, 191 "visible": s.x.visible 192 }); 193 } 194 s.x.isVisible && s.x.scroll.bar.css('left', c.scrollLeft() * s.x.kx + 'px'); 195 s.y.isVisible && s.y.scroll.bar.css('top', c.scrollTop() * s.y.kx + 'px'); 196 }); 197 198 /* prevent native scrollbars to be visible on #anchor click */ 199 w.on('scroll' + namespace, function () { 200 w.scrollTop(0).scrollLeft(0); 201 }); 202 203 if (o.disableBodyScroll) { 204 var handleMouseScroll = function (event) { 205 isVerticalScroll(event) ? 206 s.y.isVisible && s.y.mousewheel(event) : 207 s.x.isVisible && s.x.mousewheel(event); 208 }; 209 w.on('MozMousePixelScroll' + namespace, handleMouseScroll); 210 w.on('mousewheel' + namespace, handleMouseScroll); 211 212 if (browser.mobile) { 213 w.on('touchstart' + namespace, function (event) { 214 var touch = event.originalEvent.touches && event.originalEvent.touches[0] || event; 215 var originalTouch = { 216 "pageX": touch.pageX, 217 "pageY": touch.pageY 218 }; 219 var originalScroll = { 220 "left": c.scrollLeft(), 221 "top": c.scrollTop() 222 }; 223 $(document).on('touchmove' + namespace, function (event) { 224 var touch = event.originalEvent.targetTouches && event.originalEvent.targetTouches[0] || event; 225 c.scrollLeft(originalScroll.left + originalTouch.pageX - touch.pageX); 226 c.scrollTop(originalScroll.top + originalTouch.pageY - touch.pageY); 227 event.preventDefault(); 228 }); 229 $(document).on('touchend' + namespace, function () { 230 $(document).off(namespace); 231 }); 232 }); 233 } 234 } 235 if ($.isFunction(o.onInit)){ 236 o.onInit.apply(this, [c]); 237 } 238 } else { 239 cw.css({ 240 "height": "auto", 241 "margin-bottom": browser.scroll.height * -1 + 'px', 242 "margin-right": browser.scroll.width * -1 + 'px', 243 "max-height": "" 244 }); 245 } 246 247 // init scrollbars & recalculate sizes 248 $.each(s, function (d, scrollx) { 249 250 var scrollCallback = null; 251 var scrollForward = 1; 252 var scrollOffset = (d === 'x') ? 'scrollLeft' : 'scrollTop'; 253 var scrollStep = o.scrollStep; 254 var scrollTo = function () { 255 var currentOffset = c[scrollOffset](); 256 c[scrollOffset](currentOffset + scrollStep); 257 if (scrollForward == 1 && (currentOffset + scrollStep) >= scrollToValue) 258 currentOffset = c[scrollOffset](); 259 if (scrollForward == -1 && (currentOffset + scrollStep) <= scrollToValue) 260 currentOffset = c[scrollOffset](); 261 if (c[scrollOffset]() == currentOffset && scrollCallback) { 262 scrollCallback(); 263 } 264 } 265 var scrollToValue = 0; 266 267 if (!scrollx.scroll) { 268 269 scrollx.scroll = S._getScroll(o['scroll' + d]).addClass('scroll-' + d); 270 271 if(o.showArrows){ 272 scrollx.scroll.addClass('scroll-element_arrows_visible'); 273 } 274 275 scrollx.mousewheel = function (event) { 276 277 if (!scrollx.isVisible || (d === 'x' && isVerticalScroll(event))) { 278 return true; 279 } 280 if (d === 'y' && !isVerticalScroll(event)) { 281 s.x.mousewheel(event); 282 return true; 283 } 284 285 var delta = event.originalEvent.wheelDelta * -1 || event.originalEvent.detail; 286 var maxScrollValue = scrollx.size - scrollx.visible - scrollx.offset; 287 288 if ((delta > 0 && scrollToValue < maxScrollValue) || (delta < 0 && scrollToValue > 0)) { 289 scrollToValue = scrollToValue + delta; 290 if (scrollToValue < 0) 291 scrollToValue = 0; 292 if (scrollToValue > maxScrollValue) 293 scrollToValue = maxScrollValue; 294 295 S.scrollTo = S.scrollTo || {}; 296 S.scrollTo[scrollOffset] = scrollToValue; 297 setTimeout(function () { 298 if (S.scrollTo) { 299 c.stop().animate(S.scrollTo, 240, 'linear', function () { 300 scrollToValue = c[scrollOffset](); 301 }); 302 S.scrollTo = null; 303 } 304 }, 1); 305 } 306 307 event.preventDefault(); 308 return false; 309 }; 310 311 scrollx.scroll 312 .on('MozMousePixelScroll' + namespace, scrollx.mousewheel) 313 .on('mousewheel' + namespace, scrollx.mousewheel) 314 .on('mouseenter' + namespace, function () { 315 scrollToValue = c[scrollOffset](); 316 }); 317 318 // handle arrows & scroll inner mousedown event 319 scrollx.scroll.find('.scroll-arrow, .scroll-element_track') 320 .on('mousedown' + namespace, function (event) { 321 322 if (event.which != 1) // lmb 323 return true; 324 325 scrollForward = 1; 326 327 var data = { 328 "eventOffset": event[(d === 'x') ? 'pageX' : 'pageY'], 329 "maxScrollValue": scrollx.size - scrollx.visible - scrollx.offset, 330 "scrollbarOffset": scrollx.scroll.bar.offset()[(d === 'x') ? 'left' : 'top'], 331 "scrollbarSize": scrollx.scroll.bar[(d === 'x') ? 'outerWidth' : 'outerHeight']() 332 }; 333 var timeout = 0, timer = 0; 334 335 if ($(this).hasClass('scroll-arrow')) { 336 scrollForward = $(this).hasClass("scroll-arrow_more") ? 1 : -1; 337 scrollStep = o.scrollStep * scrollForward; 338 scrollToValue = scrollForward > 0 ? data.maxScrollValue : 0; 339 } else { 340 scrollForward = (data.eventOffset > (data.scrollbarOffset + data.scrollbarSize) ? 1 341 : (data.eventOffset < data.scrollbarOffset ? -1 : 0)); 342 scrollStep = Math.round(scrollx.visible * 0.75) * scrollForward; 343 scrollToValue = (data.eventOffset - data.scrollbarOffset - 344 (o.stepScrolling ? (scrollForward == 1 ? data.scrollbarSize : 0) 345 : Math.round(data.scrollbarSize / 2))); 346 scrollToValue = c[scrollOffset]() + (scrollToValue / scrollx.kx); 347 } 348 349 S.scrollTo = S.scrollTo || {}; 350 S.scrollTo[scrollOffset] = o.stepScrolling ? c[scrollOffset]() + scrollStep : scrollToValue; 351 352 if (o.stepScrolling) { 353 scrollCallback = function () { 354 scrollToValue = c[scrollOffset](); 355 clearInterval(timer); 356 clearTimeout(timeout); 357 timeout = 0; 358 timer = 0; 359 }; 360 timeout = setTimeout(function () { 361 timer = setInterval(scrollTo, 40); 362 }, o.duration + 100); 363 } 364 365 setTimeout(function () { 366 if (S.scrollTo) { 367 c.animate(S.scrollTo, o.duration); 368 S.scrollTo = null; 369 } 370 }, 1); 371 372 return S._handleMouseDown(scrollCallback, event); 373 }); 374 375 // handle scrollbar drag'n'drop 376 scrollx.scroll.bar.on('mousedown' + namespace, function (event) { 377 378 if (event.which != 1) // lmb 379 return true; 380 381 var eventPosition = event[(d === 'x') ? 'pageX' : 'pageY']; 382 var initOffset = c[scrollOffset](); 383 384 scrollx.scroll.addClass('scroll-draggable'); 385 386 $(document).on('mousemove' + namespace, function (event) { 387 var diff = parseInt((event[(d === 'x') ? 'pageX' : 'pageY'] - eventPosition) / scrollx.kx, 10); 388 c[scrollOffset](initOffset + diff); 389 }); 390 391 return S._handleMouseDown(function () { 392 scrollx.scroll.removeClass('scroll-draggable'); 393 scrollToValue = c[scrollOffset](); 394 }, event); 395 }); 396 } 397 }); 398 399 // remove classes & reset applied styles 400 $.each(s, function (d, scrollx) { 401 var scrollClass = 'scroll-scroll' + d + '_visible'; 402 var scrolly = (d == "x") ? s.y : s.x; 403 404 scrollx.scroll.removeClass(scrollClass); 405 scrolly.scroll.removeClass(scrollClass); 406 cw.removeClass(scrollClass); 407 }); 408 409 // calculate init sizes 410 $.each(s, function (d, scrollx) { 411 $.extend(scrollx, (d == "x") ? { 412 "offset": parseInt(c.css('left'), 10) || 0, 413 "size": c.prop('scrollWidth'), 414 "visible": w.width() 415 } : { 416 "offset": parseInt(c.css('top'), 10) || 0, 417 "size": c.prop('scrollHeight'), 418 "visible": w.height() 419 }); 420 }); 421 422 // update scrollbar visibility/dimensions 423 this._updateScroll('x', this.scrollx); 424 this._updateScroll('y', this.scrolly); 425 426 if ($.isFunction(o.onUpdate)){ 427 o.onUpdate.apply(this, [c]); 428 } 429 430 // calculate scroll size 431 $.each(s, function (d, scrollx) { 432 433 var cssOffset = (d === 'x') ? 'left' : 'top'; 434 var cssFullSize = (d === 'x') ? 'outerWidth' : 'outerHeight'; 435 var cssSize = (d === 'x') ? 'width' : 'height'; 436 var offset = parseInt(c.css(cssOffset), 10) || 0; 437 438 var AreaSize = scrollx.size; 439 var AreaVisible = scrollx.visible + offset; 440 441 var scrollSize = scrollx.scroll.size[cssFullSize]() + (parseInt(scrollx.scroll.size.css(cssOffset), 10) || 0); 442 443 if (o.autoScrollSize) { 444 scrollx.scrollbarSize = parseInt(scrollSize * AreaVisible / AreaSize, 10); 445 scrollx.scroll.bar.css(cssSize, scrollx.scrollbarSize + 'px'); 446 } 447 448 scrollx.scrollbarSize = scrollx.scroll.bar[cssFullSize](); 449 scrollx.kx = ((scrollSize - scrollx.scrollbarSize) / (AreaSize - AreaVisible)) || 1; 450 scrollx.maxScrollOffset = AreaSize - AreaVisible; 451 }); 452 453 c.scrollLeft(initScroll.scrollLeft).scrollTop(initScroll.scrollTop).trigger('scroll'); 454 }, 455 456 /** 457 * Get scrollx/scrolly object 458 * 459 * @param {Mixed} scroll 460 * @returns {jQuery} scroll object 461 */ 462 _getScroll: function (scroll) { 463 var types = { 464 advanced: [ 465 '<div class="scroll-element">', 466 '<div class="scroll-element_corner"></div>', 467 '<div class="scroll-arrow scroll-arrow_less"></div>', 468 '<div class="scroll-arrow scroll-arrow_more"></div>', 469 '<div class="scroll-element_outer">', 470 '<div class="scroll-element_size"></div>', // required! used for scrollbar size calculation ! 471 '<div class="scroll-element_inner-wrapper">', 472 '<div class="scroll-element_inner scroll-element_track">', // used for handling scrollbar click 473 '<div class="scroll-element_inner-bottom"></div>', 474 '</div>', 475 '</div>', 476 '<div class="scroll-bar">', // required 477 '<div class="scroll-bar_body">', 478 '<div class="scroll-bar_body-inner"></div>', 479 '</div>', 480 '<div class="scroll-bar_bottom"></div>', 481 '<div class="scroll-bar_center"></div>', 482 '</div>', 483 '</div>', 484 '</div>' 485 ].join(''), 486 simple: [ 487 '<div class="scroll-element">', 488 '<div class="scroll-element_outer">', 489 '<div class="scroll-element_size"></div>', // required! used for scrollbar size calculation ! 490 '<div class="scroll-element_track"></div>', // used for handling scrollbar click 491 '<div class="scroll-bar"></div>', // required 492 '</div>', 493 '</div>' 494 ].join('') 495 }; 496 if (types[scroll]) { 497 scroll = types[scroll]; 498 } 499 if (!scroll) { 500 scroll = types['simple']; 501 } 502 if (typeof (scroll) == 'string') { 503 scroll = $(scroll).appendTo(this.wrapper); 504 } else { 505 scroll = $(scroll); 506 } 507 $.extend(scroll, { 508 bar: scroll.find('.scroll-bar'), 509 size: scroll.find('.scroll-element_size'), 510 track: scroll.find('.scroll-element_track') 511 }); 512 return scroll; 513 }, 514 515 _handleMouseDown: function(callback, event) { 516 517 var namespace = this.namespace; 518 519 $(document).on('blur' + namespace, function () { 520 $(document).add('body').off(namespace); 521 callback && callback(); 522 }); 523 $(document).on('dragstart' + namespace, function (event) { 524 event.preventDefault(); 525 return false; 526 }); 527 $(document).on('mouseup' + namespace, function () { 528 $(document).add('body').off(namespace); 529 callback && callback(); 530 }); 531 $('body').on('selectstart' + namespace, function (event) { 532 event.preventDefault(); 533 return false; 534 }); 535 536 event && event.preventDefault(); 537 return false; 538 }, 539 540 _updateScroll: function (d, scrollx) { 541 542 var container = this.container, 543 containerWrapper = this.containerWrapper || container, 544 scrollClass = 'scroll-scroll' + d + '_visible', 545 scrolly = (d === 'x') ? this.scrolly : this.scrollx, 546 offset = parseInt(this.container.css((d === 'x') ? 'left' : 'top'), 10) || 0, 547 wrapper = this.wrapper; 548 549 var AreaSize = scrollx.size; 550 var AreaVisible = scrollx.visible + offset; 551 552 scrollx.isVisible = (AreaSize - AreaVisible) > 1; // bug in IE9/11 with 1px diff 553 if (scrollx.isVisible) { 554 scrollx.scroll.addClass(scrollClass); 555 scrolly.scroll.addClass(scrollClass); 556 containerWrapper.addClass(scrollClass); 557 } else { 558 scrollx.scroll.removeClass(scrollClass); 559 scrolly.scroll.removeClass(scrollClass); 560 containerWrapper.removeClass(scrollClass); 561 } 562 563 if (d === 'y') { 564 if(container.is('textarea') || AreaSize < AreaVisible){ 565 containerWrapper.css({ 566 "height": (AreaVisible + browser.scroll.height) + 'px', 567 "max-height": "none" 568 }); 569 } else { 570 containerWrapper.css({ 571 //"height": "auto", // do not reset height value: issue with height:100%! 572 "max-height": (AreaVisible + browser.scroll.height) + 'px' 573 }); 574 } 575 } 576 577 if (scrollx.size != container.prop('scrollWidth') 578 || scrolly.size != container.prop('scrollHeight') 579 || scrollx.visible != wrapper.width() 580 || scrolly.visible != wrapper.height() 581 || scrollx.offset != (parseInt(container.css('left'), 10) || 0) 582 || scrolly.offset != (parseInt(container.css('top'), 10) || 0) 583 ) { 584 $.extend(this.scrollx, { 585 "offset": parseInt(container.css('left'), 10) || 0, 586 "size": container.prop('scrollWidth'), 587 "visible": wrapper.width() 588 }); 589 $.extend(this.scrolly, { 590 "offset": parseInt(container.css('top'), 10) || 0, 591 "size": this.container.prop('scrollHeight'), 592 "visible": wrapper.height() 593 }); 594 this._updateScroll(d === 'x' ? 'y' : 'x', scrolly); 595 } 596 } 597 }; 598 599 var CustomScrollbar = BaseScrollbar; 600 601 /* 602 * Extend jQuery as plugin 603 * 604 * @param {Mixed} command to execute 605 * @param {Mixed} arguments as Array 606 * @return {jQuery} 607 */ 608 $.fn.scrollbar = function (command, args) { 609 if (typeof command !== 'string') { 610 args = command; 611 command = 'init'; 612 } 613 if (typeof args === 'undefined') { 614 args = []; 615 } 616 if (!Array.isArray(args)) { 617 args = [args]; 618 } 619 this.not('body, .scroll-wrapper').each(function () { 620 var element = $(this), 621 instance = element.data(browser.data.name); 622 if (instance || command === 'init') { 623 if (!instance) { 624 instance = new CustomScrollbar(element); 625 } 626 if (instance[command]) { 627 instance[command].apply(instance, args); 628 } 629 } 630 }); 631 return this; 632 }; 633 634 /** 635 * Connect default options to global object 636 */ 637 $.fn.scrollbar.options = defaults; 638 639 640 /** 641 * Check if scroll content/container size is changed 642 */ 643 644 var updateScrollbars = (function () { 645 var timer = 0, 646 timerCounter = 0; 647 648 return function (force) { 649 var i, container, options, scroll, wrapper, scrollx, scrolly; 650 for (i = 0; i < browser.scrolls.length; i++) { 651 scroll = browser.scrolls[i]; 652 container = scroll.container; 653 options = scroll.options; 654 wrapper = scroll.wrapper; 655 scrollx = scroll.scrollx; 656 scrolly = scroll.scrolly; 657 if (force || (options.autoUpdate && wrapper && wrapper.is(':visible') && 658 (container.prop('scrollWidth') != scrollx.size || container.prop('scrollHeight') != scrolly.size || wrapper.width() != scrollx.visible || wrapper.height() != scrolly.visible))) { 659 scroll.init(); 660 661 if (options.debug) { 662 window.console && console.log({ 663 scrollHeight: container.prop('scrollHeight') + ':' + scroll.scrolly.size, 664 scrollWidth: container.prop('scrollWidth') + ':' + scroll.scrollx.size, 665 visibleHeight: wrapper.height() + ':' + scroll.scrolly.visible, 666 visibleWidth: wrapper.width() + ':' + scroll.scrollx.visible 667 }, true); 668 timerCounter++; 669 } 670 } 671 } 672 if (debug && timerCounter > 10) { 673 window.console && console.log('Scroll updates exceed 10'); 674 updateScrollbars = function () {}; 675 } else { 676 clearTimeout(timer); 677 timer = setTimeout(updateScrollbars, 300); 678 } 679 }; 680 })(); 681 682 /* ADDITIONAL FUNCTIONS */ 683 /** 684 * Get native browser scrollbar size (height/width) 685 * 686 * @param {Boolean} actual size or CSS size, default - CSS size 687 * @returns {Object} with height, width 688 */ 689 function getBrowserScrollSize(actualSize) { 690 691 if (browser.webkit && !actualSize) { 692 return { 693 "height": 0, 694 "width": 0 695 }; 696 } 697 698 if (!browser.data.outer) { 699 var css = { 700 "border": "none", 701 "box-sizing": "content-box", 702 "height": "200px", 703 "margin": "0", 704 "padding": "0", 705 "width": "200px" 706 }; 707 browser.data.inner = $("<div>").css($.extend({}, css)); 708 browser.data.outer = $("<div>").css($.extend({ 709 "left": "-1000px", 710 "overflow": "scroll", 711 "position": "absolute", 712 "top": "-1000px" 713 }, css)).append(browser.data.inner).appendTo("body"); 714 } 715 716 browser.data.outer.scrollLeft(1000).scrollTop(1000); 717 718 return { 719 "height": Math.ceil((browser.data.outer.offset().top - browser.data.inner.offset().top) || 0), 720 "width": Math.ceil((browser.data.outer.offset().left - browser.data.inner.offset().left) || 0) 721 }; 722 } 723 724 /** 725 * Check if native browser scrollbars overlay content 726 * 727 * @returns {Boolean} 728 */ 729 function isScrollOverlaysContent() { 730 var scrollSize = getBrowserScrollSize(true); 731 return !(scrollSize.height || scrollSize.width); 732 } 733 734 function isVerticalScroll(event) { 735 var e = event.originalEvent; 736 if (e.axis && e.axis === e.HORIZONTAL_AXIS) 737 return false; 738 if (e.wheelDeltaX) 739 return false; 740 return true; 741 } 742 743 744 /** 745 * Extend AngularJS as UI directive 746 * and expose a provider for override default config 747 * 748 */ 749 if (window.angular) { 750 (function (angular) { 751 angular.module('jQueryScrollbar', []) 752 .provider('jQueryScrollbar', function () { 753 var defaultOptions = defaults; 754 return { 755 setOptions: function (options) { 756 angular.extend(defaultOptions, options); 757 }, 758 $get: function () { 759 return { 760 options: angular.copy(defaultOptions) 761 }; 762 } 763 }; 764 }) 765 .directive('jqueryScrollbar', ['jQueryScrollbar', '$parse', function (jQueryScrollbar, $parse) { 766 return { 767 "restrict": "AC", 768 "link": function (scope, element, attrs) { 769 var model = $parse(attrs.jqueryScrollbar), 770 options = model(scope); 771 element.scrollbar(options || jQueryScrollbar.options) 772 .on('$destroy', function () { 773 element.scrollbar('destroy'); 774 }); 775 } 776 }; 777 }]); 778 })(window.angular); 779 } 780}));
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.