ok
Direktori : /home2/selectio/www/tnpsctestbatch.com/js/ |
Current File : /home2/selectio/www/tnpsctestbatch.com/js/jquery.scrollbar.js |
/** * jQuery CSS Customizable Scrollbar * * Copyright 2015, Yuriy Khabarov * Dual licensed under the MIT or GPL Version 2 licenses. * * If you found bug, please contact me via email <13real008@gmail.com> * * @author Yuriy Khabarov aka Gromo * @version 0.2.10 * @url https://github.com/gromo/jquery.scrollbar/ * */ ; (function (root, factory) { if (typeof define === 'function' && define.amd) { define(['jquery'], factory); } else { factory(root.jQuery); } }(this, function ($) { 'use strict'; // init flags & variables var debug = false; var browser = { data: { index: 0, name: 'scrollbar' }, macosx: /mac/i.test(navigator.platform), mobile: /android|webos|iphone|ipad|ipod|blackberry/i.test(navigator.userAgent), overlay: null, scroll: null, scrolls: [], webkit: /webkit/i.test(navigator.userAgent) && !/edge\/\d+/i.test(navigator.userAgent) }; browser.scrolls.add = function (instance) { this.remove(instance).push(instance); }; browser.scrolls.remove = function (instance) { while ($.inArray(instance, this) >= 0) { this.splice($.inArray(instance, this), 1); } return this; }; var defaults = { "autoScrollSize": true, // automatically calculate scrollsize "autoUpdate": true, // update scrollbar if content/container size changed "debug": false, // debug mode "disableBodyScroll": false, // disable body scroll if mouse over container "duration": 200, // scroll animate duration in ms "ignoreMobile": false, // ignore mobile devices "ignoreOverlay": false, // ignore browsers with overlay scrollbars (mobile, MacOS) "scrollStep": 30, // scroll step for scrollbar arrows "showArrows": false, // add class to show arrows "stepScrolling": true, // when scrolling to scrollbar mousedown position "scrollx": null, // horizontal scroll element "scrolly": null, // vertical scroll element "onDestroy": null, // callback function on destroy, "onInit": null, // callback function on first initialization "onScroll": null, // callback function on content scrolling "onUpdate": null // callback function on init/resize (before scrollbar size calculation) }; var BaseScrollbar = function (container) { if (!browser.scroll) { browser.overlay = isScrollOverlaysContent(); browser.scroll = getBrowserScrollSize(); updateScrollbars(); $(window).resize(function () { var forceUpdate = false; if (browser.scroll && (browser.scroll.height || browser.scroll.width)) { var scroll = getBrowserScrollSize(); if (scroll.height !== browser.scroll.height || scroll.width !== browser.scroll.width) { browser.scroll = scroll; forceUpdate = true; // handle page zoom } } updateScrollbars(forceUpdate); }); } this.container = container; this.namespace = '.scrollbar_' + browser.data.index++; this.options = $.extend({}, defaults, window.jQueryScrollbarOptions || {}); this.scrollTo = null; this.scrollx = {}; this.scrolly = {}; container.data(browser.data.name, this); browser.scrolls.add(this); }; BaseScrollbar.prototype = { destroy: function () { if (!this.wrapper) { return; } this.container.removeData(browser.data.name); browser.scrolls.remove(this); // init variables var scrollLeft = this.container.scrollLeft(); var scrollTop = this.container.scrollTop(); this.container.insertBefore(this.wrapper).css({ "height": "", "margin": "", "max-height": "" }) .removeClass('scroll-content scroll-scrollx_visible scroll-scrolly_visible') .off(this.namespace) .scrollLeft(scrollLeft) .scrollTop(scrollTop); this.scrollx.scroll.removeClass('scroll-scrollx_visible').find('div').andSelf().off(this.namespace); this.scrolly.scroll.removeClass('scroll-scrolly_visible').find('div').andSelf().off(this.namespace); this.wrapper.remove(); $(document).add('body').off(this.namespace); if ($.isFunction(this.options.onDestroy)){ this.options.onDestroy.apply(this, [this.container]); } }, init: function (options) { // init variables var S = this, c = this.container, cw = this.containerWrapper || c, namespace = this.namespace, o = $.extend(this.options, options || {}), s = {x: this.scrollx, y: this.scrolly}, w = this.wrapper; var initScroll = { "scrollLeft": c.scrollLeft(), "scrollTop": c.scrollTop() }; // do not init if in ignorable browser if ((browser.mobile && o.ignoreMobile) || (browser.overlay && o.ignoreOverlay) || (browser.macosx && !browser.webkit) // still required to ignore nonWebKit browsers on Mac ) { return false; } // init scroll container if (!w) { this.wrapper = w = $('<div>').addClass('scroll-wrapper').addClass(c.attr('class')) .css('position', c.css('position') == 'absolute' ? 'absolute' : 'relative') .insertBefore(c).append(c); if (c.is('textarea')) { this.containerWrapper = cw = $('<div>').insertBefore(c).append(c); w.addClass('scroll-textarea'); } cw.addClass('scroll-content').css({ "height": "auto", "margin-bottom": browser.scroll.height * -1 + 'px', "margin-right": browser.scroll.width * -1 + 'px', "max-height": "" }); c.on('scroll' + namespace, function (event) { if ($.isFunction(o.onScroll)) { o.onScroll.call(S, { "maxScroll": s.y.maxScrollOffset, "scroll": c.scrollTop(), "size": s.y.size, "visible": s.y.visible }, { "maxScroll": s.x.maxScrollOffset, "scroll": c.scrollLeft(), "size": s.x.size, "visible": s.x.visible }); } s.x.isVisible && s.x.scroll.bar.css('left', c.scrollLeft() * s.x.kx + 'px'); s.y.isVisible && s.y.scroll.bar.css('top', c.scrollTop() * s.y.kx + 'px'); }); /* prevent native scrollbars to be visible on #anchor click */ w.on('scroll' + namespace, function () { w.scrollTop(0).scrollLeft(0); }); if (o.disableBodyScroll) { var handleMouseScroll = function (event) { isVerticalScroll(event) ? s.y.isVisible && s.y.mousewheel(event) : s.x.isVisible && s.x.mousewheel(event); }; w.on('MozMousePixelScroll' + namespace, handleMouseScroll); w.on('mousewheel' + namespace, handleMouseScroll); if (browser.mobile) { w.on('touchstart' + namespace, function (event) { var touch = event.originalEvent.touches && event.originalEvent.touches[0] || event; var originalTouch = { "pageX": touch.pageX, "pageY": touch.pageY }; var originalScroll = { "left": c.scrollLeft(), "top": c.scrollTop() }; $(document).on('touchmove' + namespace, function (event) { var touch = event.originalEvent.targetTouches && event.originalEvent.targetTouches[0] || event; c.scrollLeft(originalScroll.left + originalTouch.pageX - touch.pageX); c.scrollTop(originalScroll.top + originalTouch.pageY - touch.pageY); event.preventDefault(); }); $(document).on('touchend' + namespace, function () { $(document).off(namespace); }); }); } } if ($.isFunction(o.onInit)){ o.onInit.apply(this, [c]); } } else { cw.css({ "height": "auto", "margin-bottom": browser.scroll.height * -1 + 'px', "margin-right": browser.scroll.width * -1 + 'px', "max-height": "" }); } // init scrollbars & recalculate sizes $.each(s, function (d, scrollx) { var scrollCallback = null; var scrollForward = 1; var scrollOffset = (d === 'x') ? 'scrollLeft' : 'scrollTop'; var scrollStep = o.scrollStep; var scrollTo = function () { var currentOffset = c[scrollOffset](); c[scrollOffset](currentOffset + scrollStep); if (scrollForward == 1 && (currentOffset + scrollStep) >= scrollToValue) currentOffset = c[scrollOffset](); if (scrollForward == -1 && (currentOffset + scrollStep) <= scrollToValue) currentOffset = c[scrollOffset](); if (c[scrollOffset]() == currentOffset && scrollCallback) { scrollCallback(); } } var scrollToValue = 0; if (!scrollx.scroll) { scrollx.scroll = S._getScroll(o['scroll' + d]).addClass('scroll-' + d); if(o.showArrows){ scrollx.scroll.addClass('scroll-element_arrows_visible'); } scrollx.mousewheel = function (event) { if (!scrollx.isVisible || (d === 'x' && isVerticalScroll(event))) { return true; } if (d === 'y' && !isVerticalScroll(event)) { s.x.mousewheel(event); return true; } var delta = event.originalEvent.wheelDelta * -1 || event.originalEvent.detail; var maxScrollValue = scrollx.size - scrollx.visible - scrollx.offset; if ((delta > 0 && scrollToValue < maxScrollValue) || (delta < 0 && scrollToValue > 0)) { scrollToValue = scrollToValue + delta; if (scrollToValue < 0) scrollToValue = 0; if (scrollToValue > maxScrollValue) scrollToValue = maxScrollValue; S.scrollTo = S.scrollTo || {}; S.scrollTo[scrollOffset] = scrollToValue; setTimeout(function () { if (S.scrollTo) { c.stop().animate(S.scrollTo, 240, 'linear', function () { scrollToValue = c[scrollOffset](); }); S.scrollTo = null; } }, 1); } event.preventDefault(); return false; }; scrollx.scroll .on('MozMousePixelScroll' + namespace, scrollx.mousewheel) .on('mousewheel' + namespace, scrollx.mousewheel) .on('mouseenter' + namespace, function () { scrollToValue = c[scrollOffset](); }); // handle arrows & scroll inner mousedown event scrollx.scroll.find('.scroll-arrow, .scroll-element_track') .on('mousedown' + namespace, function (event) { if (event.which != 1) // lmb return true; scrollForward = 1; var data = { "eventOffset": event[(d === 'x') ? 'pageX' : 'pageY'], "maxScrollValue": scrollx.size - scrollx.visible - scrollx.offset, "scrollbarOffset": scrollx.scroll.bar.offset()[(d === 'x') ? 'left' : 'top'], "scrollbarSize": scrollx.scroll.bar[(d === 'x') ? 'outerWidth' : 'outerHeight']() }; var timeout = 0, timer = 0; if ($(this).hasClass('scroll-arrow')) { scrollForward = $(this).hasClass("scroll-arrow_more") ? 1 : -1; scrollStep = o.scrollStep * scrollForward; scrollToValue = scrollForward > 0 ? data.maxScrollValue : 0; } else { scrollForward = (data.eventOffset > (data.scrollbarOffset + data.scrollbarSize) ? 1 : (data.eventOffset < data.scrollbarOffset ? -1 : 0)); scrollStep = Math.round(scrollx.visible * 0.75) * scrollForward; scrollToValue = (data.eventOffset - data.scrollbarOffset - (o.stepScrolling ? (scrollForward == 1 ? data.scrollbarSize : 0) : Math.round(data.scrollbarSize / 2))); scrollToValue = c[scrollOffset]() + (scrollToValue / scrollx.kx); } S.scrollTo = S.scrollTo || {}; S.scrollTo[scrollOffset] = o.stepScrolling ? c[scrollOffset]() + scrollStep : scrollToValue; if (o.stepScrolling) { scrollCallback = function () { scrollToValue = c[scrollOffset](); clearInterval(timer); clearTimeout(timeout); timeout = 0; timer = 0; }; timeout = setTimeout(function () { timer = setInterval(scrollTo, 40); }, o.duration + 100); } setTimeout(function () { if (S.scrollTo) { c.animate(S.scrollTo, o.duration); S.scrollTo = null; } }, 1); return S._handleMouseDown(scrollCallback, event); }); // handle scrollbar drag'n'drop scrollx.scroll.bar.on('mousedown' + namespace, function (event) { if (event.which != 1) // lmb return true; var eventPosition = event[(d === 'x') ? 'pageX' : 'pageY']; var initOffset = c[scrollOffset](); scrollx.scroll.addClass('scroll-draggable'); $(document).on('mousemove' + namespace, function (event) { var diff = parseInt((event[(d === 'x') ? 'pageX' : 'pageY'] - eventPosition) / scrollx.kx, 10); c[scrollOffset](initOffset + diff); }); return S._handleMouseDown(function () { scrollx.scroll.removeClass('scroll-draggable'); scrollToValue = c[scrollOffset](); }, event); }); } }); // remove classes & reset applied styles $.each(s, function (d, scrollx) { var scrollClass = 'scroll-scroll' + d + '_visible'; var scrolly = (d == "x") ? s.y : s.x; scrollx.scroll.removeClass(scrollClass); scrolly.scroll.removeClass(scrollClass); cw.removeClass(scrollClass); }); // calculate init sizes $.each(s, function (d, scrollx) { $.extend(scrollx, (d == "x") ? { "offset": parseInt(c.css('left'), 10) || 0, "size": c.prop('scrollWidth'), "visible": w.width() } : { "offset": parseInt(c.css('top'), 10) || 0, "size": c.prop('scrollHeight'), "visible": w.height() }); }); // update scrollbar visibility/dimensions this._updateScroll('x', this.scrollx); this._updateScroll('y', this.scrolly); if ($.isFunction(o.onUpdate)){ o.onUpdate.apply(this, [c]); } // calculate scroll size $.each(s, function (d, scrollx) { var cssOffset = (d === 'x') ? 'left' : 'top'; var cssFullSize = (d === 'x') ? 'outerWidth' : 'outerHeight'; var cssSize = (d === 'x') ? 'width' : 'height'; var offset = parseInt(c.css(cssOffset), 10) || 0; var AreaSize = scrollx.size; var AreaVisible = scrollx.visible + offset; var scrollSize = scrollx.scroll.size[cssFullSize]() + (parseInt(scrollx.scroll.size.css(cssOffset), 10) || 0); if (o.autoScrollSize) { scrollx.scrollbarSize = parseInt(scrollSize * AreaVisible / AreaSize, 10); scrollx.scroll.bar.css(cssSize, scrollx.scrollbarSize + 'px'); } scrollx.scrollbarSize = scrollx.scroll.bar[cssFullSize](); scrollx.kx = ((scrollSize - scrollx.scrollbarSize) / (AreaSize - AreaVisible)) || 1; scrollx.maxScrollOffset = AreaSize - AreaVisible; }); c.scrollLeft(initScroll.scrollLeft).scrollTop(initScroll.scrollTop).trigger('scroll'); }, /** * Get scrollx/scrolly object * * @param {Mixed} scroll * @returns {jQuery} scroll object */ _getScroll: function (scroll) { var types = { advanced: [ '<div class="scroll-element">', '<div class="scroll-element_corner"></div>', '<div class="scroll-arrow scroll-arrow_less"></div>', '<div class="scroll-arrow scroll-arrow_more"></div>', '<div class="scroll-element_outer">', '<div class="scroll-element_size"></div>', // required! used for scrollbar size calculation ! '<div class="scroll-element_inner-wrapper">', '<div class="scroll-element_inner scroll-element_track">', // used for handling scrollbar click '<div class="scroll-element_inner-bottom"></div>', '</div>', '</div>', '<div class="scroll-bar">', // required '<div class="scroll-bar_body">', '<div class="scroll-bar_body-inner"></div>', '</div>', '<div class="scroll-bar_bottom"></div>', '<div class="scroll-bar_center"></div>', '</div>', '</div>', '</div>' ].join(''), simple: [ '<div class="scroll-element">', '<div class="scroll-element_outer">', '<div class="scroll-element_size"></div>', // required! used for scrollbar size calculation ! '<div class="scroll-element_track"></div>', // used for handling scrollbar click '<div class="scroll-bar"></div>', // required '</div>', '</div>' ].join('') }; if (types[scroll]) { scroll = types[scroll]; } if (!scroll) { scroll = types['simple']; } if (typeof (scroll) == 'string') { scroll = $(scroll).appendTo(this.wrapper); } else { scroll = $(scroll); } $.extend(scroll, { bar: scroll.find('.scroll-bar'), size: scroll.find('.scroll-element_size'), track: scroll.find('.scroll-element_track') }); return scroll; }, _handleMouseDown: function(callback, event) { var namespace = this.namespace; $(document).on('blur' + namespace, function () { $(document).add('body').off(namespace); callback && callback(); }); $(document).on('dragstart' + namespace, function (event) { event.preventDefault(); return false; }); $(document).on('mouseup' + namespace, function () { $(document).add('body').off(namespace); callback && callback(); }); $('body').on('selectstart' + namespace, function (event) { event.preventDefault(); return false; }); event && event.preventDefault(); return false; }, _updateScroll: function (d, scrollx) { var container = this.container, containerWrapper = this.containerWrapper || container, scrollClass = 'scroll-scroll' + d + '_visible', scrolly = (d === 'x') ? this.scrolly : this.scrollx, offset = parseInt(this.container.css((d === 'x') ? 'left' : 'top'), 10) || 0, wrapper = this.wrapper; var AreaSize = scrollx.size; var AreaVisible = scrollx.visible + offset; scrollx.isVisible = (AreaSize - AreaVisible) > 1; // bug in IE9/11 with 1px diff if (scrollx.isVisible) { scrollx.scroll.addClass(scrollClass); scrolly.scroll.addClass(scrollClass); containerWrapper.addClass(scrollClass); } else { scrollx.scroll.removeClass(scrollClass); scrolly.scroll.removeClass(scrollClass); containerWrapper.removeClass(scrollClass); } if (d === 'y') { if(container.is('textarea') || AreaSize < AreaVisible){ containerWrapper.css({ "height": (AreaVisible + browser.scroll.height) + 'px', "max-height": "none" }); } else { containerWrapper.css({ //"height": "auto", // do not reset height value: issue with height:100%! "max-height": (AreaVisible + browser.scroll.height) + 'px' }); } } if (scrollx.size != container.prop('scrollWidth') || scrolly.size != container.prop('scrollHeight') || scrollx.visible != wrapper.width() || scrolly.visible != wrapper.height() || scrollx.offset != (parseInt(container.css('left'), 10) || 0) || scrolly.offset != (parseInt(container.css('top'), 10) || 0) ) { $.extend(this.scrollx, { "offset": parseInt(container.css('left'), 10) || 0, "size": container.prop('scrollWidth'), "visible": wrapper.width() }); $.extend(this.scrolly, { "offset": parseInt(container.css('top'), 10) || 0, "size": this.container.prop('scrollHeight'), "visible": wrapper.height() }); this._updateScroll(d === 'x' ? 'y' : 'x', scrolly); } } }; var CustomScrollbar = BaseScrollbar; /* * Extend jQuery as plugin * * @param {Mixed} command to execute * @param {Mixed} arguments as Array * @return {jQuery} */ $.fn.scrollbar = function (command, args) { if (typeof command !== 'string') { args = command; command = 'init'; } if (typeof args === 'undefined') { args = []; } if (!$.isArray(args)) { args = [args]; } this.not('body, .scroll-wrapper').each(function () { var element = $(this), instance = element.data(browser.data.name); if (instance || command === 'init') { if (!instance) { instance = new CustomScrollbar(element); } if (instance[command]) { instance[command].apply(instance, args); } } }); return this; }; /** * Connect default options to global object */ $.fn.scrollbar.options = defaults; /** * Check if scroll content/container size is changed */ var updateScrollbars = (function () { var timer = 0, timerCounter = 0; return function (force) { var i, container, options, scroll, wrapper, scrollx, scrolly; for (i = 0; i < browser.scrolls.length; i++) { scroll = browser.scrolls[i]; container = scroll.container; options = scroll.options; wrapper = scroll.wrapper; scrollx = scroll.scrollx; scrolly = scroll.scrolly; if (force || (options.autoUpdate && wrapper && wrapper.is(':visible') && (container.prop('scrollWidth') != scrollx.size || container.prop('scrollHeight') != scrolly.size || wrapper.width() != scrollx.visible || wrapper.height() != scrolly.visible))) { scroll.init(); if (options.debug) { window.console && console.log({ scrollHeight: container.prop('scrollHeight') + ':' + scroll.scrolly.size, scrollWidth: container.prop('scrollWidth') + ':' + scroll.scrollx.size, visibleHeight: wrapper.height() + ':' + scroll.scrolly.visible, visibleWidth: wrapper.width() + ':' + scroll.scrollx.visible }, true); timerCounter++; } } } if (debug && timerCounter > 10) { window.console && console.log('Scroll updates exceed 10'); updateScrollbars = function () {}; } else { clearTimeout(timer); timer = setTimeout(updateScrollbars, 300); } }; })(); /* ADDITIONAL FUNCTIONS */ /** * Get native browser scrollbar size (height/width) * * @param {Boolean} actual size or CSS size, default - CSS size * @returns {Object} with height, width */ function getBrowserScrollSize(actualSize) { if (browser.webkit && !actualSize) { return { "height": 0, "width": 0 }; } if (!browser.data.outer) { var css = { "border": "none", "box-sizing": "content-box", "height": "200px", "margin": "0", "padding": "0", "width": "200px" }; browser.data.inner = $("<div>").css($.extend({}, css)); browser.data.outer = $("<div>").css($.extend({ "left": "-1000px", "overflow": "scroll", "position": "absolute", "top": "-1000px" }, css)).append(browser.data.inner).appendTo("body"); } browser.data.outer.scrollLeft(1000).scrollTop(1000); return { "height": Math.ceil((browser.data.outer.offset().top - browser.data.inner.offset().top) || 0), "width": Math.ceil((browser.data.outer.offset().left - browser.data.inner.offset().left) || 0) }; } /** * Check if native browser scrollbars overlay content * * @returns {Boolean} */ function isScrollOverlaysContent() { var scrollSize = getBrowserScrollSize(true); return !(scrollSize.height || scrollSize.width); } function isVerticalScroll(event) { var e = event.originalEvent; if (e.axis && e.axis === e.HORIZONTAL_AXIS) return false; if (e.wheelDeltaX) return false; return true; } /** * Extend AngularJS as UI directive * and expose a provider for override default config * */ if (window.angular) { (function (angular) { angular.module('jQueryScrollbar', []) .provider('jQueryScrollbar', function () { var defaultOptions = defaults; return { setOptions: function (options) { angular.extend(defaultOptions, options); }, $get: function () { return { options: angular.copy(defaultOptions) }; } }; }) .directive('jqueryScrollbar', ['jQueryScrollbar', '$parse', function (jQueryScrollbar, $parse) { return { "restrict": "AC", "link": function (scope, element, attrs) { var model = $parse(attrs.jqueryScrollbar), options = model(scope); element.scrollbar(options || jQueryScrollbar.options) .on('$destroy', function () { element.scrollbar('destroy'); }); } }; }]); })(window.angular); } }));