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