PageSourceSearch

https://mfds.go.kr/js/www/jquery.scrollbar.js

js mfds.go.kr collected 2026-09-24 08:28:22 UTC 32,106 bytes, 780 lines download raw bytes

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.