(function ($) { /** * Augment jQuery prototype. */ $.fn.antiscroll = function (options) { return this.each(function () { if ($(this).data('antiscroll')) { $(this).data('antiscroll').destroy(); } $(this).data('antiscroll', new $.Antiscroll(this, options)); }); }; /** * Expose constructor. */ $.Antiscroll = Antiscroll; /** * Antiscroll pane constructor. * * @param {Element|jQuery} main pane * @parma {Object} options * @api public */ function Antiscroll (el, opts) { this.el = $(el); this.options = opts || {}; this.x = false !== this.options.x; this.y = false !== this.options.y; this.padding = undefined == this.options.padding ? 2 : this.options.padding; this.inner = this.el.find('.antiscroll-inner'); this.inner.css({ 'width': '+=' + scrollbarSize() , 'height': '+=' + scrollbarSize() }); this.refresh(); }; /** * refresh scrollbars * * @api public */ Antiscroll.prototype.refresh = function() { var needHScroll = this.inner.get(0).scrollWidth > this.el.width() , needVScroll = this.inner.get(0).scrollHeight > this.el.height(); if (!this.horizontal && needHScroll && this.x) { this.horizontal = new Scrollbar.Horizontal(this); } else if (this.horizontal && !needHScroll) { this.horizontal.destroy(); this.horizontal = null } if (!this.vertical && needVScroll && this.y) { this.vertical = new Scrollbar.Vertical(this); } else if (this.vertical && !needVScroll) { this.vertical.destroy(); this.vertical = null } }; /** * Cleans up. * * @return {Antiscroll} for chaining * @api public */ Antiscroll.prototype.destroy = function () { if (this.horizontal) { this.horizontal.destroy(); } if (this.vertical) { this.vertical.destroy(); } return this; }; /** * Rebuild Antiscroll. * * @return {Antiscroll} for chaining * @api public */ Antiscroll.prototype.rebuild = function () { this.destroy(); this.inner.attr('style', ''); Antiscroll.call(this, this.el, this.options); return this; }; /** * Scrollbar constructor. * * @param {Element|jQuery} element * @api public */ function Scrollbar (pane) { this.pane = pane; this.pane.el.append(this.el); this.innerEl = this.pane.inner.get(0); this.dragging = false; this.enter = false; this.shown = false; // hovering this.pane.el.mouseenter($.proxy(this, 'mouseenter')); this.pane.el.mouseleave($.proxy(this, 'mouseleave')); // dragging this.el.mousedown($.proxy(this, 'mousedown')); // scrolling this.pane.inner.scroll($.proxy(this, 'scroll')); // wheel -optional- this.pane.inner.bind('mousewheel', $.proxy(this, 'mousewheel')); // show var initialDisplay = this.pane.options.initialDisplay; if (initialDisplay !== false) { this.show(); this.hiding = setTimeout($.proxy(this, 'hide'), parseInt(initialDisplay, 10) || 3000); } }; /** * Cleans up. * * @return {Scrollbar} for chaining * @api public */ Scrollbar.prototype.destroy = function () { this.el.remove(); return this; }; /** * Called upon mouseenter. * * @api private */ Scrollbar.prototype.mouseenter = function () { this.enter = true; this.show(); }; /** * Called upon mouseleave. * * @api private */ Scrollbar.prototype.mouseleave = function () { this.enter = false; if (!this.dragging) { this.hide(); } } /** * Called upon wrap scroll. * * @api private */ Scrollbar.prototype.scroll = function () { if (!this.shown) { this.show(); if (!this.enter && !this.dragging) { this.hiding = setTimeout($.proxy(this, 'hide'), 1500); } } this.update(); }; /** * Called upon scrollbar mousedown. * * @api private */ Scrollbar.prototype.mousedown = function (ev) { ev.preventDefault(); this.dragging = true; this.startPageY = ev.pageY - parseInt(this.el.css('top'), 10); this.startPageX = ev.pageX - parseInt(this.el.css('left'), 10); // prevent crazy selections on IE document.onselectstart = function () { return false; }; var pane = this.pane , move = $.proxy(this, 'mousemove') , self = this $(document) .mousemove(move) .mouseup(function () { self.dragging = false; document.onselectstart = null; $(document).unbind('mousemove', move); if (!self.enter) { self.hide(); } }) }; /** * Show scrollbar. * * @api private */ Scrollbar.prototype.show = function (duration) { if (!this.shown) { this.update(); this.el.addClass('antiscroll-scrollbar-shown'); if (this.hiding) { clearTimeout(this.hiding); this.hiding = null; } this.shown = true; } }; /** * Hide scrollbar. * * @api private */ Scrollbar.prototype.hide = function () { var autoHide = this.pane.options.autoHide; if (autoHide !== false && this.shown) { // check for dragging this.el.removeClass('antiscroll-scrollbar-shown'); this.shown = false; } }; /** * Horizontal scrollbar constructor * * @api private */ Scrollbar.Horizontal = function (pane) { this.el = $('