/*!
* jScrollPane - v2.0.0beta2 - 2010-08-19
* http://jscrollpane.kelvinluck.com/
*
* Copyright (c) 2010 Kelvin Luck
* Dual licensed under the MIT or GPL licenses.
*/
// Script: jScrollPane - cross browser customisable scrollbars
//
// *Version: 2.0.0beta2, Last updated: 2010-08-19*
//
// 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.0beta2 - (2010-08-19) 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;
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();
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 {
hasContainingSpaceChanged = elem.outerWidth() != paneWidth || elem.outerHeight() != paneHeight;
if (hasContainingSpaceChanged) {
paneWidth = elem.innerWidth();
paneHeight = elem.innerHeight();
container.css({
'width': paneWidth + 'px',
'height': paneHeight + 'px'
});
}
previousPaneWidth = pane.innerWidth();
pane.css('width', null);
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');
}
// Then abort...
return;
}
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);
removeMousewheel();
removeFocusHandler();
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();
observeHash();
if (settings.hijackInternalLinks) {
hijackInternalLinks();
}
}
if (settings.autoReinitialise && !reinitialiseInterval) {
reinitialiseInterval = setInterval(
function()
{
initialise(settings);
},
settings.autoReinitialiseDelay
);
} else if (!settings.autoReinitialise && reinitialiseInterval) {
clearInterval(reinitialiseInterval)
}
}
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 href="#" class="jspArrow jspArrowUp">Scroll up</a>').bind(
'mousedown.jsp', getArrowScroll(0, -1)
).bind('click.jsp', nil);
arrowDown = $('<a href="#" class="jspArrow jspArrowDown">Scroll down</a>').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();
initMousewheel();
} else {
// no vertical scroll
removeMousewheel();
}
}
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 href="#" class="jspArrow jspArrowLeft">Scroll left</a>').bind(
'mousedown.jsp', getArrowScroll(-1, 0)
).bind('click.jsp', nil);
arrowRight = $('<a href="#" class="jspArrow jspArrowRight">Scroll right</a>').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);
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);
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('mousewheel.jsp').bind(
'mousewheel.jsp',
function (event, delta) {
var d = verticalDragPosition;
positionDragY(verticalDragPosition - delta * settings.mouseWheelSpeed, false);
// return true if there was no movement so rest of screen can scroll
return d == verticalDragPosition;
}
);
}
function removeMousewheel()
{
container.unbind('mousewheel.jsp');
}
function nil()
{
return false;
}
function initFocusHandler()
{
pane.find(':input,a').bind(
'focus.jsp',
function()
{
scrollToElement(this, false);
}
);
}
function removeFocusHandler()
{
pane.find(':input,a').unbind('focus.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();
},
// 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'
};
})(jQuery,this);
|