/ajax/libs/jScrollPane/2.0.0beta3/script/jquery.jscrollpane.js
JavaScript | 1061 lines | 805 code | 117 blank | 139 comment | 133 complexity | 6914d006be814b2e00c14339dd375ebe MD5 | raw file
- /*!
- * jScrollPane - v2.0.0beta3 - 2010-08-27
- * http://jscrollpane.kelvinluck.com/
- *
- * Copyright (c) 2010 Kelvin Luck
- * Dual licensed under the MIT and GPL licenses.
- */
- // Script: jScrollPane - cross browser customisable scrollbars
- //
- // *Version: 2.0.0beta3, Last updated: 2010-08-27*
- //
- // Project Home - http://jscrollpane.kelvinluck.com/
- // GitHub - http://github.com/vitch/jScrollPane
- // Source - http://github.com/vitch/jScrollPane/raw/master/script/jquery.jscrollpane.js
- // (Minified) - http://github.com/vitch/jScrollPane/raw/master/script/jquery.jscrollpane.min.js
- //
- // About: License
- //
- // Copyright (c) 2010 Kelvin Luck
- // Dual licensed under the MIT or GPL Version 2 licenses.
- // http://jscrollpane.kelvinluck.com/MIT-LICENSE.txt
- // http://jscrollpane.kelvinluck.com/GPL-LICENSE.txt
- //
- // About: Examples
- //
- // All examples and demos are available through the jScrollPane example site at:
- // http://jscrollpane.kelvinluck.com/
- //
- // About: Support and Testing
- //
- // This plugin is tested on the browsers below and has been found to work reliably on them. If you run
- // into a problem on one of the supported browsers then please visit the support section on the jScrollPane
- // website (http://jscrollpane.kelvinluck.com/) for more information on getting support. You are also
- // welcome to fork the project on GitHub if you can contribute a fix for a given issue.
- //
- // jQuery Versions - 1.4.2
- // Browsers Tested - Firefox 3.6.8, Safari 5, Opera 10.6, Chrome 5.0, IE 6, 7, 8
- //
- // About: Release History
- //
- // 2.0.0beta3 - (2010-08-27) Horizontal mousewheel, mwheelIntent, keyboard support, bug fixes
- // 2.0.0beta2 - (2010-08-21) Bug fixes
- // 2.0.0beta1 - (2010-08-17) Rewrite to follow modern best practices and enable horizontal scrolling, initially hidden
- // elements and dynamically sized elements.
- // 1.x - (2006-12-31 - 2010-07-31) Initial version, hosted at googlecode, deprecated
- (function($,window,undefined){
- $.fn.jScrollPane = function(settings)
- {
- // JScrollPane "class" - public methods are available through $('selector').data('jsp')
- function JScrollPane(elem, s)
- {
- var settings, jsp = this, pane, paneWidth, paneHeight, container, contentWidth, contentHeight,
- percentInViewH, percentInViewV, isScrollableV, isScrollableH, verticalDrag, dragMaxY,
- verticalDragPosition, horizontalDrag, dragMaxX, horizontalDragPosition,
- verticalBar, verticalTrack, scrollbarWidth, verticalTrackHeight, verticalDragHeight, arrowUp, arrowDown,
- horizontalBar, horizontalTrack, horizontalTrackWidth, horizontalDragWidth, arrowLeft, arrowRight,
- reinitialiseInterval, originalPadding, originalPaddingTotalWidth, previousPaneWidth,
- wasAtTop = true, wasAtLeft = true, wasAtBottom = false, wasAtRight = false,
- mwEvent = $.fn.mwheelIntent ? 'mwheelIntent.jsp' : 'mousewheel.jsp';
- originalPadding = elem.css('paddingTop') + ' ' +
- elem.css('paddingRight') + ' ' +
- elem.css('paddingBottom') + ' ' +
- elem.css('paddingLeft');
- originalPaddingTotalWidth = (parseInt(elem.css('paddingLeft')) || 0) +
- (parseInt(elem.css('paddingRight')) || 0);
- initialise(s);
- function initialise(s)
- {
- var clonedElem, tempWrapper, /*firstChild, lastChild, */isMaintainingPositon, lastContentX, lastContentY,
- hasContainingSpaceChanged;
- settings = s;
- if (pane == undefined) {
- elem.css(
- {
- 'overflow': 'hidden',
- 'padding': 0
- }
- );
- // TODO: Deal with where width/ height is 0 as it probably means the element is hidden and we should
- // come back to it later and check once it is unhidden...
- paneWidth = elem.innerWidth() + originalPaddingTotalWidth;
- paneHeight = elem.innerHeight();
- elem.width(paneWidth);
-
- pane = $('<div class="jspPane" />').wrap(
- $('<div class="jspContainer" />')
- .css({
- 'width': paneWidth + 'px',
- 'height': paneHeight + 'px'
- }
- )
- );
- elem.wrapInner(pane.parent());
- // Need to get the vars after being added to the document, otherwise they reference weird
- // disconnected orphan elements...
- container = elem.find('>.jspContainer');
- pane = container.find('>.jspPane');
- pane.css('padding', originalPadding);
- /*
- // Move any margins from the first and last children up to the container so they can still
- // collapse with neighbouring elements as they would before jScrollPane
- firstChild = pane.find(':first-child');
- lastChild = pane.find(':last-child');
- elem.css(
- {
- 'margin-top': firstChild.css('margin-top'),
- 'margin-bottom': lastChild.css('margin-bottom')
- }
- );
- firstChild.css('margin-top', 0);
- lastChild.css('margin-bottom', 0);
- */
- } else {
- elem.css('width', null);
- hasContainingSpaceChanged = elem.outerWidth() + originalPaddingTotalWidth != paneWidth || elem.outerHeight() != paneHeight;
- if (hasContainingSpaceChanged) {
- paneWidth = elem.innerWidth() + originalPaddingTotalWidth;
- paneHeight = elem.innerHeight();
- container.css({
- 'width': paneWidth + 'px',
- 'height': paneHeight + 'px'
- });
- }
- previousPaneWidth = pane.innerWidth();
- if (!hasContainingSpaceChanged && pane.outerWidth() == contentWidth && pane.outerHeight() == contentHeight) {
- // Nothing has changed since we last initialised
- if (isScrollableH || isScrollableV) { // If we had already set a width then re-set it
- pane.css('width', previousPaneWidth + 'px');
- elem.css('width', (previousPaneWidth + originalPaddingTotalWidth) + 'px');
- }
- // Then abort...
- return;
- }
-
- pane.css('width', null);
- elem.css('width', (paneWidth + originalPaddingTotalWidth) + 'px');
- container.find('>.jspVerticalBar,>.jspHorizontalBar').remove().end();
- }
- // Unfortunately it isn't that easy to find out the width of the element as it will always report the
- // width as allowed by its container, regardless of overflow settings.
- // A cunning workaround is to clone the element, set its position to absolute and place it in a narrow
- // container. Now it will push outwards to its maxium real width...
- clonedElem = pane.clone().css('position', 'absolute');
- tempWrapper = $('<div style="width:1px; position: relative;" />').append(clonedElem);
- $('body').append(tempWrapper);
- contentWidth = Math.max(pane.outerWidth(), clonedElem.outerWidth());
- tempWrapper.remove();
-
- contentHeight = pane.outerHeight();
- percentInViewH = contentWidth / paneWidth;
- percentInViewV = contentHeight / paneHeight;
- isScrollableV = percentInViewV > 1;
- isScrollableH = percentInViewH > 1;
- //console.log(paneWidth, paneHeight, contentWidth, contentHeight, percentInViewH, percentInViewV, isScrollableH, isScrollableV);
- if (!(isScrollableH || isScrollableV)) {
- elem.removeClass('jspScrollable');
- pane.css({
- 'top': 0,
- 'width': container.width() + 'px'
- });
- removeMousewheel();
- removeFocusHandler();
- removeKeyboardNav();
- unhijackInternalLinks();
- } else {
- elem.addClass('jspScrollable');
- isMaintainingPositon = settings.maintainPosition && (verticalDragPosition || horizontalDragPosition);
- if (isMaintainingPositon) {
- lastContentX = contentPositionX();
- lastContentY = contentPositionY();
- }
- initialiseVerticalScroll();
- initialiseHorizontalScroll();
- resizeScrollbars();
- if (isMaintainingPositon) {
- scrollToX(lastContentX);
- scrollToY(lastContentY);
- }
- initFocusHandler();
- initMousewheel();
- if (settings.enableKeyboardNavigation) {
- initKeyboardNav();
- }
-
- observeHash();
- if (settings.hijackInternalLinks) {
- hijackInternalLinks();
- }
- }
- if (settings.autoReinitialise && !reinitialiseInterval) {
- reinitialiseInterval = setInterval(
- function()
- {
- initialise(settings);
- },
- settings.autoReinitialiseDelay
- );
- } else if (!settings.autoReinitialise && reinitialiseInterval) {
- clearInterval(reinitialiseInterval)
- }
- elem.trigger('jsp-initialised', [isScrollableH || isScrollableV]);
- }
- function initialiseVerticalScroll()
- {
- if (isScrollableV) {
- container.append(
- $('<div class="jspVerticalBar" />').append(
- $('<div class="jspCap jspCapTop" />'),
- $('<div class="jspTrack" />').append(
- $('<div class="jspDrag" />').append(
- $('<div class="jspDragTop" />'),
- $('<div class="jspDragBottom" />')
- )
- ),
- $('<div class="jspCap jspCapBottom" />')
- )
- );
- verticalBar = container.find('>.jspVerticalBar');
- verticalTrack = verticalBar.find('>.jspTrack');
- verticalDrag = verticalTrack.find('>.jspDrag');
- if (settings.showArrows) {
- arrowUp = $('<a class="jspArrow jspArrowUp" />').bind(
- 'mousedown.jsp', getArrowScroll(0, -1)
- ).bind('click.jsp', nil);
- arrowDown = $('<a class="jspArrow jspArrowDown" />').bind(
- 'mousedown.jsp', getArrowScroll(0, 1)
- ).bind('click.jsp', nil);
- if (settings.arrowScrollOnHover) {
- arrowUp.bind('mouseover.jsp', getArrowScroll(0, -1, arrowUp));
- arrowDown.bind('mouseover.jsp', getArrowScroll(0, 1, arrowDown));
- }
- appendArrows(verticalTrack, settings.verticalArrowPositions, arrowUp, arrowDown);
- }
- verticalTrackHeight = paneHeight;
- container.find('>.jspVerticalBar>.jspCap:visible,>.jspVerticalBar>.jspArrow').each(
- function()
- {
- verticalTrackHeight -= $(this).outerHeight();
- }
- );
- verticalDrag.hover(
- function()
- {
- verticalDrag.addClass('jspHover');
- },
- function()
- {
- verticalDrag.removeClass('jspHover');
- }
- ).bind(
- 'mousedown.jsp',
- function(e)
- {
- // Stop IE from allowing text selection
- $('html').bind('dragstart.jsp selectstart.jsp', function() { return false; });
- verticalDrag.addClass('jspActive');
- var startY = e.pageY - verticalDrag.position().top;
- $('html').bind(
- 'mousemove.jsp',
- function(e)
- {
- positionDragY(e.pageY - startY, false);
- }
- ).bind('mouseup.jsp mouseleave.jsp', cancelDrag);
- return false;
- }
- );
- sizeVerticalScrollbar();
- updateVerticalArrows();
- }
- }
- function sizeVerticalScrollbar()
- {
- verticalTrack.height(verticalTrackHeight + 'px');
- verticalDragPosition = 0;
- scrollbarWidth = settings.verticalGutter + verticalTrack.outerWidth();
- // Make the pane thinner to allow for the vertical scrollbar
- pane.width(paneWidth - scrollbarWidth - originalPaddingTotalWidth);
- // Add margin to the left of the pane if scrollbars are on that side (to position
- // the scrollbar on the left or right set it's left or right property in CSS)
- if (verticalBar.position().left == 0) {
- pane.css('margin-left', scrollbarWidth + 'px');
- }
- }
- function initialiseHorizontalScroll()
- {
- if (isScrollableH) {
- container.append(
- $('<div class="jspHorizontalBar" />').append(
- $('<div class="jspCap jspCapLeft" />'),
- $('<div class="jspTrack" />').append(
- $('<div class="jspDrag" />').append(
- $('<div class="jspDragLeft" />'),
- $('<div class="jspDragRight" />')
- )
- ),
- $('<div class="jspCap jspCapRight" />')
- )
- );
- horizontalBar = container.find('>.jspHorizontalBar');
- horizontalTrack = horizontalBar.find('>.jspTrack');
- horizontalDrag = horizontalTrack.find('>.jspDrag');
- if (settings.showArrows) {
- arrowLeft = $('<a class="jspArrow jspArrowLeft" />').bind(
- 'mousedown.jsp', getArrowScroll(-1, 0)
- ).bind('click.jsp', nil);
- arrowRight = $('<a class="jspArrow jspArrowRight" />').bind(
- 'mousedown.jsp', getArrowScroll(1, 0)
- ).bind('click.jsp', nil);
- if (settings.arrowScrollOnHover) {
- arrowLeft.bind('mouseover.jsp', getArrowScroll(-1, 0, arrowLeft));
- arrowRight.bind('mouseover.jsp', getArrowScroll(1, 0, arrowRight));
- }
- appendArrows(horizontalTrack, settings.horizontalArrowPositions, arrowLeft, arrowRight);
- }
- horizontalDrag.hover(
- function()
- {
- horizontalDrag.addClass('jspHover');
- },
- function()
- {
- horizontalDrag.removeClass('jspHover');
- }
- ).bind(
- 'mousedown.jsp',
- function(e)
- {
- // Stop IE from allowing text selection
- $('html').bind('dragstart.jsp selectstart.jsp', function() { return false; });
- horizontalDrag.addClass('jspActive');
- var startX = e.pageX - horizontalDrag.position().left;
- $('html').bind(
- 'mousemove.jsp',
- function(e)
- {
- positionDragX(e.pageX - startX, false);
- }
- ).bind('mouseup.jsp mouseleave.jsp', cancelDrag);
- return false;
- }
- );
- horizontalTrackWidth = container.innerWidth();
- sizeHorizontalScrollbar();
- updateHorizontalArrows();
- } else {
- // no horizontal scroll
- }
- }
- function sizeHorizontalScrollbar()
- {
- container.find('>.jspHorizontalBar>.jspCap:visible,>.jspHorizontalBar>.jspArrow').each(
- function()
- {
- horizontalTrackWidth -= $(this).outerWidth();
- }
- );
- horizontalTrack.width(horizontalTrackWidth + 'px');
- horizontalDragPosition = 0;
- }
- function resizeScrollbars()
- {
- if (isScrollableH && isScrollableV) {
- var horizontalTrackHeight = horizontalTrack.outerHeight(),
- verticalTrackWidth = verticalTrack.outerWidth();
- verticalTrackHeight -= horizontalTrackHeight;
- $(horizontalBar).find('>.jspCap:visible,>.jspArrow').each(
- function()
- {
- horizontalTrackWidth += $(this).outerWidth();
- }
- );
- horizontalTrackWidth -= verticalTrackWidth;
- paneHeight -= verticalTrackWidth;
- paneWidth -= horizontalTrackHeight;
- horizontalTrack.parent().append(
- $('<div class="jspCorner" />').css('width', horizontalTrackHeight + 'px')
- );
- sizeVerticalScrollbar();
- sizeHorizontalScrollbar();
- }
- // reflow content
- if (isScrollableH) {
- pane.width((container.outerWidth() - originalPaddingTotalWidth) + 'px');
- }
- contentHeight = pane.outerHeight();
- percentInViewV = contentHeight / paneHeight;
- if (isScrollableH) {
- horizontalDragWidth = 1 / percentInViewH * horizontalTrackWidth;
- if (horizontalDragWidth > settings.horizontalDragMaxWidth) {
- horizontalDragWidth = settings.horizontalDragMaxWidth;
- } else if (horizontalDragWidth < settings.horizontalDragMinWidth) {
- horizontalDragWidth = settings.horizontalDragMinWidth;
- }
- horizontalDrag.width(horizontalDragWidth + 'px');
- dragMaxX = horizontalTrackWidth - horizontalDragWidth;
- }
- if (isScrollableV) {
- verticalDragHeight = 1 / percentInViewV * verticalTrackHeight;
- if (verticalDragHeight > settings.verticalDragMaxHeight) {
- verticalDragHeight = settings.verticalDragMaxHeight;
- } else if (verticalDragHeight < settings.verticalDragMinHeight) {
- verticalDragHeight = settings.verticalDragMinHeight;
- }
- verticalDrag.height(verticalDragHeight + 'px');
- dragMaxY = verticalTrackHeight - verticalDragHeight;
- }
- }
- function appendArrows(ele, p, a1, a2)
- {
- var p1 = "before", p2 = "after", aTemp;
-
- // Sniff for mac... Is there a better way to determine whether the arrows would naturally appear
- // at the top or the bottom of the bar?
- if (p == "os") {
- p = /Mac/.test(navigator.platform) ? "after" : "split";
- }
- if (p == p1) {
- p2 = p;
- } else if (p == p2) {
- p1 = p;
- aTemp = a1;
- a1 = a2;
- a2 = aTemp;
- }
- ele[p1](a1)[p2](a2);
- }
- function getArrowScroll(dirX, dirY, ele) {
- return function()
- {
- arrowScroll(dirX, dirY, this, ele);
- this.blur();
- return false;
- }
- }
- function arrowScroll(dirX, dirY, arrow, ele)
- {
- arrow = $(arrow).addClass('jspActive');
- var eve, doScroll = function()
- {
- if (dirX != 0) {
- positionDragX(horizontalDragPosition + dirX * settings.arrowButtonSpeed, false);
- }
- if (dirY != 0) {
- positionDragY(verticalDragPosition + dirY * settings.arrowButtonSpeed, false);
- }
- },
- scrollInt = setInterval(doScroll, settings.arrowRepeatFreq);
- doScroll();
- eve = ele == undefined ? 'mouseup.jsp' : 'mouseout.jsp';
- ele = ele || $('html');
- ele.bind(
- eve,
- function()
- {
- arrow.removeClass('jspActive');
- clearInterval(scrollInt);
- ele.unbind(eve);
- }
- );
- }
- function cancelDrag()
- {
- $('html').unbind('dragstart.jsp selectstart.jsp mousemove.jsp mouseup.jsp mouseleave.jsp');
- verticalDrag && verticalDrag.removeClass('jspActive');
- horizontalDrag && horizontalDrag.removeClass('jspActive');
- }
- function positionDragY(destY, animate)
- {
- if (!isScrollableV) {
- return;
- }
- if (destY < 0) {
- destY = 0;
- } else if (destY > dragMaxY) {
- destY = dragMaxY;
- }
- // can't just check if(animate) because false is a valid value that could be passed in...
- if (animate == undefined) {
- animate = settings.animateScroll;
- }
- if (animate) {
- jsp.animate(verticalDrag, 'top', destY, _positionDragY);
- } else {
- verticalDrag.css('top', destY);
- _positionDragY(destY);
- }
- }
- function _positionDragY(destY)
- {
- if (destY == undefined) {
- destY = verticalDrag.position().top;
- }
- container.scrollTop(0);
- verticalDragPosition = destY;
- var isAtTop = verticalDragPosition == 0,
- isAtBottom = verticalDragPosition == dragMaxY,
- percentScrolled = destY/ dragMaxY,
- destTop = -percentScrolled * (contentHeight - paneHeight);
- if (wasAtTop != isAtTop || wasAtBottom != isAtBottom) {
- wasAtTop = isAtTop;
- wasAtBottom = isAtBottom;
- elem.trigger('jsp-arrow-change', [wasAtTop, wasAtBottom, wasAtLeft, wasAtRight]);
- }
-
- updateVerticalArrows(isAtTop, isAtBottom);
- pane.css('top', destTop);
- elem.trigger('jsp-scroll-y', [-destTop, isAtTop, isAtBottom]);
- }
- function positionDragX(destX, animate)
- {
- if (!isScrollableH) {
- return;
- }
- if (destX < 0) {
- destX = 0;
- } else if (destX > dragMaxX) {
- destX = dragMaxX;
- }
- if (animate == undefined) {
- animate = settings.animateScroll;
- }
- if (animate) {
- jsp.animate(horizontalDrag, 'left', destX, _positionDragX);
- } else {
- horizontalDrag.css('left', destX);
- _positionDragX(destX);
- }
- }
- function _positionDragX(destX)
- {
- if (destX == undefined) {
- destX = horizontalDrag.position().left;
- }
- container.scrollTop(0);
- horizontalDragPosition = destX;
- var isAtLeft = horizontalDragPosition == 0,
- isAtRight = horizontalDragPosition == dragMaxY,
- percentScrolled = destX / dragMaxX,
- destLeft = -percentScrolled * (contentWidth - paneWidth);
- if (wasAtLeft != isAtLeft || wasAtRight != isAtRight) {
- wasAtLeft = isAtLeft;
- wasAtRight = isAtRight;
- elem.trigger('jsp-arrow-change', [wasAtTop, wasAtBottom, wasAtLeft, wasAtRight]);
- }
-
- updateHorizontalArrows(isAtLeft, isAtRight);
- pane.css('left', destLeft);
- elem.trigger('jsp-scroll-x', [-destLeft, isAtLeft, isAtRight]);
- }
- function updateVerticalArrows(isAtTop, isAtBottom)
- {
- if (settings.showArrows) {
- arrowUp[isAtTop ? 'addClass' : 'removeClass']('jspDisabled');
- arrowDown[isAtBottom ? 'addClass' : 'removeClass']('jspDisabled');
- }
- }
- function updateHorizontalArrows(isAtLeft, isAtRight)
- {
- if (settings.showArrows) {
- arrowLeft[isAtLeft ? 'addClass' : 'removeClass']('jspDisabled');
- arrowRight[isAtRight ? 'addClass' : 'removeClass']('jspDisabled');
- }
- }
- function scrollToY(destY, animate)
- {
- var percentScrolled = destY / (contentHeight - paneHeight);
- positionDragY(percentScrolled * dragMaxY, animate);
- }
- function scrollToX(destX, animate)
- {
- var percentScrolled = destX / (contentWidth - paneWidth);
- positionDragX(percentScrolled * dragMaxX, animate);
- }
- function scrollToElement(ele, stickToTop, animate)
- {
- var e, eleHeight, eleTop = 0, viewportTop, maxVisibleEleTop, destY;
- // Legal hash values aren't necessarily legal jQuery selectors so we need to catch any
- // errors from the lookup...
- try {
- e = $(ele);
- } catch (err) {
- return;
- }
- eleHeight = e.outerHeight();
- container.scrollTop(0);
-
- // loop through parents adding the offset top of any elements that are relatively positioned between
- // the focused element and the jspPane so we can get the true distance from the top
- // of the focused element to the top of the scrollpane...
- while (!e.is('.jspPane')) {
- eleTop += e.position().top;
- e = e.offsetParent();
- if (/^body|html$/i.test(e[0].nodeName)) {
- // we ended up too high in the document structure. Quit!
- return;
- }
- }
- viewportTop = contentPositionY();
- maxVisibleEleTop = viewportTop + paneHeight;
- if (eleTop < viewportTop || stickToTop) { // element is above viewport
- destY = eleTop - settings.verticalGutter;
- } else if (eleTop + eleHeight > maxVisibleEleTop) { // element is below viewport
- destY = eleTop - paneHeight + eleHeight + settings.verticalGutter;
- }
- if (destY) {
- scrollToY(destY, animate);
- }
- // TODO: Implement automatic horizontal scrolling?
- }
- function contentPositionX()
- {
- return -pane.position().left;
- }
- function contentPositionY()
- {
- return -pane.position().top;
- }
- function initMousewheel()
- {
- container.unbind(mwEvent).bind(
- mwEvent,
- function (event, delta, deltaX, deltaY) {
- var dX = horizontalDragPosition, dY = verticalDragPosition;
- positionDragX(horizontalDragPosition + deltaX * settings.mouseWheelSpeed, false)
- positionDragY(verticalDragPosition - deltaY * settings.mouseWheelSpeed, false);
- // return true if there was no movement so rest of screen can scroll
- return dX == horizontalDragPosition && dY == verticalDragPosition;
- }
- );
- }
- function removeMousewheel()
- {
- container.unbind(mwEvent);
- }
- function nil()
- {
- return false;
- }
- function initFocusHandler()
- {
- pane.unbind('focusin.jsp').bind(
- 'focusin.jsp',
- function(e)
- {
- if(e.target === pane[0]){return;}
- scrollToElement(e.target, false);
- }
- );
- }
- function removeFocusHandler()
- {
- pane.unbind('focusin.jsp');
- }
-
- function initKeyboardNav()
- {
- var pressed, pressedTimer;
- elem.attr('tabindex', 0)
- .unbind('keydown.jsp')
- .bind(
- 'keydown.jsp',
- function(e)
- {
- if(e.target !== elem[0]){
- return;
- }
- var dX = horizontalDragPosition, dY = verticalDragPosition, step = pressed ? 2 : 16;
- switch(e.keyCode) {
- case 40: // down
- positionDragY(verticalDragPosition + step, false);
- break;
- case 38: // up
- positionDragY(verticalDragPosition - step, false);
- break;
- case 34: // page down
- case 32: // space
- scrollToY(contentPositionY() + Math.max(32, paneHeight) - 16);
- break;
- case 33: // page up
- scrollToY(contentPositionY() - paneHeight + 16);
- break;
- case 35: // end
- scrollToY(contentHeight - paneHeight);
- break;
- case 36: // home
- scrollToY(0);
- break;
- case 39: // right
- positionDragX(horizontalDragPosition + step, false);
- break;
- case 37: // left
- positionDragX(horizontalDragPosition - step, false);
- break;
- }
- if( !(dX == horizontalDragPosition && dY == verticalDragPosition) ){
- pressed = true;
- clearTimeout(pressedTimer);
- pressedTimer = setTimeout(function(){
- pressed = false;
- }, 260);
- return false;
- }
- }
- );
- if(settings.hideFocus) {
- elem.css('outline', 'none');
- if('hideFocus' in container[0]){
- elem.attr('hideFocus', true);
- }
- } else {
- elem.css('outline', '');
- if('hideFocus' in container[0]){
- elem.attr('hideFocus', false);
- }
- }
- }
-
- function removeKeyboardNav()
- {
- elem.attr('tabindex', '-1')
- .removeAttr('tabindex')
- .unbind('keydown.jsp');
- }
- function observeHash()
- {
- if (location.hash && location.hash.length > 1) {
- var e, retryInt;
- try {
- e = $(location.hash);
- } catch (err) {
- return;
- }
- if (e.length && pane.find(e)) {
- // nasty workaround but it appears to take a little while before the hash has done its thing
- // to the rendered page so we just wait until the container's scrollTop has been messed up.
- if (container.scrollTop() == 0) {
- retryInt = setInterval(
- function()
- {
- if (container.scrollTop() > 0) {
- scrollToElement(location.hash, true);
- $(document).scrollTop(container.position().top);
- clearInterval(retryInt);
- }
- },
- 50
- )
- } else {
- scrollToElement(location.hash, true);
- $(document).scrollTop(container.position().top);
- }
- }
- }
- }
- function unhijackInternalLinks()
- {
- $('a.jspHijack').unbind('click.jsp-hijack').removeClass('jspHijack');
- }
- function hijackInternalLinks()
- {
- unhijackInternalLinks();
- $('a[href^=#]').addClass('jspHijack').bind(
- 'click.jsp-hijack',
- function()
- {
- var uriParts = this.href.split('#'), hash;
- if (uriParts.length > 1) {
- hash = uriParts[1];
- if (hash.length > 0 && pane.find('#' + hash).length > 0) {
- scrollToElement('#' + hash, true);
- // Need to return false otherwise things mess up... Would be nice to maybe also scroll
- // the window to the top of the scrollpane?
- return false;
- }
- }
- }
- )
- }
- // Public API
- $.extend(
- jsp,
- {
- // Reinitialises the scroll pane (if it's internal dimensions have changed since the last time it
- // was initialised). The settings object which is passed in will override any settings from the
- // previous time it was initialised - if you don't pass any settings then the ones from the previous
- // initialisation will be used.
- reinitialise: function(s)
- {
- s = $.extend({}, s, settings);
- initialise(s);
- },
- // Scrolls the specified element (a jQuery object, DOM node or jQuery selector string) into view so
- // that it can be seen within the viewport. If stickToTop is true then the element will appear at
- // the top of the viewport, if it is false then the viewport will scroll as little as possible to
- // show the element. You can also specify if you want animation to occur. If you don't provide this
- // argument then the animateScroll value from the settings object is used instead.
- scrollToElement: function(ele, stickToTop, animate)
- {
- scrollToElement(ele, stickToTop, animate);
- },
- // Scrolls the pane so that the specified co-ordinates within the content are at the top left
- // of the viewport. animate is optional and if not passed then the value of animateScroll from
- // the settings object this jScrollPane was initialised with is used.
- scrollTo: function(destX, destY, animate)
- {
- scrollToX(destX, animate);
- scrollToY(destY, animate);
- },
- // Scrolls the pane so that the specified co-ordinate within the content is at the left of the
- // viewport. animate is optional and if not passed then the value of animateScroll from the settings
- // object this jScrollPane was initialised with is used.
- scrollToX: function(destX, animate)
- {
- scrollToX(destX, animate);
- },
- // Scrolls the pane so that the specified co-ordinate within the content is at the top of the
- // viewport. animate is optional and if not passed then the value of animateScroll from the settings
- // object this jScrollPane was initialised with is used.
- scrollToY: function(destY, animate)
- {
- scrollToY(destY, animate);
- },
- // Scrolls the pane by the specified amount of pixels. animate is optional and if not passed then
- // the value of animateScroll from the settings object this jScrollPane was initialised with is used.
- scrollBy: function(deltaX, deltaY, animate)
- {
- jsp.scrollByX(deltaX, animate);
- jsp.scrollByY(deltaY, animate);
- },
- // Scrolls the pane by the specified amount of pixels. animate is optional and if not passed then
- // the value of animateScroll from the settings object this jScrollPane was initialised with is used.
- scrollByX: function(deltaX, animate)
- {
- var destX = contentPositionX() + deltaX,
- percentScrolled = destX / (contentWidth - paneWidth);
- positionDragX(percentScrolled * dragMaxX, animate);
- },
- // Scrolls the pane by the specified amount of pixels. animate is optional and if not passed then
- // the value of animateScroll from the settings object this jScrollPane was initialised with is used.
- scrollByY: function(deltaY, animate)
- {
- var destY = contentPositionY() + deltaY,
- percentScrolled = destY / (contentHeight - paneHeight);
- positionDragY(percentScrolled * dragMaxY, animate);
- },
- // This method is called when jScrollPane is trying to animate to a new position. You can override
- // it if you want to provide advanced animation functionality. It is passed the following arguments:
- // * ele - the element whose position is being animated
- // * prop - the property that is being animated
- // * value - the value it's being animated to
- // * stepCallback - a function that you must execute each time you update the value of the property
- // You can use the default implementation (below) as a starting point for your own implementation.
- animate: function(ele, prop, value, stepCallback)
- {
- var params = {};
- params[prop] = value;
- ele.animate(
- params,
- {
- 'duration' : settings.animateDuration,
- 'ease' : settings.animateEase,
- 'queue' : false,
- 'step' : stepCallback
- }
- );
- },
- // Returns the current x position of the viewport with regards to the content pane.
- getContentPositionX: function()
- {
- return contentPositionX();
- },
- // Returns the current y position of the viewport with regards to the content pane.
- getContentPositionY: function()
- {
- return contentPositionY();
- },
- // Returns whether or not this scrollpane has a horizontal scrollbar.
- getIsScrollableH: function()
- {
- return isScrollableH;
- },
- // Returns whether or not this scrollpane has a vertical scrollbar.
- getIsScrollableV: function()
- {
- return isScrollableV;
- },
- // Gets a reference to the content pane. It is important that you use this method if you want to
- // edit the content of your jScrollPane as if you access the element directly then you may have some
- // problems (as your original element has had additional elements for the scrollbars etc added into
- // it).
- getContentPane: function()
- {
- return pane;
- },
- // Scrolls this jScrollPane down as far as it can currently scroll. If animate isn't passed then the
- // animateScroll value from settings is used instead.
- scrollToBottom: function(animate)
- {
- positionDragY(dragMaxY, animate);
- },
- // Hijacks the links on the page which link to content inside the scrollpane. If you have changed
- // the content of your page (e.g. via AJAX) and want to make sure any new anchor links to the
- // contents of your scroll pane will work then call this function.
- hijackInternalLinks: function()
- {
- hijackInternalLinks();
- }
- }
- );
- }
- // Pluginifying code...
- settings = $.extend({}, $.fn.jScrollPane.defaults, settings);
- var ret;
- this.each(
- function()
- {
- var elem = $(this), jspApi = elem.data('jsp');
- if (jspApi) {
- jspApi.reinitialise(settings);
- } else {
- jspApi = new JScrollPane(elem, settings);
- elem.data('jsp', jspApi);
- }
- ret = ret ? ret.add(elem) : elem;
- }
- )
- return ret;
- };
- $.fn.jScrollPane.defaults = {
- 'showArrows' : false,
- 'maintainPosition' : true,
- 'autoReinitialise' : false,
- 'autoReinitialiseDelay' : 500,
- 'verticalDragMinHeight' : 0,
- 'verticalDragMaxHeight' : 99999,
- 'horizontalDragMinWidth' : 0,
- 'horizontalDragMaxWidth' : 99999,
- 'animateScroll' : false,
- 'animateDuration' : 300,
- 'animateEase' : 'linear',
- 'hijackInternalLinks' : false,
- 'verticalGutter' : 4,
- 'horizontalGutter' : 4,
- 'mouseWheelSpeed' : 10,
- 'arrowButtonSpeed' : 10,
- 'arrowRepeatFreq' : 100,
- 'arrowScrollOnHover' : false,
- 'verticalArrowPositions' : 'split',
- 'horizontalArrowPositions' : 'split',
- 'enableKeyboardNavigation' : true,
- 'hideFocus' : false
- };
- })(jQuery,this);