From 74272a4117c00221d407d1de8183d0a976616891 Mon Sep 17 00:00:00 2001 From: Peter Dave Hello Date: Tue, 30 Jun 2015 16:55:09 +0800 Subject: [PATCH] update jScrollPane to v2.0.22 and update its filename field --- .../2.0.0beta1/script/jquery.jscrollpane.js | 928 +++++++++++ .../script/jquery.jscrollpane.min.js | 10 + .../style}/jquery.jscrollpane.css | 0 .../style}/jquery.jscrollpane.min.css | 0 .../2.0.0beta10/script/jquery.jscrollpane.js | 1389 ++++++++++++++++ .../script/jquery.jscrollpane.min.js | 11 + .../2.0.0beta10/style/jquery.jscrollpane.css | 120 ++ .../style}/jquery.jscrollpane.min.css | 0 .../2.0.0beta11/script/jquery.jscrollpane.js | 1434 ++++++++++++++++ .../script/jquery.jscrollpane.min.js | 11 + .../2.0.0beta11/style/jquery.jscrollpane.css | 120 ++ .../style/jquery.jscrollpane.min.css | 1 + .../2.0.0beta2/script/jquery.jscrollpane.js | 972 +++++++++++ .../script/jquery.jscrollpane.min.js | 10 + .../2.0.0beta2/style/jquery.jscrollpane.css | 120 ++ .../style/jquery.jscrollpane.min.css | 1 + .../2.0.0beta3/script/jquery.jscrollpane.js | 1061 ++++++++++++ .../script/jquery.jscrollpane.min.js | 10 + .../2.0.0beta3/style/jquery.jscrollpane.css | 120 ++ .../style/jquery.jscrollpane.min.css | 1 + .../2.0.0beta4/script/jquery.jscrollpane.js | 1146 +++++++++++++ .../script/jquery.jscrollpane.min.js | 10 + .../2.0.0beta4/style/jquery.jscrollpane.css | 120 ++ .../style/jquery.jscrollpane.min.css | 1 + .../2.0.0beta5/script/jquery.jscrollpane.js | 1146 +++++++++++++ .../script/jquery.jscrollpane.min.js | 10 + .../2.0.0beta5/style/jquery.jscrollpane.css | 120 ++ .../style/jquery.jscrollpane.min.css | 1 + .../2.0.0beta8/script/jquery.jscrollpane.js | 1328 +++++++++++++++ .../script/jquery.jscrollpane.min.js | 11 + .../2.0.0beta8/style/jquery.jscrollpane.css | 120 ++ .../style/jquery.jscrollpane.min.css | 1 + .../2.0.0beta9/script/jquery.jscrollpane.js | 1376 +++++++++++++++ .../script/jquery.jscrollpane.min.js | 11 + .../2.0.0beta9/style/jquery.jscrollpane.css | 120 ++ .../style/jquery.jscrollpane.min.css | 1 + .../2.0.13/script/jquery.jscrollpane.js | 1437 ++++++++++++++++ .../script}/jquery.jscrollpane.min.js | 8 +- .../2.0.13/style/jquery.jscrollpane.css | 120 ++ .../2.0.13/style/jquery.jscrollpane.min.css | 1 + .../2.0.14/{ => script}/jquery.jscrollpane.js | 0 .../{ => script}/jquery.jscrollpane.min.js | 0 .../2.0.14/style/jquery.jscrollpane.css | 120 ++ .../2.0.14/style/jquery.jscrollpane.min.css | 1 + .../2.0.20/script/jquery.jscrollpane.js | 1467 ++++++++++++++++ .../2.0.20/script/jquery.jscrollpane.min.js | 11 + .../2.0.20/style/jquery.jscrollpane.css | 115 ++ .../2.0.20/style/jquery.jscrollpane.min.css | 1 + .../2.0.21/script/jquery.jscrollpane.js | 1465 ++++++++++++++++ .../2.0.21/script/jquery.jscrollpane.min.js | 8 + .../2.0.21/style/jquery.jscrollpane.css | 115 ++ .../2.0.21/style/jquery.jscrollpane.min.css | 1 + .../2.0.22/script/jquery.jscrollpane.js | 1470 +++++++++++++++++ .../2.0.22/script/jquery.jscrollpane.min.js | 8 + .../2.0.22/style/jquery.jscrollpane.css | 115 ++ .../2.0.22/style/jquery.jscrollpane.min.css | 1 + ajax/libs/jScrollPane/package.json | 4 +- 57 files changed, 18303 insertions(+), 6 deletions(-) create mode 100644 ajax/libs/jScrollPane/2.0.0beta1/script/jquery.jscrollpane.js create mode 100644 ajax/libs/jScrollPane/2.0.0beta1/script/jquery.jscrollpane.min.js rename ajax/libs/jScrollPane/{2.0.0beta12 => 2.0.0beta1/style}/jquery.jscrollpane.css (100%) rename ajax/libs/jScrollPane/{2.0.0beta12 => 2.0.0beta1/style}/jquery.jscrollpane.min.css (100%) create mode 100644 ajax/libs/jScrollPane/2.0.0beta10/script/jquery.jscrollpane.js create mode 100644 ajax/libs/jScrollPane/2.0.0beta10/script/jquery.jscrollpane.min.js create mode 100644 ajax/libs/jScrollPane/2.0.0beta10/style/jquery.jscrollpane.css rename ajax/libs/jScrollPane/{2.0.14 => 2.0.0beta10/style}/jquery.jscrollpane.min.css (100%) create mode 100644 ajax/libs/jScrollPane/2.0.0beta11/script/jquery.jscrollpane.js create mode 100644 ajax/libs/jScrollPane/2.0.0beta11/script/jquery.jscrollpane.min.js create mode 100644 ajax/libs/jScrollPane/2.0.0beta11/style/jquery.jscrollpane.css create mode 100644 ajax/libs/jScrollPane/2.0.0beta11/style/jquery.jscrollpane.min.css create mode 100644 ajax/libs/jScrollPane/2.0.0beta2/script/jquery.jscrollpane.js create mode 100644 ajax/libs/jScrollPane/2.0.0beta2/script/jquery.jscrollpane.min.js create mode 100644 ajax/libs/jScrollPane/2.0.0beta2/style/jquery.jscrollpane.css create mode 100644 ajax/libs/jScrollPane/2.0.0beta2/style/jquery.jscrollpane.min.css create mode 100644 ajax/libs/jScrollPane/2.0.0beta3/script/jquery.jscrollpane.js create mode 100644 ajax/libs/jScrollPane/2.0.0beta3/script/jquery.jscrollpane.min.js create mode 100644 ajax/libs/jScrollPane/2.0.0beta3/style/jquery.jscrollpane.css create mode 100644 ajax/libs/jScrollPane/2.0.0beta3/style/jquery.jscrollpane.min.css create mode 100644 ajax/libs/jScrollPane/2.0.0beta4/script/jquery.jscrollpane.js create mode 100644 ajax/libs/jScrollPane/2.0.0beta4/script/jquery.jscrollpane.min.js create mode 100644 ajax/libs/jScrollPane/2.0.0beta4/style/jquery.jscrollpane.css create mode 100644 ajax/libs/jScrollPane/2.0.0beta4/style/jquery.jscrollpane.min.css create mode 100644 ajax/libs/jScrollPane/2.0.0beta5/script/jquery.jscrollpane.js create mode 100644 ajax/libs/jScrollPane/2.0.0beta5/script/jquery.jscrollpane.min.js create mode 100644 ajax/libs/jScrollPane/2.0.0beta5/style/jquery.jscrollpane.css create mode 100644 ajax/libs/jScrollPane/2.0.0beta5/style/jquery.jscrollpane.min.css create mode 100644 ajax/libs/jScrollPane/2.0.0beta8/script/jquery.jscrollpane.js create mode 100644 ajax/libs/jScrollPane/2.0.0beta8/script/jquery.jscrollpane.min.js create mode 100644 ajax/libs/jScrollPane/2.0.0beta8/style/jquery.jscrollpane.css create mode 100644 ajax/libs/jScrollPane/2.0.0beta8/style/jquery.jscrollpane.min.css create mode 100644 ajax/libs/jScrollPane/2.0.0beta9/script/jquery.jscrollpane.js create mode 100644 ajax/libs/jScrollPane/2.0.0beta9/script/jquery.jscrollpane.min.js create mode 100644 ajax/libs/jScrollPane/2.0.0beta9/style/jquery.jscrollpane.css create mode 100644 ajax/libs/jScrollPane/2.0.0beta9/style/jquery.jscrollpane.min.css create mode 100644 ajax/libs/jScrollPane/2.0.13/script/jquery.jscrollpane.js rename ajax/libs/jScrollPane/{2.0.0beta12 => 2.0.13/script}/jquery.jscrollpane.min.js (99%) create mode 100644 ajax/libs/jScrollPane/2.0.13/style/jquery.jscrollpane.css create mode 100644 ajax/libs/jScrollPane/2.0.13/style/jquery.jscrollpane.min.css rename ajax/libs/jScrollPane/2.0.14/{ => script}/jquery.jscrollpane.js (100%) rename ajax/libs/jScrollPane/2.0.14/{ => script}/jquery.jscrollpane.min.js (100%) create mode 100644 ajax/libs/jScrollPane/2.0.14/style/jquery.jscrollpane.css create mode 100644 ajax/libs/jScrollPane/2.0.14/style/jquery.jscrollpane.min.css create mode 100644 ajax/libs/jScrollPane/2.0.20/script/jquery.jscrollpane.js create mode 100644 ajax/libs/jScrollPane/2.0.20/script/jquery.jscrollpane.min.js create mode 100644 ajax/libs/jScrollPane/2.0.20/style/jquery.jscrollpane.css create mode 100644 ajax/libs/jScrollPane/2.0.20/style/jquery.jscrollpane.min.css create mode 100644 ajax/libs/jScrollPane/2.0.21/script/jquery.jscrollpane.js create mode 100644 ajax/libs/jScrollPane/2.0.21/script/jquery.jscrollpane.min.js create mode 100644 ajax/libs/jScrollPane/2.0.21/style/jquery.jscrollpane.css create mode 100644 ajax/libs/jScrollPane/2.0.21/style/jquery.jscrollpane.min.css create mode 100644 ajax/libs/jScrollPane/2.0.22/script/jquery.jscrollpane.js create mode 100644 ajax/libs/jScrollPane/2.0.22/script/jquery.jscrollpane.min.js create mode 100644 ajax/libs/jScrollPane/2.0.22/style/jquery.jscrollpane.css create mode 100644 ajax/libs/jScrollPane/2.0.22/style/jquery.jscrollpane.min.css diff --git a/ajax/libs/jScrollPane/2.0.0beta1/script/jquery.jscrollpane.js b/ajax/libs/jScrollPane/2.0.0beta1/script/jquery.jscrollpane.js new file mode 100644 index 00000000000000..fa5d688d1e2668 --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.0beta1/script/jquery.jscrollpane.js @@ -0,0 +1,928 @@ +/*! + * jScrollPane - v2.0.0beta1 - 2010-08-17 + * 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.0beta1, Last updated: 2010-08-17* +// +// 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.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, savedSettings, 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; + + savedSettings = { + /* + 'originalPadding' : elem.css('paddingTop') + ' ' + + elem.css('paddingRight') + ' ' + + elem.css('paddingBottom') + ' ' + + elem.css('paddingLeft'), + 'originalSidePaddingTotal' : (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'); // So we are measuring it without scrollbars + // 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(); + paneHeight = elem.innerHeight(); + pane = $('
').wrap( + $('
') + .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'); + + /* + // 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' + }); + } + + pane.css('width', null); + + if (!hasContainingSpaceChanged && pane.outerWidth() == contentWidth && pane.outerHeight() == contentHeight) { + // Nothing has changed since we last initialised, lets just 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 = $('
').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( + $('
').append( + $('
'), + $('
').append( + $('
').append( + $('
'), + $('
') + ) + ), + $('
') + ) + ); + + verticalBar = container.find('>.jspVerticalBar'); + verticalTrack = verticalBar.find('>.jspTrack'); + verticalDrag = verticalTrack.find('>.jspDrag'); + + if (settings.showArrows) { + arrowUp = $('Scroll up').bind( + 'mousedown.jsp', getArrowScroll(0, -1) + ).bind('click.jsp', nil); + arrowDown = $('Scroll down').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); + + // 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( + $('
').append( + $('
'), + $('
').append( + $('
').append( + $('
'), + $('
') + ) + ), + $('
') + ) + ); + + horizontalBar = container.find('>.jspHorizontalBar'); + horizontalTrack = horizontalBar.find('>.jspTrack'); + horizontalDrag = horizontalTrack.find('>.jspDrag'); + + if (settings.showArrows) { + arrowLeft = $('Scroll left').bind( + 'mousedown.jsp', getArrowScroll(-1, 0) + ).bind('click.jsp', nil); + arrowRight = $('Scroll right').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( + $('
').css('width', horizontalTrackHeight + 'px') + ); + sizeVerticalScrollbar(); + sizeHorizontalScrollbar(); + } + // reflow content + if (isScrollableH) { + pane.width(container.outerWidth() + '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, scrollInt = setInterval( + function() + { + if (dirX != 0) { + positionDragX(horizontalDragPosition + dirX * settings.arrowButtonSpeed, false); + } + if (dirY != 0) { + positionDragY(verticalDragPosition + dirY * settings.arrowButtonSpeed, false); + } + }, + settings.arrowRepeatFreq + ) + + 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; + updateVerticalArrows(); + var percentScrolled = destY/ dragMaxY, + destTop = -percentScrolled * (contentHeight - paneHeight); + pane.css('top', destTop); + } + + 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; + updateHorizontalArrows(); + var percentScrolled = destX / dragMaxX, + destLeft = -percentScrolled * (contentWidth - paneWidth); + pane.css('left', destLeft); + } + + function updateVerticalArrows() + { + if (settings.showArrows) { + arrowUp[verticalDragPosition == 0 ? 'addClass' : 'removeClass']('jspDisabled'); + arrowDown[verticalDragPosition == dragMaxY ? 'addClass' : 'removeClass']('jspDisabled'); + } + } + + function updateHorizontalArrows() + { + if (settings.showArrows) { + arrowLeft[horizontalDragPosition == 0 ? 'addClass' : 'removeClass']('jspDisabled'); + arrowRight[horizontalDragPosition == dragMaxX ? '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); diff --git a/ajax/libs/jScrollPane/2.0.0beta1/script/jquery.jscrollpane.min.js b/ajax/libs/jScrollPane/2.0.0beta1/script/jquery.jscrollpane.min.js new file mode 100644 index 00000000000000..58c57f61d65540 --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.0beta1/script/jquery.jscrollpane.min.js @@ -0,0 +1,10 @@ +/* + * jScrollPane - v2.0.0beta1 - 2010-08-17 + * http://jscrollpane.kelvinluck.com/ + * + * Copyright (c) 2010 Kelvin Luck + * Dual licensed under the MIT and GPL licenses. + */ +(function(b,a,c){b.fn.jScrollPane=function(f){function d(ah,ae){var an,h=this,ad,I,R,at,W,al,ac,E,q,aq,m,X,A,p,ap,D,P,af,V,o,S,C,aa,F,H,O,n,K,y,ao,z;I={};J(ae);function J(aw){var aA,az,ay,av,au,ax;an=aw;if(ad==c){ah.css("overflow","hidden");R=ah.innerWidth();at=ah.innerHeight();ad=b('
').wrap(b('
').css({width:R+"px",height:at+"px"}));ah.wrapInner(ad.parent());W=ah.find(">.jspContainer");ad=W.find(">.jspPane")}else{ax=ah.outerWidth()!=R||ah.outerHeight()!=at;if(ax){R=ah.innerWidth();at=ah.innerHeight();W.css({width:R+"px",height:at+"px"})}ad.css("width",null);if(!ax&&ad.outerWidth()==al&&ad.outerHeight()==ac){return}W.find(".jspVerticalBar,.jspHorizontalBar").remove().end()}aA=ad.clone().css("position","absolute");az=b('
').append(aA);b("body").append(az);al=Math.max(ad.outerWidth(),aA.outerWidth());az.remove();ac=ad.outerHeight();E=al/R;q=ac/at;aq=q>1;m=E>1;if(!(m||aq)){ah.removeClass("jspScrollable");ad.css("top",0);Q();r();u()}else{ah.addClass("jspScrollable");ay=an.maintainPosition&&(p||P);if(ay){av=j();au=g()}x();aj();k();if(ay){w(av);v(au)}t();ar();if(an.hijackInternalLinks){i()}}if(an.autoReinitialise&&!z){z=setInterval(function(){J(an)},an.autoReinitialiseDelay)}else{if(!an.autoReinitialise&&z){clearInterval(z)}}}function x(){if(aq){W.append(b('
').append(b('
'),b('
').append(b('
').append(b('
'),b('
'))),b('
')));af=W.find(">.jspVerticalBar");V=af.find(">.jspTrack");X=V.find(">.jspDrag");if(an.showArrows){aa=b('Scroll up').bind("mousedown.jsp",G(0,-1)).bind("click.jsp",ai);F=b('Scroll down').bind("mousedown.jsp",G(0,1)).bind("click.jsp",ai);if(an.arrowScrollOnHover){aa.bind("mouseover.jsp",G(0,-1,aa));F.bind("mouseover.jsp",G(0,1,F))}U(V,an.verticalArrowPositions,aa,F)}S=at;W.find(">.jspVerticalBar>.jspCap:visible,>.jspVerticalBar>.jspArrow").each(function(){S-=b(this).outerHeight()});X.hover(function(){X.addClass("jspHover")},function(){X.removeClass("jspHover")}).bind("mousedown.jsp",function(au){b("html").bind("dragstart.jsp selectstart.jsp",function(){return false});X.addClass("jspActive");var s=au.pageY-X.position().top;b("html").bind("mousemove.jsp",function(av){L(av.pageY-s,false)}).bind("mouseup.jsp mouseleave.jsp",B);return false});N();ag();l()}else{Q()}}function N(){V.height(S+"px");p=0;o=an.verticalGutter+V.outerWidth();ad.width(R-o);if(af.position().left==0){ad.css("margin-left",o+"px")}}function aj(){if(m){W.append(b('
').append(b('
'),b('
').append(b('
').append(b('
'),b('
'))),b('
')));H=W.find(">.jspHorizontalBar");O=H.find(">.jspTrack");ap=O.find(">.jspDrag");if(an.showArrows){y=b('Scroll left').bind("mousedown.jsp",G(-1,0)).bind("click.jsp",ai);ao=b('Scroll right').bind("mousedown.jsp",G(1,0)).bind("click.jsp",ai);if(an.arrowScrollOnHover){y.bind("mouseover.jsp",G(-1,0,y));ao.bind("mouseover.jsp",G(1,0,ao))}U(O,an.horizontalArrowPositions,y,ao)}ap.hover(function(){ap.addClass("jspHover")},function(){ap.removeClass("jspHover")}).bind("mousedown.jsp",function(au){b("html").bind("dragstart.jsp selectstart.jsp",function(){return false});ap.addClass("jspActive");var s=au.pageX-ap.position().left;b("html").bind("mousemove.jsp",function(av){M(av.pageX-s,false)}).bind("mouseup.jsp mouseleave.jsp",B); +return false});n=W.innerWidth();ab();am()}else{}}function ab(){W.find(">.jspHorizontalBar>.jspCap:visible,>.jspHorizontalBar>.jspArrow").each(function(){n-=b(this).outerWidth()});O.width(n+"px");P=0}function k(){if(m&&aq){var au=O.outerHeight(),s=V.outerWidth();S-=au;b(H).find(">.jspCap:visible,>.jspArrow").each(function(){n+=b(this).outerWidth()});n-=s;at-=s;R-=au;O.parent().append(b('
').css("width",au+"px"));N();ab()}if(m){ad.width(W.outerWidth()+"px")}ac=ad.outerHeight();q=ac/at;if(m){K=1/E*n;if(K>an.horizontalDragMaxWidth){K=an.horizontalDragMaxWidth}else{if(Kan.verticalDragMaxHeight){C=an.verticalDragMaxHeight}else{if(CA){s=A}}if(au==c){au=an.animateScroll}if(au){h.animate(X,"top",s,Y)}else{X.css("top",s);Y(s)}}function Y(au){if(au==c){au=X.position().top}W.scrollTop(0);p=au;ag();var av=au/A,s=-av*(ac-at);ad.css("top",s)}function M(au,s){if(!m){return}if(au<0){au=0}else{if(au>D){au=D}}if(s==c){s=an.animateScroll}if(s){h.animate(ap,"left",au,Z)}else{ap.css("left",au);Z(au)}}function Z(au){if(au==c){au=ap.position().left}W.scrollTop(0);P=au;am();var av=au/D,s=-av*(al-R);ad.css("left",s)}function ag(){if(an.showArrows){aa[p==0?"addClass":"removeClass"]("jspDisabled");F[p==A?"addClass":"removeClass"]("jspDisabled")}}function am(){if(an.showArrows){y[P==0?"addClass":"removeClass"]("jspDisabled");ao[P==D?"addClass":"removeClass"]("jspDisabled")}}function v(s,au){var av=s/(ac-at);L(av*A,au)}function w(au,s){var av=au/(al-R);M(av*D,s)}function T(aC,aA,au){var ay,aw,s=0,av,az,aB;try{ay=b(aC)}catch(ax){return}aw=ay.outerHeight();W.scrollTop(0);while(!ay.is(".jspPane")){s+=ay.position().top;ay=ay.offsetParent();if(/^body|html$/i.test(ay[0].nodeName)){return}}av=g();az=av+at;if(saz){aB=s-at+aw+an.verticalGutter}}if(aB){v(aB,au)}}function j(){return -ad.position().left}function g(){return -ad.position().top}function l(){W.unbind("mousewheel.jsp").bind("mousewheel.jsp",function(s,av){var au=p;L(p-av*an.mouseWheelSpeed,false);return au==p})}function Q(){W.unbind("mousewheel.jsp")}function ai(){return false}function t(){ad.find(":input,a").bind("focus.jsp",function(){T(this,false)})}function r(){ad.find(":input,a").unbind("focus.jsp")}function ar(){if(location.hash&&location.hash.length>1){var av,au;try{av=b(location.hash)}catch(s){return}if(av.length&&ad.find(av)){if(W.scrollTop()==0){au=setInterval(function(){if(W.scrollTop()>0){T(location.hash,true);b(document).scrollTop(W.position().top);clearInterval(au)}},50)}else{T(location.hash,true);b(document).scrollTop(W.position().top)}}}}function u(){b("a.jspHijack").unbind("click.jsp-hijack").removeClass("jspHijack")}function i(){u();b("a[href^=#]").addClass("jspHijack").bind("click.jsp-hijack",function(){var s=this.href.split("#"),au;if(s.length>1){au=s[1];if(au.length>0&&ad.find("#"+au).length>0){T("#"+au,true);return false}}})}b.extend(h,{reinitialise:function(au){au=b.extend({},au,an);J(au)},scrollToElement:function(av,au,s){T(av,au,s) +},scrollTo:function(av,s,au){w(av,au);v(s,au)},scrollToX:function(au,s){w(au,s)},scrollToY:function(s,au){v(s,au)},scrollBy:function(au,s,av){h.scrollByX(au,av);h.scrollByY(s,av)},scrollByX:function(s,av){var au=j()+s,aw=au/(al-R);M(aw*D,av)},scrollByY:function(s,av){var au=g()+s,aw=au/(ac-at);L(aw*A,av)},animate:function(au,ax,s,aw){var av={};av[ax]=s;au.animate(av,{duration:an.animateDuration,ease:an.animateEase,queue:false,step:aw})},getContentPositionX:function(){return j()},getContentPositionY:function(){return g()},getContentPane:function(){return ad},scrollToBottom:function(s){L(A,s)},hijackInternalLinks:function(){i()}})}f=b.extend({},b.fn.jScrollPane.defaults,f);var e;this.each(function(){var g=b(this),h=g.data("jsp");if(h){h.reinitialise(f)}else{h=new d(g,f);g.data("jsp",h)}e=e?e.add(g):g});return e};b.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); \ No newline at end of file diff --git a/ajax/libs/jScrollPane/2.0.0beta12/jquery.jscrollpane.css b/ajax/libs/jScrollPane/2.0.0beta1/style/jquery.jscrollpane.css similarity index 100% rename from ajax/libs/jScrollPane/2.0.0beta12/jquery.jscrollpane.css rename to ajax/libs/jScrollPane/2.0.0beta1/style/jquery.jscrollpane.css diff --git a/ajax/libs/jScrollPane/2.0.0beta12/jquery.jscrollpane.min.css b/ajax/libs/jScrollPane/2.0.0beta1/style/jquery.jscrollpane.min.css similarity index 100% rename from ajax/libs/jScrollPane/2.0.0beta12/jquery.jscrollpane.min.css rename to ajax/libs/jScrollPane/2.0.0beta1/style/jquery.jscrollpane.min.css diff --git a/ajax/libs/jScrollPane/2.0.0beta10/script/jquery.jscrollpane.js b/ajax/libs/jScrollPane/2.0.0beta10/script/jquery.jscrollpane.js new file mode 100644 index 00000000000000..a3afb60b5679da --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.0beta10/script/jquery.jscrollpane.js @@ -0,0 +1,1389 @@ +/*! + * jScrollPane - v2.0.0beta10 - 2011-04-17 + * 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.0beta10, Last updated: 2011-04-17* +// +// 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) 2011 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 - tested in 1.4.2+ - reported to work in 1.3.x +// Browsers Tested - Firefox 3.6.8, Safari 5, Opera 10.6, Chrome 5.0, IE 6, 7, 8 +// +// About: Release History +// +// 2.0.0beta10 - (2011-04-17) cleaner required size calculation, improved keyboard support, stickToBottom/Left, other small fixes +// 2.0.0beta9 - (2011-01-31) new API methods, bug fixes and correct keyboard support for FF/OSX +// 2.0.0beta8 - (2011-01-29) touchscreen support, improved keyboard support +// 2.0.0beta7 - (2011-01-23) scroll speed consistent (thanks Aivo Paas) +// 2.0.0beta6 - (2010-12-07) scrollToElement horizontal support +// 2.0.0beta5 - (2010-10-18) jQuery 1.4.3 support, various bug fixes +// 2.0.0beta4 - (2010-09-17) clickOnTrack support, bug fixes +// 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, previousContentWidth, + wasAtTop = true, wasAtLeft = true, wasAtBottom = false, wasAtRight = false, + originalElement = elem.clone(false, false).empty(), + 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'), 10) || 0) + + (parseInt(elem.css('paddingRight'), 10) || 0); + + function initialise(s) + { + + var /*firstChild, lastChild, */isMaintainingPositon, lastContentX, lastContentY, + hasContainingSpaceChanged, originalScrollTop, originalScrollLeft, + maintainAtBottom = false, maintainAtRight = false; + + settings = s; + + if (pane === undefined) { + originalScrollTop = elem.scrollTop(); + originalScrollLeft = elem.scrollLeft(); + + 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 = $('
').css('padding', originalPadding).append(elem.children()); + container = $('
') + .css({ + 'width': paneWidth + 'px', + 'height': paneHeight + 'px' + } + ).append(pane).appendTo(elem); + + /* + // 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', ''); + + maintainAtBottom = settings.stickToBottom && isCloseToBottom(); + maintainAtRight = settings.stickToRight && isCloseToRight(); + + hasContainingSpaceChanged = elem.innerWidth() + originalPaddingTotalWidth != paneWidth || elem.outerHeight() != paneHeight; + + if (hasContainingSpaceChanged) { + paneWidth = elem.innerWidth() + originalPaddingTotalWidth; + paneHeight = elem.innerHeight(); + container.css({ + width: paneWidth + 'px', + height: paneHeight + 'px' + }); + } + + // If nothing changed since last check... + if (!hasContainingSpaceChanged && previousContentWidth == contentWidth && pane.outerHeight() == contentHeight) { + elem.width(paneWidth); + return; + } + previousContentWidth = contentWidth; + + pane.css('width', ''); + elem.width(paneWidth); + + container.find('>.jspVerticalBar,>.jspHorizontalBar').remove().end(); + } + + pane.css('overflow', 'auto'); + if (s.contentWidth) { + contentWidth = s.contentWidth; + } else { + contentWidth = pane[0].scrollWidth; + } + contentHeight = pane[0].scrollHeight; + pane.css('overflow', ''); + + 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() - originalPaddingTotalWidth + }); + removeMousewheel(); + removeFocusHandler(); + removeKeyboardNav(); + removeClickOnTrack(); + unhijackInternalLinks(); + } else { + elem.addClass('jspScrollable'); + + isMaintainingPositon = settings.maintainPosition && (verticalDragPosition || horizontalDragPosition); + if (isMaintainingPositon) { + lastContentX = contentPositionX(); + lastContentY = contentPositionY(); + } + + initialiseVerticalScroll(); + initialiseHorizontalScroll(); + resizeScrollbars(); + + if (isMaintainingPositon) { + scrollToX(maintainAtRight ? (contentWidth - paneWidth ) : lastContentX, false); + scrollToY(maintainAtBottom ? (contentHeight - paneHeight) : lastContentY, false); + } + + initFocusHandler(); + initMousewheel(); + initTouch(); + + if (settings.enableKeyboardNavigation) { + initKeyboardNav(); + } + if (settings.clickOnTrack) { + initClickOnTrack(); + } + + observeHash(); + if (settings.hijackInternalLinks) { + hijackInternalLinks(); + } + } + + if (settings.autoReinitialise && !reinitialiseInterval) { + reinitialiseInterval = setInterval( + function() + { + initialise(settings); + }, + settings.autoReinitialiseDelay + ); + } else if (!settings.autoReinitialise && reinitialiseInterval) { + clearInterval(reinitialiseInterval); + } + + originalScrollTop && elem.scrollTop(0) && scrollToY(originalScrollTop, false); + originalScrollLeft && elem.scrollLeft(0) && scrollToX(originalScrollLeft, false); + + elem.trigger('jsp-initialised', [isScrollableH || isScrollableV]); + } + + function initialiseVerticalScroll() + { + if (isScrollableV) { + + container.append( + $('
').append( + $('
'), + $('
').append( + $('
').append( + $('
'), + $('
') + ) + ), + $('
') + ) + ); + + verticalBar = container.find('>.jspVerticalBar'); + verticalTrack = verticalBar.find('>.jspTrack'); + verticalDrag = verticalTrack.find('>.jspDrag'); + + if (settings.showArrows) { + arrowUp = $('').bind( + 'mousedown.jsp', getArrowScroll(0, -1) + ).bind('click.jsp', nil); + arrowDown = $('').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', nil); + + 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(); + } + } + + 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) + try { + if (verticalBar.position().left === 0) { + pane.css('margin-left', scrollbarWidth + 'px'); + } + } catch (err) { + } + } + + function initialiseHorizontalScroll() + { + if (isScrollableH) { + + container.append( + $('
').append( + $('
'), + $('
').append( + $('
').append( + $('
'), + $('
') + ) + ), + $('
') + ) + ); + + horizontalBar = container.find('>.jspHorizontalBar'); + horizontalTrack = horizontalBar.find('>.jspTrack'); + horizontalDrag = horizontalTrack.find('>.jspDrag'); + + if (settings.showArrows) { + arrowLeft = $('').bind( + 'mousedown.jsp', getArrowScroll(-1, 0) + ).bind('click.jsp', nil); + arrowRight = $('').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', nil); + + 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(); + } + } + + 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( + $('
').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 = Math.ceil(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; + _positionDragX(horizontalDragPosition); // To update the state for the arrow buttons + } + if (isScrollableV) { + verticalDragHeight = Math.ceil(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; + _positionDragY(verticalDragPosition); // To update the state for the arrow buttons + } + } + + 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, + scrollTimeout, + isFirst = true, + doScroll = function() + { + if (dirX !== 0) { + jsp.scrollByX(dirX * settings.arrowButtonSpeed); + } + if (dirY !== 0) { + jsp.scrollByY(dirY * settings.arrowButtonSpeed); + } + scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.arrowRepeatFreq); + isFirst = false; + }; + + doScroll(); + + eve = ele ? 'mouseout.jsp' : 'mouseup.jsp'; + ele = ele || $('html'); + ele.bind( + eve, + function() + { + arrow.removeClass('jspActive'); + scrollTimeout && clearTimeout(scrollTimeout); + scrollTimeout = null; + ele.unbind(eve); + } + ); + } + + function initClickOnTrack() + { + removeClickOnTrack(); + if (isScrollableV) { + verticalTrack.bind( + 'mousedown.jsp', + function(e) + { + if (e.originalTarget === undefined || e.originalTarget == e.currentTarget) { + var clickedTrack = $(this), + offset = clickedTrack.offset(), + direction = e.pageY - offset.top - verticalDragPosition, + scrollTimeout, + isFirst = true, + doScroll = function() + { + var offset = clickedTrack.offset(), + pos = e.pageY - offset.top - verticalDragHeight / 2, + contentDragY = paneHeight * settings.scrollPagePercent, + dragY = dragMaxY * contentDragY / (contentHeight - paneHeight); + if (direction < 0) { + if (verticalDragPosition - dragY > pos) { + jsp.scrollByY(-contentDragY); + } else { + positionDragY(pos); + } + } else if (direction > 0) { + if (verticalDragPosition + dragY < pos) { + jsp.scrollByY(contentDragY); + } else { + positionDragY(pos); + } + } else { + cancelClick(); + return; + } + scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.trackClickRepeatFreq); + isFirst = false; + }, + cancelClick = function() + { + scrollTimeout && clearTimeout(scrollTimeout); + scrollTimeout = null; + $(document).unbind('mouseup.jsp', cancelClick); + }; + doScroll(); + $(document).bind('mouseup.jsp', cancelClick); + return false; + } + } + ); + } + + if (isScrollableH) { + horizontalTrack.bind( + 'mousedown.jsp', + function(e) + { + if (e.originalTarget === undefined || e.originalTarget == e.currentTarget) { + var clickedTrack = $(this), + offset = clickedTrack.offset(), + direction = e.pageX - offset.left - horizontalDragPosition, + scrollTimeout, + isFirst = true, + doScroll = function() + { + var offset = clickedTrack.offset(), + pos = e.pageX - offset.left - horizontalDragWidth / 2, + contentDragX = paneWidth * settings.scrollPagePercent, + dragX = dragMaxX * contentDragX / (contentWidth - paneWidth); + if (direction < 0) { + if (horizontalDragPosition - dragX > pos) { + jsp.scrollByX(-contentDragX); + } else { + positionDragX(pos); + } + } else if (direction > 0) { + if (horizontalDragPosition + dragX < pos) { + jsp.scrollByX(contentDragX); + } else { + positionDragX(pos); + } + } else { + cancelClick(); + return; + } + scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.trackClickRepeatFreq); + isFirst = false; + }, + cancelClick = function() + { + scrollTimeout && clearTimeout(scrollTimeout); + scrollTimeout = null; + $(document).unbind('mouseup.jsp', cancelClick); + }; + doScroll(); + $(document).bind('mouseup.jsp', cancelClick); + return false; + } + } + ); + } + } + + function removeClickOnTrack() + { + if (horizontalTrack) { + horizontalTrack.unbind('mousedown.jsp'); + } + if (verticalTrack) { + verticalTrack.unbind('mousedown.jsp'); + } + } + + function cancelDrag() + { + $('html').unbind('dragstart.jsp selectstart.jsp mousemove.jsp mouseup.jsp mouseleave.jsp'); + + if (verticalDrag) { + verticalDrag.removeClass('jspActive'); + } + if (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]).trigger('scroll'); + } + + 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 == dragMaxX, + 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]).trigger('scroll'); + } + + 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, eleWidth, eleTop = 0, eleLeft = 0, viewportTop, viewportLeft, maxVisibleEleTop, maxVisibleEleLeft, destY, destX; + + // 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(); + eleWidth= e.outerWidth(); + + container.scrollTop(0); + container.scrollLeft(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; + eleLeft += e.position().left; + 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); + } + + viewportLeft = contentPositionX(); + maxVisibleEleLeft = viewportLeft + paneWidth; + if (eleLeft < viewportLeft || stickToTop) { // element is to the left of viewport + destX = eleLeft - settings.horizontalGutter; + } else if (eleLeft + eleWidth > maxVisibleEleLeft) { // element is to the right viewport + destX = eleLeft - paneWidth + eleWidth + settings.horizontalGutter; + } + if (destX) { + scrollToX(destX, animate); + } + + } + + function contentPositionX() + { + return -pane.position().left; + } + + function contentPositionY() + { + return -pane.position().top; + } + + function isCloseToBottom() + { + var scrollableHeight = contentHeight - paneHeight; + return (scrollableHeight > 20) && (scrollableHeight - contentPositionY() < 10); + } + + function isCloseToRight() + { + var scrollableWidth = contentWidth - paneWidth; + return (scrollableWidth > 20) && (scrollableWidth - contentPositionX() < 10); + } + + function initMousewheel() + { + container.unbind(mwEvent).bind( + mwEvent, + function (event, delta, deltaX, deltaY) { + var dX = horizontalDragPosition, dY = verticalDragPosition; + jsp.scrollBy(deltaX * settings.mouseWheelSpeed, -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.find(':input,a').unbind('focus.jsp').bind( + 'focus.jsp', + function(e) + { + scrollToElement(e.target, false); + } + ); + } + + function removeFocusHandler() + { + pane.find(':input,a').unbind('focus.jsp'); + } + + function initKeyboardNav() + { + var keyDown, elementHasScrolled, validParents = []; + isScrollableH && validParents.push(horizontalBar[0]); + isScrollableV && validParents.push(verticalBar[0]); + + // IE also focuses elements that don't have tabindex set. + pane.focus( + function() + { + elem.focus(); + } + ); + + elem.attr('tabindex', 0) + .unbind('keydown.jsp keypress.jsp') + .bind( + 'keydown.jsp', + function(e) + { + if (e.target !== this && !(validParents.length && $(e.target).closest(validParents).length)){ + return; + } + var dX = horizontalDragPosition, dY = verticalDragPosition; + switch(e.keyCode) { + case 40: // down + case 38: // up + case 34: // page down + case 32: // space + case 33: // page up + case 39: // right + case 37: // left + keyDown = e.keyCode; + keyDownHandler(); + break; + case 35: // end + scrollToY(contentHeight - paneHeight); + keyDown = null; + break; + case 36: // home + scrollToY(0); + keyDown = null; + break; + } + + elementHasScrolled = e.keyCode == keyDown && dX != horizontalDragPosition || dY != verticalDragPosition; + return !elementHasScrolled; + } + ).bind( + 'keypress.jsp', // For FF/ OSX so that we can cancel the repeat key presses if the JSP scrolls... + function(e) + { + if (e.keyCode == keyDown) { + keyDownHandler(); + } + return !elementHasScrolled; + } + ); + + 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 keyDownHandler() + { + var dX = horizontalDragPosition, dY = verticalDragPosition; + switch(keyDown) { + case 40: // down + jsp.scrollByY(settings.keyboardSpeed, false); + break; + case 38: // up + jsp.scrollByY(-settings.keyboardSpeed, false); + break; + case 34: // page down + case 32: // space + jsp.scrollByY(paneHeight * settings.scrollPagePercent, false); + break; + case 33: // page up + jsp.scrollByY(-paneHeight * settings.scrollPagePercent, false); + break; + case 39: // right + jsp.scrollByX(settings.keyboardSpeed, false); + break; + case 37: // left + jsp.scrollByX(-settings.keyboardSpeed, false); + break; + } + + elementHasScrolled = dX != horizontalDragPosition || dY != verticalDragPosition; + return elementHasScrolled; + } + } + + function removeKeyboardNav() + { + elem.attr('tabindex', '-1') + .removeAttr('tabindex') + .unbind('keydown.jsp keypress.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(location.hash)) { + // 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; + } + } + } + ); + } + + // Init touch on iPad, iPhone, iPod, Android + function initTouch() + { + var startX, + startY, + touchStartX, + touchStartY, + moved, + moving = false; + + container.unbind('touchstart.jsp touchmove.jsp touchend.jsp click.jsp-touchclick').bind( + 'touchstart.jsp', + function(e) + { + var touch = e.originalEvent.touches[0]; + startX = contentPositionX(); + startY = contentPositionY(); + touchStartX = touch.pageX; + touchStartY = touch.pageY; + moved = false; + moving = true; + } + ).bind( + 'touchmove.jsp', + function(ev) + { + if(!moving) { + return; + } + + var touchPos = ev.originalEvent.touches[0], + dX = horizontalDragPosition, dY = verticalDragPosition; + + jsp.scrollTo(startX + touchStartX - touchPos.pageX, startY + touchStartY - touchPos.pageY); + + moved = moved || Math.abs(touchStartX - touchPos.pageX) > 5 || Math.abs(touchStartY - touchPos.pageY) > 5; + + // return true if there was no movement so rest of screen can scroll + return dX == horizontalDragPosition && dY == verticalDragPosition; + } + ).bind( + 'touchend.jsp', + function(e) + { + moving = false; + /*if(moved) { + return false; + }*/ + } + ).bind( + 'click.jsp-touchclick', + function(e) + { + if(moved) { + moved = false; + return false; + } + } + ); + } + + function destroy(){ + var currentY = contentPositionY(), + currentX = contentPositionX(); + elem.removeClass('jspScrollable').unbind('.jsp'); + elem.replaceWith(originalElement.append(pane.children())); + originalElement.scrollTop(currentY); + originalElement.scrollLeft(currentX); + } + + // 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({}, settings, s); + 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 to the specified percentage of its maximum horizontal scroll position. animate + // is optional and if not passed then the value of animateScroll from the settings object this + // jScrollPane was initialised with is used. + scrollToPercentX: function(destPercentX, animate) + { + scrollToX(destPercentX * (contentWidth - paneWidth), animate); + }, + // Scrolls the pane to the specified percentage of its maximum vertical scroll position. animate + // is optional and if not passed then the value of animateScroll from the settings object this + // jScrollPane was initialised with is used. + scrollToPercentY: function(destPercentY, animate) + { + scrollToY(destPercentY * (contentHeight - paneHeight), 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); + }, + // Positions the horizontal drag at the specified x position (and updates the viewport to reflect + // this). animate is optional and if not passed then the value of animateScroll from the settings + // object this jScrollPane was initialised with is used. + positionDragX: function(x, animate) + { + positionDragX(x, animate); + }, + // Positions the vertical drag at the specified y position (and updates the viewport to reflect + // this). animate is optional and if not passed then the value of animateScroll from the settings + // object this jScrollPane was initialised with is used. + positionDragY: function(y, animate) + { + positionDragY(y, 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 the width of the content within the scroll pane. + getContentWidth: function() + { + return contentWidth; + }, + // Returns the height of the content within the scroll pane. + getContentHeight: function() + { + return contentHeight; + }, + // Returns the horizontal position of the viewport within the pane content. + getPercentScrolledX: function() + { + return contentPositionX() / (contentWidth - paneWidth); + }, + // Returns the vertical position of the viewport within the pane content. + getPercentScrolledY: function() + { + return contentPositionY() / (contentHeight - paneHeight); + }, + // 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(); + }, + // Removes the jScrollPane and returns the page to the state it was in before jScrollPane was + // initialised. + destroy: function() + { + destroy(); + } + } + ); + + initialise(s); + } + + // Pluginifying code... + settings = $.extend({}, $.fn.jScrollPane.defaults, settings); + + // Apply default speed + $.each(['mouseWheelSpeed', 'arrowButtonSpeed', 'trackClickSpeed', 'keyboardSpeed'], function() { + settings[this] = settings[this] || settings.speed; + }); + + 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, + stickToBottom : false, + stickToRight : false, + clickOnTrack : true, + autoReinitialise : false, + autoReinitialiseDelay : 500, + verticalDragMinHeight : 0, + verticalDragMaxHeight : 99999, + horizontalDragMinWidth : 0, + horizontalDragMaxWidth : 99999, + contentWidth : undefined, + animateScroll : false, + animateDuration : 300, + animateEase : 'linear', + hijackInternalLinks : false, + verticalGutter : 4, + horizontalGutter : 4, + mouseWheelSpeed : 0, + arrowButtonSpeed : 0, + arrowRepeatFreq : 50, + arrowScrollOnHover : false, + trackClickSpeed : 0, + trackClickRepeatFreq : 70, + verticalArrowPositions : 'split', + horizontalArrowPositions : 'split', + enableKeyboardNavigation : true, + hideFocus : false, + keyboardSpeed : 0, + initialDelay : 300, // Delay before starting repeating + speed : 30, // Default speed when others falsey + scrollPagePercent : .8 // Percent of visible area scrolled when pageUp/Down or track area pressed + }; + +})(jQuery,this); + diff --git a/ajax/libs/jScrollPane/2.0.0beta10/script/jquery.jscrollpane.min.js b/ajax/libs/jScrollPane/2.0.0beta10/script/jquery.jscrollpane.min.js new file mode 100644 index 00000000000000..57423356af59c9 --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.0beta10/script/jquery.jscrollpane.min.js @@ -0,0 +1,11 @@ +/* + * jScrollPane - v2.0.0beta10 - 2011-04-17 + * http://jscrollpane.kelvinluck.com/ + * + * Copyright (c) 2010 Kelvin Luck + * Dual licensed under the MIT and GPL licenses. + */ +(function(b,a,c){b.fn.jScrollPane=function(f){function d(E,P){var aA,R=this,Z,al,w,an,U,aa,z,r,aB,aG,aw,j,J,i,k,ab,V,ar,Y,u,B,at,ag,ao,H,m,av,az,y,ax,aJ,g,M,ak=true,Q=true,aI=false,l=false,aq=E.clone(false,false).empty(),ad=b.fn.mwheelIntent?"mwheelIntent.jsp":"mousewheel.jsp";aJ=E.css("paddingTop")+" "+E.css("paddingRight")+" "+E.css("paddingBottom")+" "+E.css("paddingLeft");g=(parseInt(E.css("paddingLeft"),10)||0)+(parseInt(E.css("paddingRight"),10)||0);function au(aS){var aN,aP,aO,aL,aK,aR,aQ=false,aM=false;aA=aS;if(Z===c){aK=E.scrollTop();aR=E.scrollLeft();E.css({overflow:"hidden",padding:0});al=E.innerWidth()+g;w=E.innerHeight();E.width(al);Z=b('
').css("padding",aJ).append(E.children());an=b('
').css({width:al+"px",height:w+"px"}).append(Z).appendTo(E)}else{E.css("width","");aQ=aA.stickToBottom&&L();aM=aA.stickToRight&&C();aL=E.innerWidth()+g!=al||E.outerHeight()!=w;if(aL){al=E.innerWidth()+g;w=E.innerHeight();an.css({width:al+"px",height:w+"px"})}if(!aL&&M==U&&Z.outerHeight()==aa){E.width(al);return}M=U;Z.css("width","");E.width(al);an.find(">.jspVerticalBar,>.jspHorizontalBar").remove().end()}Z.css("overflow","auto");if(aS.contentWidth){U=aS.contentWidth}else{U=Z[0].scrollWidth}aa=Z[0].scrollHeight;Z.css("overflow","");z=U/al;r=aa/w;aB=r>1;aG=z>1;if(!(aG||aB)){E.removeClass("jspScrollable");Z.css({top:0,width:an.width()-g});o();F();S();x();aj()}else{E.addClass("jspScrollable");aN=aA.maintainPosition&&(J||ab);if(aN){aP=aE();aO=aC()}aH();A();G();if(aN){O(aM?(U-al):aP,false);N(aQ?(aa-w):aO,false)}K();ah();ap();if(aA.enableKeyboardNavigation){T()}if(aA.clickOnTrack){q()}D();if(aA.hijackInternalLinks){n()}}if(aA.autoReinitialise&&!ax){ax=setInterval(function(){au(aA)},aA.autoReinitialiseDelay)}else{if(!aA.autoReinitialise&&ax){clearInterval(ax)}}aK&&E.scrollTop(0)&&N(aK,false);aR&&E.scrollLeft(0)&&O(aR,false);E.trigger("jsp-initialised",[aG||aB])}function aH(){if(aB){an.append(b('
').append(b('
'),b('
').append(b('
').append(b('
'),b('
'))),b('
')));V=an.find(">.jspVerticalBar");ar=V.find(">.jspTrack");aw=ar.find(">.jspDrag");if(aA.showArrows){at=b('').bind("mousedown.jsp",aF(0,-1)).bind("click.jsp",aD);ag=b('').bind("mousedown.jsp",aF(0,1)).bind("click.jsp",aD);if(aA.arrowScrollOnHover){at.bind("mouseover.jsp",aF(0,-1,at));ag.bind("mouseover.jsp",aF(0,1,ag))}am(ar,aA.verticalArrowPositions,at,ag)}u=w;an.find(">.jspVerticalBar>.jspCap:visible,>.jspVerticalBar>.jspArrow").each(function(){u-=b(this).outerHeight()});aw.hover(function(){aw.addClass("jspHover")},function(){aw.removeClass("jspHover")}).bind("mousedown.jsp",function(aK){b("html").bind("dragstart.jsp selectstart.jsp",aD);aw.addClass("jspActive");var s=aK.pageY-aw.position().top;b("html").bind("mousemove.jsp",function(aL){W(aL.pageY-s,false)}).bind("mouseup.jsp mouseleave.jsp",ay);return false});p()}}function p(){ar.height(u+"px");J=0;Y=aA.verticalGutter+ar.outerWidth();Z.width(al-Y-g);try{if(V.position().left===0){Z.css("margin-left",Y+"px")}}catch(s){}}function A(){if(aG){an.append(b('
').append(b('
'),b('
').append(b('
').append(b('
'),b('
'))),b('
')));ao=an.find(">.jspHorizontalBar");H=ao.find(">.jspTrack");i=H.find(">.jspDrag");if(aA.showArrows){az=b('').bind("mousedown.jsp",aF(-1,0)).bind("click.jsp",aD);y=b('').bind("mousedown.jsp",aF(1,0)).bind("click.jsp",aD); +if(aA.arrowScrollOnHover){az.bind("mouseover.jsp",aF(-1,0,az));y.bind("mouseover.jsp",aF(1,0,y))}am(H,aA.horizontalArrowPositions,az,y)}i.hover(function(){i.addClass("jspHover")},function(){i.removeClass("jspHover")}).bind("mousedown.jsp",function(aK){b("html").bind("dragstart.jsp selectstart.jsp",aD);i.addClass("jspActive");var s=aK.pageX-i.position().left;b("html").bind("mousemove.jsp",function(aL){X(aL.pageX-s,false)}).bind("mouseup.jsp mouseleave.jsp",ay);return false});m=an.innerWidth();ai()}}function ai(){an.find(">.jspHorizontalBar>.jspCap:visible,>.jspHorizontalBar>.jspArrow").each(function(){m-=b(this).outerWidth()});H.width(m+"px");ab=0}function G(){if(aG&&aB){var aK=H.outerHeight(),s=ar.outerWidth();u-=aK;b(ao).find(">.jspCap:visible,>.jspArrow").each(function(){m+=b(this).outerWidth()});m-=s;w-=s;al-=aK;H.parent().append(b('
').css("width",aK+"px"));p();ai()}if(aG){Z.width((an.outerWidth()-g)+"px")}aa=Z.outerHeight();r=aa/w;if(aG){av=Math.ceil(1/z*m);if(av>aA.horizontalDragMaxWidth){av=aA.horizontalDragMaxWidth}else{if(avaA.verticalDragMaxHeight){B=aA.verticalDragMaxHeight}else{if(BaU){R.scrollByY(-aR)}else{W(aU)}}else{if(aO>0){if(J+aSaU){R.scrollByX(-aR)}else{X(aU)}}else{if(aO>0){if(ab+aSj){s=j}}if(aK===c){aK=aA.animateScroll}if(aK){R.animate(aw,"top",s,ae)}else{aw.css("top",s);ae(s)}}function ae(aK){if(aK===c){aK=aw.position().top}an.scrollTop(0);J=aK;var aN=J===0,aL=J==j,aM=aK/j,s=-aM*(aa-w);if(ak!=aN||aI!=aL){ak=aN;aI=aL;E.trigger("jsp-arrow-change",[ak,aI,Q,l])}v(aN,aL);Z.css("top",s);E.trigger("jsp-scroll-y",[-s,aN,aL]).trigger("scroll")}function X(aK,s){if(!aG){return}if(aK<0){aK=0}else{if(aK>k){aK=k}}if(s===c){s=aA.animateScroll}if(s){R.animate(i,"left",aK,af) +}else{i.css("left",aK);af(aK)}}function af(aK){if(aK===c){aK=i.position().left}an.scrollTop(0);ab=aK;var aN=ab===0,aM=ab==k,aL=aK/k,s=-aL*(U-al);if(Q!=aN||l!=aM){Q=aN;l=aM;E.trigger("jsp-arrow-change",[ak,aI,Q,l])}t(aN,aM);Z.css("left",s);E.trigger("jsp-scroll-x",[-s,aN,aM]).trigger("scroll")}function v(aK,s){if(aA.showArrows){at[aK?"addClass":"removeClass"]("jspDisabled");ag[s?"addClass":"removeClass"]("jspDisabled")}}function t(aK,s){if(aA.showArrows){az[aK?"addClass":"removeClass"]("jspDisabled");y[s?"addClass":"removeClass"]("jspDisabled")}}function N(s,aK){var aL=s/(aa-w);W(aL*j,aK)}function O(aK,s){var aL=aK/(U-al);X(aL*k,s)}function ac(aX,aS,aL){var aP,aM,aN,s=0,aW=0,aK,aR,aQ,aU,aT,aV;try{aP=b(aX)}catch(aO){return}aM=aP.outerHeight();aN=aP.outerWidth();an.scrollTop(0);an.scrollLeft(0);while(!aP.is(".jspPane")){s+=aP.position().top;aW+=aP.position().left;aP=aP.offsetParent();if(/^body|html$/i.test(aP[0].nodeName)){return}}aK=aC();aQ=aK+w;if(saQ){aT=s-w+aM+aA.verticalGutter}}if(aT){N(aT,aL)}aR=aE();aU=aR+al;if(aWaU){aV=aW-al+aN+aA.horizontalGutter}}if(aV){O(aV,aL)}}function aE(){return -Z.position().left}function aC(){return -Z.position().top}function L(){var s=aa-w;return(s>20)&&(s-aC()<10)}function C(){var s=U-al;return(s>20)&&(s-aE()<10)}function ah(){an.unbind(ad).bind(ad,function(aN,aO,aM,aK){var aL=ab,s=J;R.scrollBy(aM*aA.mouseWheelSpeed,-aK*aA.mouseWheelSpeed,false);return aL==ab&&s==J})}function o(){an.unbind(ad)}function aD(){return false}function K(){Z.find(":input,a").unbind("focus.jsp").bind("focus.jsp",function(s){ac(s.target,false)})}function F(){Z.find(":input,a").unbind("focus.jsp")}function T(){var s,aK,aM=[];aG&&aM.push(ao[0]);aB&&aM.push(V[0]);Z.focus(function(){E.focus()});E.attr("tabindex",0).unbind("keydown.jsp keypress.jsp").bind("keydown.jsp",function(aP){if(aP.target!==this&&!(aM.length&&b(aP.target).closest(aM).length)){return}var aO=ab,aN=J;switch(aP.keyCode){case 40:case 38:case 34:case 32:case 33:case 39:case 37:s=aP.keyCode;aL();break;case 35:N(aa-w);s=null;break;case 36:N(0);s=null;break}aK=aP.keyCode==s&&aO!=ab||aN!=J;return !aK}).bind("keypress.jsp",function(aN){if(aN.keyCode==s){aL()}return !aK});if(aA.hideFocus){E.css("outline","none");if("hideFocus" in an[0]){E.attr("hideFocus",true)}}else{E.css("outline","");if("hideFocus" in an[0]){E.attr("hideFocus",false)}}function aL(){var aO=ab,aN=J;switch(s){case 40:R.scrollByY(aA.keyboardSpeed,false);break;case 38:R.scrollByY(-aA.keyboardSpeed,false);break;case 34:case 32:R.scrollByY(w*aA.scrollPagePercent,false);break;case 33:R.scrollByY(-w*aA.scrollPagePercent,false);break;case 39:R.scrollByX(aA.keyboardSpeed,false);break;case 37:R.scrollByX(-aA.keyboardSpeed,false);break}aK=aO!=ab||aN!=J;return aK}}function S(){E.attr("tabindex","-1").removeAttr("tabindex").unbind("keydown.jsp keypress.jsp")}function D(){if(location.hash&&location.hash.length>1){var aL,aK;try{aL=b(location.hash)}catch(s){return}if(aL.length&&Z.find(location.hash)){if(an.scrollTop()===0){aK=setInterval(function(){if(an.scrollTop()>0){ac(location.hash,true);b(document).scrollTop(an.position().top);clearInterval(aK)}},50)}else{ac(location.hash,true);b(document).scrollTop(an.position().top)}}}}function aj(){b("a.jspHijack").unbind("click.jsp-hijack").removeClass("jspHijack")}function n(){aj();b("a[href^=#]").addClass("jspHijack").bind("click.jsp-hijack",function(){var s=this.href.split("#"),aK;if(s.length>1){aK=s[1];if(aK.length>0&&Z.find("#"+aK).length>0){ac("#"+aK,true);return false}}})}function ap(){var aL,aK,aN,aM,aO,s=false;an.unbind("touchstart.jsp touchmove.jsp touchend.jsp click.jsp-touchclick").bind("touchstart.jsp",function(aP){var aQ=aP.originalEvent.touches[0];aL=aE();aK=aC();aN=aQ.pageX;aM=aQ.pageY;aO=false;s=true}).bind("touchmove.jsp",function(aS){if(!s){return}var aR=aS.originalEvent.touches[0],aQ=ab,aP=J;R.scrollTo(aL+aN-aR.pageX,aK+aM-aR.pageY);aO=aO||Math.abs(aN-aR.pageX)>5||Math.abs(aM-aR.pageY)>5; +return aQ==ab&&aP==J}).bind("touchend.jsp",function(aP){s=false}).bind("click.jsp-touchclick",function(aP){if(aO){aO=false;return false}})}function h(){var s=aC(),aK=aE();E.removeClass("jspScrollable").unbind(".jsp");E.replaceWith(aq.append(Z.children()));aq.scrollTop(s);aq.scrollLeft(aK)}b.extend(R,{reinitialise:function(aK){aK=b.extend({},aA,aK);au(aK)},scrollToElement:function(aL,aK,s){ac(aL,aK,s)},scrollTo:function(aL,s,aK){O(aL,aK);N(s,aK)},scrollToX:function(aK,s){O(aK,s)},scrollToY:function(s,aK){N(s,aK)},scrollToPercentX:function(aK,s){O(aK*(U-al),s)},scrollToPercentY:function(aK,s){N(aK*(aa-w),s)},scrollBy:function(aK,s,aL){R.scrollByX(aK,aL);R.scrollByY(s,aL)},scrollByX:function(s,aL){var aK=aE()+s,aM=aK/(U-al);X(aM*k,aL)},scrollByY:function(s,aL){var aK=aC()+s,aM=aK/(aa-w);W(aM*j,aL)},positionDragX:function(s,aK){X(s,aK)},positionDragY:function(aK,s){W(aK,s)},animate:function(aK,aN,s,aM){var aL={};aL[aN]=s;aK.animate(aL,{duration:aA.animateDuration,ease:aA.animateEase,queue:false,step:aM})},getContentPositionX:function(){return aE()},getContentPositionY:function(){return aC()},getContentWidth:function(){return U},getContentHeight:function(){return aa},getPercentScrolledX:function(){return aE()/(U-al)},getPercentScrolledY:function(){return aC()/(aa-w)},getIsScrollableH:function(){return aG},getIsScrollableV:function(){return aB},getContentPane:function(){return Z},scrollToBottom:function(s){W(j,s)},hijackInternalLinks:function(){n()},destroy:function(){h()}});au(P)}f=b.extend({},b.fn.jScrollPane.defaults,f);b.each(["mouseWheelSpeed","arrowButtonSpeed","trackClickSpeed","keyboardSpeed"],function(){f[this]=f[this]||f.speed});var e;this.each(function(){var g=b(this),h=g.data("jsp");if(h){h.reinitialise(f)}else{h=new d(g,f);g.data("jsp",h)}e=e?e.add(g):g});return e};b.fn.jScrollPane.defaults={showArrows:false,maintainPosition:true,stickToBottom:false,stickToRight:false,clickOnTrack:true,autoReinitialise:false,autoReinitialiseDelay:500,verticalDragMinHeight:0,verticalDragMaxHeight:99999,horizontalDragMinWidth:0,horizontalDragMaxWidth:99999,contentWidth:c,animateScroll:false,animateDuration:300,animateEase:"linear",hijackInternalLinks:false,verticalGutter:4,horizontalGutter:4,mouseWheelSpeed:0,arrowButtonSpeed:0,arrowRepeatFreq:50,arrowScrollOnHover:false,trackClickSpeed:0,trackClickRepeatFreq:70,verticalArrowPositions:"split",horizontalArrowPositions:"split",enableKeyboardNavigation:true,hideFocus:false,keyboardSpeed:0,initialDelay:300,speed:30,scrollPagePercent:0.8}})(jQuery,this); \ No newline at end of file diff --git a/ajax/libs/jScrollPane/2.0.0beta10/style/jquery.jscrollpane.css b/ajax/libs/jScrollPane/2.0.0beta10/style/jquery.jscrollpane.css new file mode 100644 index 00000000000000..a051caed0a41b7 --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.0beta10/style/jquery.jscrollpane.css @@ -0,0 +1,120 @@ +/* + * CSS Styles that are needed by jScrollPane for it to operate correctly. + * + * Include this stylesheet in your site or copy and paste the styles below into your stylesheet - jScrollPane + * may not operate correctly without them. + */ + +.jspContainer +{ + overflow: hidden; + position: relative; +} + +.jspPane +{ + position: absolute; +} + +.jspVerticalBar +{ + position: absolute; + top: 0; + right: 0; + width: 16px; + height: 100%; + background: red; +} + +.jspHorizontalBar +{ + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 16px; + background: red; +} + +.jspVerticalBar *, +.jspHorizontalBar * +{ + margin: 0; + padding: 0; +} + +.jspCap +{ + display: none; +} + +.jspHorizontalBar .jspCap +{ + float: left; +} + +.jspTrack +{ + background: #dde; + position: relative; +} + +.jspDrag +{ + background: #bbd; + position: relative; + top: 0; + left: 0; + cursor: pointer; +} + +.jspHorizontalBar .jspTrack, +.jspHorizontalBar .jspDrag +{ + float: left; + height: 100%; +} + +.jspArrow +{ + background: #50506d; + text-indent: -20000px; + display: block; + cursor: pointer; +} + +.jspArrow.jspDisabled +{ + cursor: default; + background: #80808d; +} + +.jspVerticalBar .jspArrow +{ + height: 16px; +} + +.jspHorizontalBar .jspArrow +{ + width: 16px; + float: left; + height: 100%; +} + +.jspVerticalBar .jspArrow:focus +{ + outline: none; +} + +.jspCorner +{ + background: #eeeef4; + float: left; + height: 100%; +} + +/* Yuk! CSS Hack for IE6 3 pixel bug :( */ +* html .jspCorner +{ + margin: 0 -3px 0 0; +} \ No newline at end of file diff --git a/ajax/libs/jScrollPane/2.0.14/jquery.jscrollpane.min.css b/ajax/libs/jScrollPane/2.0.0beta10/style/jquery.jscrollpane.min.css similarity index 100% rename from ajax/libs/jScrollPane/2.0.14/jquery.jscrollpane.min.css rename to ajax/libs/jScrollPane/2.0.0beta10/style/jquery.jscrollpane.min.css diff --git a/ajax/libs/jScrollPane/2.0.0beta11/script/jquery.jscrollpane.js b/ajax/libs/jScrollPane/2.0.0beta11/script/jquery.jscrollpane.js new file mode 100644 index 00000000000000..191c346403c15f --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.0beta11/script/jquery.jscrollpane.js @@ -0,0 +1,1434 @@ +/*! + * jScrollPane - v2.0.0beta11 - 2012-05-14 + * 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.0beta11, Last updated: 2012-05-14* +// +// 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) 2012 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 - tested in 1.4.2+ - reported to work in 1.3.x +// Browsers Tested - Firefox 3.6.8, Safari 5, Opera 10.6, Chrome 5.0, IE 6, 7, 8 +// +// About: Release History +// +// 2.0.0beta11 - (2012-05-14) +// 2.0.0beta10 - (2011-04-17) cleaner required size calculation, improved keyboard support, stickToBottom/Left, other small fixes +// 2.0.0beta9 - (2011-01-31) new API methods, bug fixes and correct keyboard support for FF/OSX +// 2.0.0beta8 - (2011-01-29) touchscreen support, improved keyboard support +// 2.0.0beta7 - (2011-01-23) scroll speed consistent (thanks Aivo Paas) +// 2.0.0beta6 - (2010-12-07) scrollToElement horizontal support +// 2.0.0beta5 - (2010-10-18) jQuery 1.4.3 support, various bug fixes +// 2.0.0beta4 - (2010-09-17) clickOnTrack support, bug fixes +// 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, previousContentWidth, + wasAtTop = true, wasAtLeft = true, wasAtBottom = false, wasAtRight = false, + originalElement = elem.clone(false, false).empty(), + 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'), 10) || 0) + + (parseInt(elem.css('paddingRight'), 10) || 0); + + function initialise(s) + { + + var /*firstChild, lastChild, */isMaintainingPositon, lastContentX, lastContentY, + hasContainingSpaceChanged, originalScrollTop, originalScrollLeft, + maintainAtBottom = false, maintainAtRight = false; + + settings = s; + + if (pane === undefined) { + originalScrollTop = elem.scrollTop(); + originalScrollLeft = elem.scrollLeft(); + + 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 = $('
').css('padding', originalPadding).append(elem.children()); + container = $('
') + .css({ + 'width': paneWidth + 'px', + 'height': paneHeight + 'px' + } + ).append(pane).appendTo(elem); + + /* + // 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', ''); + + maintainAtBottom = settings.stickToBottom && isCloseToBottom(); + maintainAtRight = settings.stickToRight && isCloseToRight(); + + hasContainingSpaceChanged = elem.innerWidth() + originalPaddingTotalWidth != paneWidth || elem.outerHeight() != paneHeight; + + if (hasContainingSpaceChanged) { + paneWidth = elem.innerWidth() + originalPaddingTotalWidth; + paneHeight = elem.innerHeight(); + container.css({ + width: paneWidth + 'px', + height: paneHeight + 'px' + }); + } + + // If nothing changed since last check... + if (!hasContainingSpaceChanged && previousContentWidth == contentWidth && pane.outerHeight() == contentHeight) { + elem.width(paneWidth); + return; + } + previousContentWidth = contentWidth; + + pane.css('width', ''); + elem.width(paneWidth); + + container.find('>.jspVerticalBar,>.jspHorizontalBar').remove().end(); + } + + pane.css('overflow', 'auto'); + if (s.contentWidth) { + contentWidth = s.contentWidth; + } else { + contentWidth = pane[0].scrollWidth; + } + contentHeight = pane[0].scrollHeight; + pane.css('overflow', ''); + + 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() - originalPaddingTotalWidth + }); + removeMousewheel(); + removeFocusHandler(); + removeKeyboardNav(); + removeClickOnTrack(); + } else { + elem.addClass('jspScrollable'); + + isMaintainingPositon = settings.maintainPosition && (verticalDragPosition || horizontalDragPosition); + if (isMaintainingPositon) { + lastContentX = contentPositionX(); + lastContentY = contentPositionY(); + } + + initialiseVerticalScroll(); + initialiseHorizontalScroll(); + resizeScrollbars(); + + if (isMaintainingPositon) { + scrollToX(maintainAtRight ? (contentWidth - paneWidth ) : lastContentX, false); + scrollToY(maintainAtBottom ? (contentHeight - paneHeight) : lastContentY, false); + } + + initFocusHandler(); + initMousewheel(); + initTouch(); + + if (settings.enableKeyboardNavigation) { + initKeyboardNav(); + } + if (settings.clickOnTrack) { + initClickOnTrack(); + } + + observeHash(); + if (settings.hijackInternalLinks) { + hijackInternalLinks(); + } + } + + if (settings.autoReinitialise && !reinitialiseInterval) { + reinitialiseInterval = setInterval( + function() + { + initialise(settings); + }, + settings.autoReinitialiseDelay + ); + } else if (!settings.autoReinitialise && reinitialiseInterval) { + clearInterval(reinitialiseInterval); + } + + originalScrollTop && elem.scrollTop(0) && scrollToY(originalScrollTop, false); + originalScrollLeft && elem.scrollLeft(0) && scrollToX(originalScrollLeft, false); + + elem.trigger('jsp-initialised', [isScrollableH || isScrollableV]); + } + + function initialiseVerticalScroll() + { + if (isScrollableV) { + + container.append( + $('
').append( + $('
'), + $('
').append( + $('
').append( + $('
'), + $('
') + ) + ), + $('
') + ) + ); + + verticalBar = container.find('>.jspVerticalBar'); + verticalTrack = verticalBar.find('>.jspTrack'); + verticalDrag = verticalTrack.find('>.jspDrag'); + + if (settings.showArrows) { + arrowUp = $('').bind( + 'mousedown.jsp', getArrowScroll(0, -1) + ).bind('click.jsp', nil); + arrowDown = $('').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', nil); + + 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(); + } + } + + 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) + try { + if (verticalBar.position().left === 0) { + pane.css('margin-left', scrollbarWidth + 'px'); + } + } catch (err) { + } + } + + function initialiseHorizontalScroll() + { + if (isScrollableH) { + + container.append( + $('
').append( + $('
'), + $('
').append( + $('
').append( + $('
'), + $('
') + ) + ), + $('
') + ) + ); + + horizontalBar = container.find('>.jspHorizontalBar'); + horizontalTrack = horizontalBar.find('>.jspTrack'); + horizontalDrag = horizontalTrack.find('>.jspDrag'); + + if (settings.showArrows) { + arrowLeft = $('').bind( + 'mousedown.jsp', getArrowScroll(-1, 0) + ).bind('click.jsp', nil); + arrowRight = $('').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', nil); + + 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(); + } + } + + 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( + $('
').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 = Math.ceil(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; + _positionDragX(horizontalDragPosition); // To update the state for the arrow buttons + } + if (isScrollableV) { + verticalDragHeight = Math.ceil(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; + _positionDragY(verticalDragPosition); // To update the state for the arrow buttons + } + } + + 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, + scrollTimeout, + isFirst = true, + doScroll = function() + { + if (dirX !== 0) { + jsp.scrollByX(dirX * settings.arrowButtonSpeed); + } + if (dirY !== 0) { + jsp.scrollByY(dirY * settings.arrowButtonSpeed); + } + scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.arrowRepeatFreq); + isFirst = false; + }; + + doScroll(); + + eve = ele ? 'mouseout.jsp' : 'mouseup.jsp'; + ele = ele || $('html'); + ele.bind( + eve, + function() + { + arrow.removeClass('jspActive'); + scrollTimeout && clearTimeout(scrollTimeout); + scrollTimeout = null; + ele.unbind(eve); + } + ); + } + + function initClickOnTrack() + { + removeClickOnTrack(); + if (isScrollableV) { + verticalTrack.bind( + 'mousedown.jsp', + function(e) + { + if (e.originalTarget === undefined || e.originalTarget == e.currentTarget) { + var clickedTrack = $(this), + offset = clickedTrack.offset(), + direction = e.pageY - offset.top - verticalDragPosition, + scrollTimeout, + isFirst = true, + doScroll = function() + { + var offset = clickedTrack.offset(), + pos = e.pageY - offset.top - verticalDragHeight / 2, + contentDragY = paneHeight * settings.scrollPagePercent, + dragY = dragMaxY * contentDragY / (contentHeight - paneHeight); + if (direction < 0) { + if (verticalDragPosition - dragY > pos) { + jsp.scrollByY(-contentDragY); + } else { + positionDragY(pos); + } + } else if (direction > 0) { + if (verticalDragPosition + dragY < pos) { + jsp.scrollByY(contentDragY); + } else { + positionDragY(pos); + } + } else { + cancelClick(); + return; + } + scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.trackClickRepeatFreq); + isFirst = false; + }, + cancelClick = function() + { + scrollTimeout && clearTimeout(scrollTimeout); + scrollTimeout = null; + $(document).unbind('mouseup.jsp', cancelClick); + }; + doScroll(); + $(document).bind('mouseup.jsp', cancelClick); + return false; + } + } + ); + } + + if (isScrollableH) { + horizontalTrack.bind( + 'mousedown.jsp', + function(e) + { + if (e.originalTarget === undefined || e.originalTarget == e.currentTarget) { + var clickedTrack = $(this), + offset = clickedTrack.offset(), + direction = e.pageX - offset.left - horizontalDragPosition, + scrollTimeout, + isFirst = true, + doScroll = function() + { + var offset = clickedTrack.offset(), + pos = e.pageX - offset.left - horizontalDragWidth / 2, + contentDragX = paneWidth * settings.scrollPagePercent, + dragX = dragMaxX * contentDragX / (contentWidth - paneWidth); + if (direction < 0) { + if (horizontalDragPosition - dragX > pos) { + jsp.scrollByX(-contentDragX); + } else { + positionDragX(pos); + } + } else if (direction > 0) { + if (horizontalDragPosition + dragX < pos) { + jsp.scrollByX(contentDragX); + } else { + positionDragX(pos); + } + } else { + cancelClick(); + return; + } + scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.trackClickRepeatFreq); + isFirst = false; + }, + cancelClick = function() + { + scrollTimeout && clearTimeout(scrollTimeout); + scrollTimeout = null; + $(document).unbind('mouseup.jsp', cancelClick); + }; + doScroll(); + $(document).bind('mouseup.jsp', cancelClick); + return false; + } + } + ); + } + } + + function removeClickOnTrack() + { + if (horizontalTrack) { + horizontalTrack.unbind('mousedown.jsp'); + } + if (verticalTrack) { + verticalTrack.unbind('mousedown.jsp'); + } + } + + function cancelDrag() + { + $('html').unbind('dragstart.jsp selectstart.jsp mousemove.jsp mouseup.jsp mouseleave.jsp'); + + if (verticalDrag) { + verticalDrag.removeClass('jspActive'); + } + if (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]).trigger('scroll'); + } + + 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 == dragMaxX, + 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]).trigger('scroll'); + } + + 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, eleWidth, eleTop = 0, eleLeft = 0, viewportTop, viewportLeft, maxVisibleEleTop, maxVisibleEleLeft, destY, destX; + + // 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(); + eleWidth= e.outerWidth(); + + container.scrollTop(0); + container.scrollLeft(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; + eleLeft += e.position().left; + 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); + } + + viewportLeft = contentPositionX(); + maxVisibleEleLeft = viewportLeft + paneWidth; + if (eleLeft < viewportLeft || stickToTop) { // element is to the left of viewport + destX = eleLeft - settings.horizontalGutter; + } else if (eleLeft + eleWidth > maxVisibleEleLeft) { // element is to the right viewport + destX = eleLeft - paneWidth + eleWidth + settings.horizontalGutter; + } + if (destX) { + scrollToX(destX, animate); + } + + } + + function contentPositionX() + { + return -pane.position().left; + } + + function contentPositionY() + { + return -pane.position().top; + } + + function isCloseToBottom() + { + var scrollableHeight = contentHeight - paneHeight; + return (scrollableHeight > 20) && (scrollableHeight - contentPositionY() < 10); + } + + function isCloseToRight() + { + var scrollableWidth = contentWidth - paneWidth; + return (scrollableWidth > 20) && (scrollableWidth - contentPositionX() < 10); + } + + function initMousewheel() + { + container.unbind(mwEvent).bind( + mwEvent, + function (event, delta, deltaX, deltaY) { + var dX = horizontalDragPosition, dY = verticalDragPosition; + jsp.scrollBy(deltaX * settings.mouseWheelSpeed, -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.find(':input,a').unbind('focus.jsp').bind( + 'focus.jsp', + function(e) + { + scrollToElement(e.target, false); + } + ); + } + + function removeFocusHandler() + { + pane.find(':input,a').unbind('focus.jsp'); + } + + function initKeyboardNav() + { + var keyDown, elementHasScrolled, validParents = []; + isScrollableH && validParents.push(horizontalBar[0]); + isScrollableV && validParents.push(verticalBar[0]); + + // IE also focuses elements that don't have tabindex set. + pane.focus( + function() + { + elem.focus(); + } + ); + + elem.attr('tabindex', 0) + .unbind('keydown.jsp keypress.jsp') + .bind( + 'keydown.jsp', + function(e) + { + if (e.target !== this && !(validParents.length && $(e.target).closest(validParents).length)){ + return; + } + var dX = horizontalDragPosition, dY = verticalDragPosition; + switch(e.keyCode) { + case 40: // down + case 38: // up + case 34: // page down + case 32: // space + case 33: // page up + case 39: // right + case 37: // left + keyDown = e.keyCode; + keyDownHandler(); + break; + case 35: // end + scrollToY(contentHeight - paneHeight); + keyDown = null; + break; + case 36: // home + scrollToY(0); + keyDown = null; + break; + } + + elementHasScrolled = e.keyCode == keyDown && dX != horizontalDragPosition || dY != verticalDragPosition; + return !elementHasScrolled; + } + ).bind( + 'keypress.jsp', // For FF/ OSX so that we can cancel the repeat key presses if the JSP scrolls... + function(e) + { + if (e.keyCode == keyDown) { + keyDownHandler(); + } + return !elementHasScrolled; + } + ); + + 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 keyDownHandler() + { + var dX = horizontalDragPosition, dY = verticalDragPosition; + switch(keyDown) { + case 40: // down + jsp.scrollByY(settings.keyboardSpeed, false); + break; + case 38: // up + jsp.scrollByY(-settings.keyboardSpeed, false); + break; + case 34: // page down + case 32: // space + jsp.scrollByY(paneHeight * settings.scrollPagePercent, false); + break; + case 33: // page up + jsp.scrollByY(-paneHeight * settings.scrollPagePercent, false); + break; + case 39: // right + jsp.scrollByX(settings.keyboardSpeed, false); + break; + case 37: // left + jsp.scrollByX(-settings.keyboardSpeed, false); + break; + } + + elementHasScrolled = dX != horizontalDragPosition || dY != verticalDragPosition; + return elementHasScrolled; + } + } + + function removeKeyboardNav() + { + elem.attr('tabindex', '-1') + .removeAttr('tabindex') + .unbind('keydown.jsp keypress.jsp'); + } + + function observeHash() + { + if (location.hash && location.hash.length > 1) { + var e, + retryInt, + hash = escape(location.hash.substr(1)) // hash must be escaped to prevent XSS + ; + try { + e = $('#' + hash + ', a[name="' + hash + '"]'); + } catch (err) { + return; + } + + if (e.length && pane.find(hash)) { + // 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(e, true); + $(document).scrollTop(container.position().top); + clearInterval(retryInt); + } + }, + 50 + ); + } else { + scrollToElement(e, true); + $(document).scrollTop(container.position().top); + } + } + } + } + + function hijackInternalLinks() + { + // only register the link handler once + if ($(document.body).data('jspHijack')) { + return; + } + + // remember that the handler was bound + $(document.body).data('jspHijack', true); + + // use live handler to also capture newly created links + $(document.body).delegate('a[href*=#]', 'click', function(event) { + // does the link point to the same page? + // this also takes care of cases with a -Tag or Links not starting with the hash # + // e.g. when the current url already is index.html + var href = this.href.substr(0, this.href.indexOf('#')), + locationHref = location.href, + hash, + element, + container, + jsp, + scrollTop, + elementTop; + if (location.href.indexOf('#') !== -1) { + locationHref = location.href.substr(0, location.href.indexOf('#')); + } + if (href !== locationHref) { + // the link points to another page + return; + } + + // check if jScrollPane should handle this click event + hash = escape(this.href.substr(this.href.indexOf('#') + 1)); + + // find the element on the page + element; + try { + element = $('#' + hash + ', a[name="' + hash + '"]'); + } catch (e) { + // hash is not a valid jQuery identifier + return; + } + + if (!element.length) { + // this link does not point to an element on this page + return; + } + + container = element.closest('.jspScrollable'); + jsp = container.data('jsp'); + + // jsp might be another jsp instance than the one, that bound this event + // remember: this event is only bound once for all instances. + jsp.scrollToElement(element, true); + + if (container[0].scrollIntoView) { + // also scroll to the top of the container (if it is not visible) + scrollTop = $(window).scrollTop(); + elementTop = element.offset().top; + if (elementTop < scrollTop || elementTop > scrollTop + $(window).height()) { + container[0].scrollIntoView(); + } + } + + // jsp handled this event, prevent the browser default (scrolling :P) + event.preventDefault(); + }); + } + + // Init touch on iPad, iPhone, iPod, Android + function initTouch() + { + var startX, + startY, + touchStartX, + touchStartY, + moved, + moving = false; + + container.unbind('touchstart.jsp touchmove.jsp touchend.jsp click.jsp-touchclick').bind( + 'touchstart.jsp', + function(e) + { + var touch = e.originalEvent.touches[0]; + startX = contentPositionX(); + startY = contentPositionY(); + touchStartX = touch.pageX; + touchStartY = touch.pageY; + moved = false; + moving = true; + } + ).bind( + 'touchmove.jsp', + function(ev) + { + if(!moving) { + return; + } + + var touchPos = ev.originalEvent.touches[0], + dX = horizontalDragPosition, dY = verticalDragPosition; + + jsp.scrollTo(startX + touchStartX - touchPos.pageX, startY + touchStartY - touchPos.pageY); + + moved = moved || Math.abs(touchStartX - touchPos.pageX) > 5 || Math.abs(touchStartY - touchPos.pageY) > 5; + + // return true if there was no movement so rest of screen can scroll + return dX == horizontalDragPosition && dY == verticalDragPosition; + } + ).bind( + 'touchend.jsp', + function(e) + { + moving = false; + /*if(moved) { + return false; + }*/ + } + ).bind( + 'click.jsp-touchclick', + function(e) + { + if(moved) { + moved = false; + return false; + } + } + ); + } + + function destroy(){ + var currentY = contentPositionY(), + currentX = contentPositionX(); + elem.removeClass('jspScrollable').unbind('.jsp'); + elem.replaceWith(originalElement.append(pane.children())); + originalElement.scrollTop(currentY); + originalElement.scrollLeft(currentX); + + // clear reinitialize timer if active + if (reinitialiseInterval) { + clearInterval(reinitialiseInterval); + } + } + + // 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({}, settings, s); + 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 to the specified percentage of its maximum horizontal scroll position. animate + // is optional and if not passed then the value of animateScroll from the settings object this + // jScrollPane was initialised with is used. + scrollToPercentX: function(destPercentX, animate) + { + scrollToX(destPercentX * (contentWidth - paneWidth), animate); + }, + // Scrolls the pane to the specified percentage of its maximum vertical scroll position. animate + // is optional and if not passed then the value of animateScroll from the settings object this + // jScrollPane was initialised with is used. + scrollToPercentY: function(destPercentY, animate) + { + scrollToY(destPercentY * (contentHeight - paneHeight), 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() + Math[deltaX<0 ? 'floor' : 'ceil'](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() + Math[deltaY<0 ? 'floor' : 'ceil'](deltaY), + percentScrolled = destY / (contentHeight - paneHeight); + positionDragY(percentScrolled * dragMaxY, animate); + }, + // Positions the horizontal drag at the specified x position (and updates the viewport to reflect + // this). animate is optional and if not passed then the value of animateScroll from the settings + // object this jScrollPane was initialised with is used. + positionDragX: function(x, animate) + { + positionDragX(x, animate); + }, + // Positions the vertical drag at the specified y position (and updates the viewport to reflect + // this). animate is optional and if not passed then the value of animateScroll from the settings + // object this jScrollPane was initialised with is used. + positionDragY: function(y, animate) + { + positionDragY(y, 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, + 'easing' : 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 the width of the content within the scroll pane. + getContentWidth: function() + { + return contentWidth; + }, + // Returns the height of the content within the scroll pane. + getContentHeight: function() + { + return contentHeight; + }, + // Returns the horizontal position of the viewport within the pane content. + getPercentScrolledX: function() + { + return contentPositionX() / (contentWidth - paneWidth); + }, + // Returns the vertical position of the viewport within the pane content. + getPercentScrolledY: function() + { + return contentPositionY() / (contentHeight - paneHeight); + }, + // 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: $.noop, + // Removes the jScrollPane and returns the page to the state it was in before jScrollPane was + // initialised. + destroy: function() + { + destroy(); + } + } + ); + + initialise(s); + } + + // Pluginifying code... + settings = $.extend({}, $.fn.jScrollPane.defaults, settings); + + // Apply default speed + $.each(['mouseWheelSpeed', 'arrowButtonSpeed', 'trackClickSpeed', 'keyboardSpeed'], function() { + settings[this] = settings[this] || settings.speed; + }); + + return 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); + } + } + ); + }; + + $.fn.jScrollPane.defaults = { + showArrows : false, + maintainPosition : true, + stickToBottom : false, + stickToRight : false, + clickOnTrack : true, + autoReinitialise : false, + autoReinitialiseDelay : 500, + verticalDragMinHeight : 0, + verticalDragMaxHeight : 99999, + horizontalDragMinWidth : 0, + horizontalDragMaxWidth : 99999, + contentWidth : undefined, + animateScroll : false, + animateDuration : 300, + animateEase : 'linear', + hijackInternalLinks : false, + verticalGutter : 4, + horizontalGutter : 4, + mouseWheelSpeed : 0, + arrowButtonSpeed : 0, + arrowRepeatFreq : 50, + arrowScrollOnHover : false, + trackClickSpeed : 0, + trackClickRepeatFreq : 70, + verticalArrowPositions : 'split', + horizontalArrowPositions : 'split', + enableKeyboardNavigation : true, + hideFocus : false, + keyboardSpeed : 0, + initialDelay : 300, // Delay before starting repeating + speed : 30, // Default speed when others falsey + scrollPagePercent : .8 // Percent of visible area scrolled when pageUp/Down or track area pressed + }; + +})(jQuery,this); + diff --git a/ajax/libs/jScrollPane/2.0.0beta11/script/jquery.jscrollpane.min.js b/ajax/libs/jScrollPane/2.0.0beta11/script/jquery.jscrollpane.min.js new file mode 100644 index 00000000000000..03ce1f0f688cc2 --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.0beta11/script/jquery.jscrollpane.min.js @@ -0,0 +1,11 @@ +/* + * jScrollPane - v2.0.0beta11 - 2012-05-14 + * http://jscrollpane.kelvinluck.com/ + * + * Copyright (c) 2010 Kelvin Luck + * Dual licensed under the MIT and GPL licenses. + */ +(function(b,a,c){b.fn.jScrollPane=function(e){function d(D,O){var ay,Q=this,Y,aj,v,al,T,Z,y,q,az,aE,au,i,I,h,j,aa,U,ap,X,t,A,aq,af,am,G,l,at,ax,x,av,aH,f,L,ai=true,P=true,aG=false,k=false,ao=D.clone(false,false).empty(),ac=b.fn.mwheelIntent?"mwheelIntent.jsp":"mousewheel.jsp";aH=D.css("paddingTop")+" "+D.css("paddingRight")+" "+D.css("paddingBottom")+" "+D.css("paddingLeft");f=(parseInt(D.css("paddingLeft"),10)||0)+(parseInt(D.css("paddingRight"),10)||0);function ar(aQ){var aL,aN,aM,aJ,aI,aP,aO=false,aK=false;ay=aQ;if(Y===c){aI=D.scrollTop();aP=D.scrollLeft();D.css({overflow:"hidden",padding:0});aj=D.innerWidth()+f;v=D.innerHeight();D.width(aj);Y=b('
').css("padding",aH).append(D.children());al=b('
').css({width:aj+"px",height:v+"px"}).append(Y).appendTo(D)}else{D.css("width","");aO=ay.stickToBottom&&K();aK=ay.stickToRight&&B();aJ=D.innerWidth()+f!=aj||D.outerHeight()!=v;if(aJ){aj=D.innerWidth()+f;v=D.innerHeight();al.css({width:aj+"px",height:v+"px"})}if(!aJ&&L==T&&Y.outerHeight()==Z){D.width(aj);return}L=T;Y.css("width","");D.width(aj);al.find(">.jspVerticalBar,>.jspHorizontalBar").remove().end()}Y.css("overflow","auto");if(aQ.contentWidth){T=aQ.contentWidth}else{T=Y[0].scrollWidth}Z=Y[0].scrollHeight;Y.css("overflow","");y=T/aj;q=Z/v;az=q>1;aE=y>1;if(!(aE||az)){D.removeClass("jspScrollable");Y.css({top:0,width:al.width()-f});n();E();R();w()}else{D.addClass("jspScrollable");aL=ay.maintainPosition&&(I||aa);if(aL){aN=aC();aM=aA()}aF();z();F();if(aL){N(aK?(T-aj):aN,false);M(aO?(Z-v):aM,false)}J();ag();an();if(ay.enableKeyboardNavigation){S()}if(ay.clickOnTrack){p()}C();if(ay.hijackInternalLinks){m()}}if(ay.autoReinitialise&&!av){av=setInterval(function(){ar(ay)},ay.autoReinitialiseDelay)}else{if(!ay.autoReinitialise&&av){clearInterval(av)}}aI&&D.scrollTop(0)&&M(aI,false);aP&&D.scrollLeft(0)&&N(aP,false);D.trigger("jsp-initialised",[aE||az])}function aF(){if(az){al.append(b('
').append(b('
'),b('
').append(b('
').append(b('
'),b('
'))),b('
')));U=al.find(">.jspVerticalBar");ap=U.find(">.jspTrack");au=ap.find(">.jspDrag");if(ay.showArrows){aq=b('').bind("mousedown.jsp",aD(0,-1)).bind("click.jsp",aB);af=b('').bind("mousedown.jsp",aD(0,1)).bind("click.jsp",aB);if(ay.arrowScrollOnHover){aq.bind("mouseover.jsp",aD(0,-1,aq));af.bind("mouseover.jsp",aD(0,1,af))}ak(ap,ay.verticalArrowPositions,aq,af)}t=v;al.find(">.jspVerticalBar>.jspCap:visible,>.jspVerticalBar>.jspArrow").each(function(){t-=b(this).outerHeight()});au.hover(function(){au.addClass("jspHover")},function(){au.removeClass("jspHover")}).bind("mousedown.jsp",function(aI){b("html").bind("dragstart.jsp selectstart.jsp",aB);au.addClass("jspActive");var s=aI.pageY-au.position().top;b("html").bind("mousemove.jsp",function(aJ){V(aJ.pageY-s,false)}).bind("mouseup.jsp mouseleave.jsp",aw);return false});o()}}function o(){ap.height(t+"px");I=0;X=ay.verticalGutter+ap.outerWidth();Y.width(aj-X-f);try{if(U.position().left===0){Y.css("margin-left",X+"px")}}catch(s){}}function z(){if(aE){al.append(b('
').append(b('
'),b('
').append(b('
').append(b('
'),b('
'))),b('
')));am=al.find(">.jspHorizontalBar");G=am.find(">.jspTrack");h=G.find(">.jspDrag");if(ay.showArrows){ax=b('').bind("mousedown.jsp",aD(-1,0)).bind("click.jsp",aB);x=b('').bind("mousedown.jsp",aD(1,0)).bind("click.jsp",aB); +if(ay.arrowScrollOnHover){ax.bind("mouseover.jsp",aD(-1,0,ax));x.bind("mouseover.jsp",aD(1,0,x))}ak(G,ay.horizontalArrowPositions,ax,x)}h.hover(function(){h.addClass("jspHover")},function(){h.removeClass("jspHover")}).bind("mousedown.jsp",function(aI){b("html").bind("dragstart.jsp selectstart.jsp",aB);h.addClass("jspActive");var s=aI.pageX-h.position().left;b("html").bind("mousemove.jsp",function(aJ){W(aJ.pageX-s,false)}).bind("mouseup.jsp mouseleave.jsp",aw);return false});l=al.innerWidth();ah()}}function ah(){al.find(">.jspHorizontalBar>.jspCap:visible,>.jspHorizontalBar>.jspArrow").each(function(){l-=b(this).outerWidth()});G.width(l+"px");aa=0}function F(){if(aE&&az){var aI=G.outerHeight(),s=ap.outerWidth();t-=aI;b(am).find(">.jspCap:visible,>.jspArrow").each(function(){l+=b(this).outerWidth()});l-=s;v-=s;aj-=aI;G.parent().append(b('
').css("width",aI+"px"));o();ah()}if(aE){Y.width((al.outerWidth()-f)+"px")}Z=Y.outerHeight();q=Z/v;if(aE){at=Math.ceil(1/y*l);if(at>ay.horizontalDragMaxWidth){at=ay.horizontalDragMaxWidth}else{if(atay.verticalDragMaxHeight){A=ay.verticalDragMaxHeight}else{if(AaS){Q.scrollByY(-aP)}else{V(aS)}}else{if(aM>0){if(I+aQaS){Q.scrollByX(-aP)}else{W(aS)}}else{if(aM>0){if(aa+aQi){s=i}}if(aI===c){aI=ay.animateScroll}if(aI){Q.animate(au,"top",s,ad)}else{au.css("top",s);ad(s)}}function ad(aI){if(aI===c){aI=au.position().top}al.scrollTop(0);I=aI;var aL=I===0,aJ=I==i,aK=aI/i,s=-aK*(Z-v);if(ai!=aL||aG!=aJ){ai=aL;aG=aJ;D.trigger("jsp-arrow-change",[ai,aG,P,k])}u(aL,aJ);Y.css("top",s);D.trigger("jsp-scroll-y",[-s,aL,aJ]).trigger("scroll")}function W(aI,s){if(!aE){return}if(aI<0){aI=0}else{if(aI>j){aI=j}}if(s===c){s=ay.animateScroll}if(s){Q.animate(h,"left",aI,ae) +}else{h.css("left",aI);ae(aI)}}function ae(aI){if(aI===c){aI=h.position().left}al.scrollTop(0);aa=aI;var aL=aa===0,aK=aa==j,aJ=aI/j,s=-aJ*(T-aj);if(P!=aL||k!=aK){P=aL;k=aK;D.trigger("jsp-arrow-change",[ai,aG,P,k])}r(aL,aK);Y.css("left",s);D.trigger("jsp-scroll-x",[-s,aL,aK]).trigger("scroll")}function u(aI,s){if(ay.showArrows){aq[aI?"addClass":"removeClass"]("jspDisabled");af[s?"addClass":"removeClass"]("jspDisabled")}}function r(aI,s){if(ay.showArrows){ax[aI?"addClass":"removeClass"]("jspDisabled");x[s?"addClass":"removeClass"]("jspDisabled")}}function M(s,aI){var aJ=s/(Z-v);V(aJ*i,aI)}function N(aI,s){var aJ=aI/(T-aj);W(aJ*j,s)}function ab(aV,aQ,aJ){var aN,aK,aL,s=0,aU=0,aI,aP,aO,aS,aR,aT;try{aN=b(aV)}catch(aM){return}aK=aN.outerHeight();aL=aN.outerWidth();al.scrollTop(0);al.scrollLeft(0);while(!aN.is(".jspPane")){s+=aN.position().top;aU+=aN.position().left;aN=aN.offsetParent();if(/^body|html$/i.test(aN[0].nodeName)){return}}aI=aA();aO=aI+v;if(saO){aR=s-v+aK+ay.verticalGutter}}if(aR){M(aR,aJ)}aP=aC();aS=aP+aj;if(aUaS){aT=aU-aj+aL+ay.horizontalGutter}}if(aT){N(aT,aJ)}}function aC(){return -Y.position().left}function aA(){return -Y.position().top}function K(){var s=Z-v;return(s>20)&&(s-aA()<10)}function B(){var s=T-aj;return(s>20)&&(s-aC()<10)}function ag(){al.unbind(ac).bind(ac,function(aL,aM,aK,aI){var aJ=aa,s=I;Q.scrollBy(aK*ay.mouseWheelSpeed,-aI*ay.mouseWheelSpeed,false);return aJ==aa&&s==I})}function n(){al.unbind(ac)}function aB(){return false}function J(){Y.find(":input,a").unbind("focus.jsp").bind("focus.jsp",function(s){ab(s.target,false)})}function E(){Y.find(":input,a").unbind("focus.jsp")}function S(){var s,aI,aK=[];aE&&aK.push(am[0]);az&&aK.push(U[0]);Y.focus(function(){D.focus()});D.attr("tabindex",0).unbind("keydown.jsp keypress.jsp").bind("keydown.jsp",function(aN){if(aN.target!==this&&!(aK.length&&b(aN.target).closest(aK).length)){return}var aM=aa,aL=I;switch(aN.keyCode){case 40:case 38:case 34:case 32:case 33:case 39:case 37:s=aN.keyCode;aJ();break;case 35:M(Z-v);s=null;break;case 36:M(0);s=null;break}aI=aN.keyCode==s&&aM!=aa||aL!=I;return !aI}).bind("keypress.jsp",function(aL){if(aL.keyCode==s){aJ()}return !aI});if(ay.hideFocus){D.css("outline","none");if("hideFocus" in al[0]){D.attr("hideFocus",true)}}else{D.css("outline","");if("hideFocus" in al[0]){D.attr("hideFocus",false)}}function aJ(){var aM=aa,aL=I;switch(s){case 40:Q.scrollByY(ay.keyboardSpeed,false);break;case 38:Q.scrollByY(-ay.keyboardSpeed,false);break;case 34:case 32:Q.scrollByY(v*ay.scrollPagePercent,false);break;case 33:Q.scrollByY(-v*ay.scrollPagePercent,false);break;case 39:Q.scrollByX(ay.keyboardSpeed,false);break;case 37:Q.scrollByX(-ay.keyboardSpeed,false);break}aI=aM!=aa||aL!=I;return aI}}function R(){D.attr("tabindex","-1").removeAttr("tabindex").unbind("keydown.jsp keypress.jsp")}function C(){if(location.hash&&location.hash.length>1){var aK,aI,aJ=escape(location.hash.substr(1));try{aK=b("#"+aJ+', a[name="'+aJ+'"]')}catch(s){return}if(aK.length&&Y.find(aJ)){if(al.scrollTop()===0){aI=setInterval(function(){if(al.scrollTop()>0){ab(aK,true);b(document).scrollTop(al.position().top);clearInterval(aI)}},50)}else{ab(aK,true);b(document).scrollTop(al.position().top)}}}}function m(){if(b(document.body).data("jspHijack")){return}b(document.body).data("jspHijack",true);b(document.body).delegate("a[href*=#]","click",function(s){var aI=this.href.substr(0,this.href.indexOf("#")),aK=location.href,aO,aP,aJ,aM,aL,aN;if(location.href.indexOf("#")!==-1){aK=location.href.substr(0,location.href.indexOf("#"))}if(aI!==aK){return}aO=escape(this.href.substr(this.href.indexOf("#")+1));aP;try{aP=b("#"+aO+', a[name="'+aO+'"]')}catch(aQ){return}if(!aP.length){return}aJ=aP.closest(".jspScrollable");aM=aJ.data("jsp");aM.scrollToElement(aP,true);if(aJ[0].scrollIntoView){aL=b(a).scrollTop();aN=aP.offset().top;if(aNaL+b(a).height()){aJ[0].scrollIntoView()}}s.preventDefault() +})}function an(){var aJ,aI,aL,aK,aM,s=false;al.unbind("touchstart.jsp touchmove.jsp touchend.jsp click.jsp-touchclick").bind("touchstart.jsp",function(aN){var aO=aN.originalEvent.touches[0];aJ=aC();aI=aA();aL=aO.pageX;aK=aO.pageY;aM=false;s=true}).bind("touchmove.jsp",function(aQ){if(!s){return}var aP=aQ.originalEvent.touches[0],aO=aa,aN=I;Q.scrollTo(aJ+aL-aP.pageX,aI+aK-aP.pageY);aM=aM||Math.abs(aL-aP.pageX)>5||Math.abs(aK-aP.pageY)>5;return aO==aa&&aN==I}).bind("touchend.jsp",function(aN){s=false}).bind("click.jsp-touchclick",function(aN){if(aM){aM=false;return false}})}function g(){var s=aA(),aI=aC();D.removeClass("jspScrollable").unbind(".jsp");D.replaceWith(ao.append(Y.children()));ao.scrollTop(s);ao.scrollLeft(aI);if(av){clearInterval(av)}}b.extend(Q,{reinitialise:function(aI){aI=b.extend({},ay,aI);ar(aI)},scrollToElement:function(aJ,aI,s){ab(aJ,aI,s)},scrollTo:function(aJ,s,aI){N(aJ,aI);M(s,aI)},scrollToX:function(aI,s){N(aI,s)},scrollToY:function(s,aI){M(s,aI)},scrollToPercentX:function(aI,s){N(aI*(T-aj),s)},scrollToPercentY:function(aI,s){M(aI*(Z-v),s)},scrollBy:function(aI,s,aJ){Q.scrollByX(aI,aJ);Q.scrollByY(s,aJ)},scrollByX:function(s,aJ){var aI=aC()+Math[s<0?"floor":"ceil"](s),aK=aI/(T-aj);W(aK*j,aJ)},scrollByY:function(s,aJ){var aI=aA()+Math[s<0?"floor":"ceil"](s),aK=aI/(Z-v);V(aK*i,aJ)},positionDragX:function(s,aI){W(s,aI)},positionDragY:function(aI,s){V(aI,s)},animate:function(aI,aL,s,aK){var aJ={};aJ[aL]=s;aI.animate(aJ,{duration:ay.animateDuration,easing:ay.animateEase,queue:false,step:aK})},getContentPositionX:function(){return aC()},getContentPositionY:function(){return aA()},getContentWidth:function(){return T},getContentHeight:function(){return Z},getPercentScrolledX:function(){return aC()/(T-aj)},getPercentScrolledY:function(){return aA()/(Z-v)},getIsScrollableH:function(){return aE},getIsScrollableV:function(){return az},getContentPane:function(){return Y},scrollToBottom:function(s){V(i,s)},hijackInternalLinks:b.noop,destroy:function(){g()}});ar(O)}e=b.extend({},b.fn.jScrollPane.defaults,e);b.each(["mouseWheelSpeed","arrowButtonSpeed","trackClickSpeed","keyboardSpeed"],function(){e[this]=e[this]||e.speed});return this.each(function(){var f=b(this),g=f.data("jsp");if(g){g.reinitialise(e)}else{g=new d(f,e);f.data("jsp",g)}})};b.fn.jScrollPane.defaults={showArrows:false,maintainPosition:true,stickToBottom:false,stickToRight:false,clickOnTrack:true,autoReinitialise:false,autoReinitialiseDelay:500,verticalDragMinHeight:0,verticalDragMaxHeight:99999,horizontalDragMinWidth:0,horizontalDragMaxWidth:99999,contentWidth:c,animateScroll:false,animateDuration:300,animateEase:"linear",hijackInternalLinks:false,verticalGutter:4,horizontalGutter:4,mouseWheelSpeed:0,arrowButtonSpeed:0,arrowRepeatFreq:50,arrowScrollOnHover:false,trackClickSpeed:0,trackClickRepeatFreq:70,verticalArrowPositions:"split",horizontalArrowPositions:"split",enableKeyboardNavigation:true,hideFocus:false,keyboardSpeed:0,initialDelay:300,speed:30,scrollPagePercent:0.8}})(jQuery,this); \ No newline at end of file diff --git a/ajax/libs/jScrollPane/2.0.0beta11/style/jquery.jscrollpane.css b/ajax/libs/jScrollPane/2.0.0beta11/style/jquery.jscrollpane.css new file mode 100644 index 00000000000000..a051caed0a41b7 --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.0beta11/style/jquery.jscrollpane.css @@ -0,0 +1,120 @@ +/* + * CSS Styles that are needed by jScrollPane for it to operate correctly. + * + * Include this stylesheet in your site or copy and paste the styles below into your stylesheet - jScrollPane + * may not operate correctly without them. + */ + +.jspContainer +{ + overflow: hidden; + position: relative; +} + +.jspPane +{ + position: absolute; +} + +.jspVerticalBar +{ + position: absolute; + top: 0; + right: 0; + width: 16px; + height: 100%; + background: red; +} + +.jspHorizontalBar +{ + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 16px; + background: red; +} + +.jspVerticalBar *, +.jspHorizontalBar * +{ + margin: 0; + padding: 0; +} + +.jspCap +{ + display: none; +} + +.jspHorizontalBar .jspCap +{ + float: left; +} + +.jspTrack +{ + background: #dde; + position: relative; +} + +.jspDrag +{ + background: #bbd; + position: relative; + top: 0; + left: 0; + cursor: pointer; +} + +.jspHorizontalBar .jspTrack, +.jspHorizontalBar .jspDrag +{ + float: left; + height: 100%; +} + +.jspArrow +{ + background: #50506d; + text-indent: -20000px; + display: block; + cursor: pointer; +} + +.jspArrow.jspDisabled +{ + cursor: default; + background: #80808d; +} + +.jspVerticalBar .jspArrow +{ + height: 16px; +} + +.jspHorizontalBar .jspArrow +{ + width: 16px; + float: left; + height: 100%; +} + +.jspVerticalBar .jspArrow:focus +{ + outline: none; +} + +.jspCorner +{ + background: #eeeef4; + float: left; + height: 100%; +} + +/* Yuk! CSS Hack for IE6 3 pixel bug :( */ +* html .jspCorner +{ + margin: 0 -3px 0 0; +} \ No newline at end of file diff --git a/ajax/libs/jScrollPane/2.0.0beta11/style/jquery.jscrollpane.min.css b/ajax/libs/jScrollPane/2.0.0beta11/style/jquery.jscrollpane.min.css new file mode 100644 index 00000000000000..41eaed48ad7829 --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.0beta11/style/jquery.jscrollpane.min.css @@ -0,0 +1 @@ +.jspContainer{overflow:hidden;position:relative}.jspPane{position:absolute}.jspVerticalBar{position:absolute;top:0;right:0;width:16px;height:100%;background:red}.jspHorizontalBar{position:absolute;bottom:0;left:0;width:100%;height:16px;background:red}.jspVerticalBar *,.jspHorizontalBar *{margin:0;padding:0}.jspCap{display:none}.jspHorizontalBar .jspCap{float:left}.jspTrack{background:#dde;position:relative}.jspDrag{background:#bbd;position:relative;top:0;left:0;cursor:pointer}.jspHorizontalBar .jspTrack,.jspHorizontalBar .jspDrag{float:left;height:100%}.jspArrow{background:#50506d;text-indent:-20000px;display:block;cursor:pointer}.jspArrow.jspDisabled{cursor:default;background:#80808d}.jspVerticalBar .jspArrow{height:16px}.jspHorizontalBar .jspArrow{width:16px;float:left;height:100%}.jspVerticalBar .jspArrow:focus{outline:0}.jspCorner{background:#eeeef4;float:left;height:100%}* html .jspCorner{margin:0 -3px 0 0} \ No newline at end of file diff --git a/ajax/libs/jScrollPane/2.0.0beta2/script/jquery.jscrollpane.js b/ajax/libs/jScrollPane/2.0.0beta2/script/jquery.jscrollpane.js new file mode 100644 index 00000000000000..721697cefd8169 --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.0beta2/script/jquery.jscrollpane.js @@ -0,0 +1,972 @@ +/*! + * jScrollPane - v2.0.0beta2 - 2010-08-21 + * 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.0beta2, Last updated: 2010-08-21* +// +// 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-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 = wasAtLeft = true, wasAtBottom = wasAtRight = false; + + 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 = $('
').wrap( + $('
') + .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 = $('
').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(); + 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) + } + + elem.trigger('jsp-initialised', [isScrollableH || isScrollableV]); + } + + function initialiseVerticalScroll() + { + if (isScrollableV) { + + container.append( + $('
').append( + $('
'), + $('
').append( + $('
').append( + $('
'), + $('
') + ) + ), + $('
') + ) + ); + + verticalBar = container.find('>.jspVerticalBar'); + verticalTrack = verticalBar.find('>.jspTrack'); + verticalDrag = verticalTrack.find('>.jspDrag'); + + if (settings.showArrows) { + arrowUp = $('Scroll up').bind( + 'mousedown.jsp', getArrowScroll(0, -1) + ).bind('click.jsp', nil); + arrowDown = $('Scroll down').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( + $('
').append( + $('
'), + $('
').append( + $('
').append( + $('
'), + $('
') + ) + ), + $('
') + ) + ); + + horizontalBar = container.find('>.jspHorizontalBar'); + horizontalTrack = horizontalBar.find('>.jspTrack'); + horizontalDrag = horizontalTrack.find('>.jspDrag'); + + if (settings.showArrows) { + arrowLeft = $('Scroll left').bind( + 'mousedown.jsp', getArrowScroll(-1, 0) + ).bind('click.jsp', nil); + arrowRight = $('Scroll right').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( + $('
').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('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); diff --git a/ajax/libs/jScrollPane/2.0.0beta2/script/jquery.jscrollpane.min.js b/ajax/libs/jScrollPane/2.0.0beta2/script/jquery.jscrollpane.min.js new file mode 100644 index 00000000000000..1fab271dbc403d --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.0beta2/script/jquery.jscrollpane.min.js @@ -0,0 +1,10 @@ +/* + * jScrollPane - v2.0.0beta2 - 2010-08-21 + * http://jscrollpane.kelvinluck.com/ + * + * Copyright (c) 2010 Kelvin Luck + * Dual licensed under the MIT and GPL licenses. + */ +(function(b,a,c){b.fn.jScrollPane=function(f){function d(aj,ag){var aq,h=this,af,S,ax,Y,ao,ae,F,q,au,m,Z,A,p,at,E,Q,ah,W,o,T,D,ac,G,I,P,n,K,y,ar,z,L,C,an,X=wasAtLeft=true,aw=wasAtRight=false;L=aj.css("paddingTop")+" "+aj.css("paddingRight")+" "+aj.css("paddingBottom")+" "+aj.css("paddingLeft");C=(parseInt(aj.css("paddingLeft"))||0)+(parseInt(aj.css("paddingRight"))||0);J(ag);function J(aA){var aE,aD,aC,az,ay,aB;aq=aA;if(af==c){aj.css({overflow:"hidden",padding:0});S=aj.innerWidth()+C;ax=aj.innerHeight();aj.width(S);af=b('
').wrap(b('
').css({width:S+"px",height:ax+"px"}));aj.wrapInner(af.parent());Y=aj.find(">.jspContainer");af=Y.find(">.jspPane");af.css("padding",L)}else{aj.css("width",null);aB=aj.outerWidth()+C!=S||aj.outerHeight()!=ax;if(aB){S=aj.innerWidth()+C;ax=aj.innerHeight();Y.css({width:S+"px",height:ax+"px"})}an=af.innerWidth();if(!aB&&af.outerWidth()==ao&&af.outerHeight()==ae){if(m||au){af.css("width",an+"px");aj.css("width",(an+C)+"px")}return}af.css("width",null);aj.css("width",(S+C)+"px");Y.find(">.jspVerticalBar,>.jspHorizontalBar").remove().end()}aE=af.clone().css("position","absolute");aD=b('
').append(aE);b("body").append(aD);ao=Math.max(af.outerWidth(),aE.outerWidth());aD.remove();ae=af.outerHeight();F=ao/S;q=ae/ax;au=q>1;m=F>1;if(!(m||au)){aj.removeClass("jspScrollable");af.css({top:0,width:Y.width()+"px"});R();r();u()}else{aj.addClass("jspScrollable");aC=aq.maintainPosition&&(p||Q);if(aC){az=j();ay=g()}x();al();k();if(aC){w(az);v(ay)}t();av();if(aq.hijackInternalLinks){i()}}if(aq.autoReinitialise&&!z){z=setInterval(function(){J(aq)},aq.autoReinitialiseDelay)}else{if(!aq.autoReinitialise&&z){clearInterval(z)}}aj.trigger("jsp-initialised",[m||au])}function x(){if(au){Y.append(b('
').append(b('
'),b('
').append(b('
').append(b('
'),b('
'))),b('
')));ah=Y.find(">.jspVerticalBar");W=ah.find(">.jspTrack");Z=W.find(">.jspDrag");if(aq.showArrows){ac=b('Scroll up').bind("mousedown.jsp",H(0,-1)).bind("click.jsp",ak);G=b('Scroll down').bind("mousedown.jsp",H(0,1)).bind("click.jsp",ak);if(aq.arrowScrollOnHover){ac.bind("mouseover.jsp",H(0,-1,ac));G.bind("mouseover.jsp",H(0,1,G))}V(W,aq.verticalArrowPositions,ac,G)}T=ax;Y.find(">.jspVerticalBar>.jspCap:visible,>.jspVerticalBar>.jspArrow").each(function(){T-=b(this).outerHeight()});Z.hover(function(){Z.addClass("jspHover")},function(){Z.removeClass("jspHover")}).bind("mousedown.jsp",function(ay){b("html").bind("dragstart.jsp selectstart.jsp",function(){return false});Z.addClass("jspActive");var s=ay.pageY-Z.position().top;b("html").bind("mousemove.jsp",function(az){M(az.pageY-s,false)}).bind("mouseup.jsp mouseleave.jsp",B);return false});O();ai();l()}else{R()}}function O(){W.height(T+"px");p=0;o=aq.verticalGutter+W.outerWidth();af.width(S-o-C);if(ah.position().left==0){af.css("margin-left",o+"px")}}function al(){if(m){Y.append(b('
').append(b('
'),b('
').append(b('
').append(b('
'),b('
'))),b('
')));I=Y.find(">.jspHorizontalBar");P=I.find(">.jspTrack");at=P.find(">.jspDrag");if(aq.showArrows){y=b('Scroll left').bind("mousedown.jsp",H(-1,0)).bind("click.jsp",ak);ar=b('Scroll right').bind("mousedown.jsp",H(1,0)).bind("click.jsp",ak);if(aq.arrowScrollOnHover){y.bind("mouseover.jsp",H(-1,0,y)); +ar.bind("mouseover.jsp",H(1,0,ar))}V(P,aq.horizontalArrowPositions,y,ar)}at.hover(function(){at.addClass("jspHover")},function(){at.removeClass("jspHover")}).bind("mousedown.jsp",function(ay){b("html").bind("dragstart.jsp selectstart.jsp",function(){return false});at.addClass("jspActive");var s=ay.pageX-at.position().left;b("html").bind("mousemove.jsp",function(az){N(az.pageX-s,false)}).bind("mouseup.jsp mouseleave.jsp",B);return false});n=Y.innerWidth();ad();ap()}else{}}function ad(){Y.find(">.jspHorizontalBar>.jspCap:visible,>.jspHorizontalBar>.jspArrow").each(function(){n-=b(this).outerWidth()});P.width(n+"px");Q=0}function k(){if(m&&au){var ay=P.outerHeight(),s=W.outerWidth();T-=ay;b(I).find(">.jspCap:visible,>.jspArrow").each(function(){n+=b(this).outerWidth()});n-=s;ax-=s;S-=ay;P.parent().append(b('
').css("width",ay+"px"));O();ad()}if(m){af.width((Y.outerWidth()-C)+"px")}ae=af.outerHeight();q=ae/ax;if(m){K=1/F*n;if(K>aq.horizontalDragMaxWidth){K=aq.horizontalDragMaxWidth}else{if(Kaq.verticalDragMaxHeight){D=aq.verticalDragMaxHeight}else{if(DA){s=A}}if(ay==c){ay=aq.animateScroll}if(ay){h.animate(Z,"top",s,aa)}else{Z.css("top",s);aa(s)}}function aa(ay){if(ay==c){ay=Z.position().top}Y.scrollTop(0);p=ay;var aB=p==0,az=p==A,aA=ay/A,s=-aA*(ae-ax);if(X!=aB||aw!=az){X=aB;aw=az;aj.trigger("jsp-arrow-change",[X,aw,wasAtLeft,wasAtRight])}ai(aB,az);af.css("top",s);aj.trigger("jsp-scroll-y",[-s,aB,az])}function N(ay,s){if(!m){return}if(ay<0){ay=0}else{if(ay>E){ay=E}}if(s==c){s=aq.animateScroll}if(s){h.animate(at,"left",ay,ab)}else{at.css("left",ay);ab(ay)}}function ab(ay){if(ay==c){ay=at.position().left}Y.scrollTop(0);Q=ay;var aB=Q==0,aA=Q==A,az=ay/E,s=-az*(ao-S);if(wasAtLeft!=aB||wasAtRight!=aA){wasAtLeft=aB;wasAtRight=aA;aj.trigger("jsp-arrow-change",[X,aw,wasAtLeft,wasAtRight])}ap(aB,aA);af.css("left",s);aj.trigger("jsp-scroll-x",[-s,aB,aA])}function ai(ay,s){if(aq.showArrows){ac[ay?"addClass":"removeClass"]("jspDisabled");G[s?"addClass":"removeClass"]("jspDisabled")}}function ap(ay,s){if(aq.showArrows){y[ay?"addClass":"removeClass"]("jspDisabled");ar[s?"addClass":"removeClass"]("jspDisabled")}}function v(s,ay){var az=s/(ae-ax);M(az*A,ay)}function w(ay,s){var az=ay/(ao-S);N(az*E,s)}function U(aG,aE,ay){var aC,aA,s=0,az,aD,aF;try{aC=b(aG)}catch(aB){return}aA=aC.outerHeight();Y.scrollTop(0);while(!aC.is(".jspPane")){s+=aC.position().top;aC=aC.offsetParent();if(/^body|html$/i.test(aC[0].nodeName)){return}}az=g();aD=az+ax;if(saD){aF=s-ax+aA+aq.verticalGutter}}if(aF){v(aF,ay)}}function j(){return -af.position().left}function g(){return -af.position().top}function l(){Y.unbind("mousewheel.jsp").bind("mousewheel.jsp",function(s,az){var ay=p;M(p-az*aq.mouseWheelSpeed,false);return ay==p})}function R(){Y.unbind("mousewheel.jsp")}function ak(){return false}function t(){af.find(":input,a").bind("focus.jsp",function(){U(this,false)})}function r(){af.find(":input,a").unbind("focus.jsp") +}function av(){if(location.hash&&location.hash.length>1){var az,ay;try{az=b(location.hash)}catch(s){return}if(az.length&&af.find(az)){if(Y.scrollTop()==0){ay=setInterval(function(){if(Y.scrollTop()>0){U(location.hash,true);b(document).scrollTop(Y.position().top);clearInterval(ay)}},50)}else{U(location.hash,true);b(document).scrollTop(Y.position().top)}}}}function u(){b("a.jspHijack").unbind("click.jsp-hijack").removeClass("jspHijack")}function i(){u();b("a[href^=#]").addClass("jspHijack").bind("click.jsp-hijack",function(){var s=this.href.split("#"),ay;if(s.length>1){ay=s[1];if(ay.length>0&&af.find("#"+ay).length>0){U("#"+ay,true);return false}}})}b.extend(h,{reinitialise:function(ay){ay=b.extend({},ay,aq);J(ay)},scrollToElement:function(az,ay,s){U(az,ay,s)},scrollTo:function(az,s,ay){w(az,ay);v(s,ay)},scrollToX:function(ay,s){w(ay,s)},scrollToY:function(s,ay){v(s,ay)},scrollBy:function(ay,s,az){h.scrollByX(ay,az);h.scrollByY(s,az)},scrollByX:function(s,az){var ay=j()+s,aA=ay/(ao-S);N(aA*E,az)},scrollByY:function(s,az){var ay=g()+s,aA=ay/(ae-ax);M(aA*A,az)},animate:function(ay,aB,s,aA){var az={};az[aB]=s;ay.animate(az,{duration:aq.animateDuration,ease:aq.animateEase,queue:false,step:aA})},getContentPositionX:function(){return j()},getContentPositionY:function(){return g()},getContentPane:function(){return af},scrollToBottom:function(s){M(A,s)},hijackInternalLinks:function(){i()}})}f=b.extend({},b.fn.jScrollPane.defaults,f);var e;this.each(function(){var g=b(this),h=g.data("jsp");if(h){h.reinitialise(f)}else{h=new d(g,f);g.data("jsp",h)}e=e?e.add(g):g});return e};b.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); \ No newline at end of file diff --git a/ajax/libs/jScrollPane/2.0.0beta2/style/jquery.jscrollpane.css b/ajax/libs/jScrollPane/2.0.0beta2/style/jquery.jscrollpane.css new file mode 100644 index 00000000000000..a051caed0a41b7 --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.0beta2/style/jquery.jscrollpane.css @@ -0,0 +1,120 @@ +/* + * CSS Styles that are needed by jScrollPane for it to operate correctly. + * + * Include this stylesheet in your site or copy and paste the styles below into your stylesheet - jScrollPane + * may not operate correctly without them. + */ + +.jspContainer +{ + overflow: hidden; + position: relative; +} + +.jspPane +{ + position: absolute; +} + +.jspVerticalBar +{ + position: absolute; + top: 0; + right: 0; + width: 16px; + height: 100%; + background: red; +} + +.jspHorizontalBar +{ + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 16px; + background: red; +} + +.jspVerticalBar *, +.jspHorizontalBar * +{ + margin: 0; + padding: 0; +} + +.jspCap +{ + display: none; +} + +.jspHorizontalBar .jspCap +{ + float: left; +} + +.jspTrack +{ + background: #dde; + position: relative; +} + +.jspDrag +{ + background: #bbd; + position: relative; + top: 0; + left: 0; + cursor: pointer; +} + +.jspHorizontalBar .jspTrack, +.jspHorizontalBar .jspDrag +{ + float: left; + height: 100%; +} + +.jspArrow +{ + background: #50506d; + text-indent: -20000px; + display: block; + cursor: pointer; +} + +.jspArrow.jspDisabled +{ + cursor: default; + background: #80808d; +} + +.jspVerticalBar .jspArrow +{ + height: 16px; +} + +.jspHorizontalBar .jspArrow +{ + width: 16px; + float: left; + height: 100%; +} + +.jspVerticalBar .jspArrow:focus +{ + outline: none; +} + +.jspCorner +{ + background: #eeeef4; + float: left; + height: 100%; +} + +/* Yuk! CSS Hack for IE6 3 pixel bug :( */ +* html .jspCorner +{ + margin: 0 -3px 0 0; +} \ No newline at end of file diff --git a/ajax/libs/jScrollPane/2.0.0beta2/style/jquery.jscrollpane.min.css b/ajax/libs/jScrollPane/2.0.0beta2/style/jquery.jscrollpane.min.css new file mode 100644 index 00000000000000..41eaed48ad7829 --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.0beta2/style/jquery.jscrollpane.min.css @@ -0,0 +1 @@ +.jspContainer{overflow:hidden;position:relative}.jspPane{position:absolute}.jspVerticalBar{position:absolute;top:0;right:0;width:16px;height:100%;background:red}.jspHorizontalBar{position:absolute;bottom:0;left:0;width:100%;height:16px;background:red}.jspVerticalBar *,.jspHorizontalBar *{margin:0;padding:0}.jspCap{display:none}.jspHorizontalBar .jspCap{float:left}.jspTrack{background:#dde;position:relative}.jspDrag{background:#bbd;position:relative;top:0;left:0;cursor:pointer}.jspHorizontalBar .jspTrack,.jspHorizontalBar .jspDrag{float:left;height:100%}.jspArrow{background:#50506d;text-indent:-20000px;display:block;cursor:pointer}.jspArrow.jspDisabled{cursor:default;background:#80808d}.jspVerticalBar .jspArrow{height:16px}.jspHorizontalBar .jspArrow{width:16px;float:left;height:100%}.jspVerticalBar .jspArrow:focus{outline:0}.jspCorner{background:#eeeef4;float:left;height:100%}* html .jspCorner{margin:0 -3px 0 0} \ No newline at end of file diff --git a/ajax/libs/jScrollPane/2.0.0beta3/script/jquery.jscrollpane.js b/ajax/libs/jScrollPane/2.0.0beta3/script/jquery.jscrollpane.js new file mode 100644 index 00000000000000..774d8f5f45a478 --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.0beta3/script/jquery.jscrollpane.js @@ -0,0 +1,1061 @@ +/*! + * 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 = $('
').wrap( + $('
') + .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 = $('
').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( + $('
').append( + $('
'), + $('
').append( + $('
').append( + $('
'), + $('
') + ) + ), + $('
') + ) + ); + + verticalBar = container.find('>.jspVerticalBar'); + verticalTrack = verticalBar.find('>.jspTrack'); + verticalDrag = verticalTrack.find('>.jspDrag'); + + if (settings.showArrows) { + arrowUp = $('').bind( + 'mousedown.jsp', getArrowScroll(0, -1) + ).bind('click.jsp', nil); + arrowDown = $('').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( + $('
').append( + $('
'), + $('
').append( + $('
').append( + $('
'), + $('
') + ) + ), + $('
') + ) + ); + + horizontalBar = container.find('>.jspHorizontalBar'); + horizontalTrack = horizontalBar.find('>.jspTrack'); + horizontalDrag = horizontalTrack.find('>.jspDrag'); + + if (settings.showArrows) { + arrowLeft = $('').bind( + 'mousedown.jsp', getArrowScroll(-1, 0) + ).bind('click.jsp', nil); + arrowRight = $('').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( + $('
').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); diff --git a/ajax/libs/jScrollPane/2.0.0beta3/script/jquery.jscrollpane.min.js b/ajax/libs/jScrollPane/2.0.0beta3/script/jquery.jscrollpane.min.js new file mode 100644 index 00000000000000..7a0e7e9ace630b --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.0beta3/script/jquery.jscrollpane.min.js @@ -0,0 +1,10 @@ +/* + * jScrollPane - v2.0.0beta3 - 2010-08-27 + * http://jscrollpane.kelvinluck.com/ + * + * Copyright (c) 2010 Kelvin Luck + * Dual licensed under the MIT and GPL licenses. + */ +(function(b,a,c){b.fn.jScrollPane=function(f){function d(A,J){var ar,L=this,T,af,u,ah,O,U,w,p,at,az,an,i,F,h,j,V,P,aj,S,r,y,ak,aa,ai,D,l,am,aq,v,ao,aC,g,ay,ae=true,K=true,aB=false,k=false,X=b.fn.mwheelIntent?"mwheelIntent.jsp":"mousewheel.jsp";aC=A.css("paddingTop")+" "+A.css("paddingRight")+" "+A.css("paddingBottom")+" "+A.css("paddingLeft");g=(parseInt(A.css("paddingLeft"))||0)+(parseInt(A.css("paddingRight"))||0);al(J);function al(aF){var aJ,aI,aH,aE,aD,aG;ar=aF;if(T==c){A.css({overflow:"hidden",padding:0});af=A.innerWidth()+g;u=A.innerHeight();A.width(af);T=b('
').wrap(b('
').css({width:af+"px",height:u+"px"}));A.wrapInner(T.parent());ah=A.find(">.jspContainer");T=ah.find(">.jspPane");T.css("padding",aC)}else{A.css("width",null);aG=A.outerWidth()+g!=af||A.outerHeight()!=u;if(aG){af=A.innerWidth()+g;u=A.innerHeight();ah.css({width:af+"px",height:u+"px"})}ay=T.innerWidth();if(!aG&&T.outerWidth()==O&&T.outerHeight()==U){if(az||at){T.css("width",ay+"px");A.css("width",(ay+g)+"px")}return}T.css("width",null);A.css("width",(af+g)+"px");ah.find(">.jspVerticalBar,>.jspHorizontalBar").remove().end()}aJ=T.clone().css("position","absolute");aI=b('
').append(aJ);b("body").append(aI);O=Math.max(T.outerWidth(),aJ.outerWidth());aI.remove();U=T.outerHeight();w=O/af;p=U/u;at=p>1;az=w>1;if(!(az||at)){A.removeClass("jspScrollable");T.css({top:0,width:ah.width()+"px"});n();B();M();ad()}else{A.addClass("jspScrollable");aH=ar.maintainPosition&&(F||V);if(aH){aE=aw();aD=au()}aA();x();C();if(aH){I(aE);H(aD)}G();ab();if(ar.enableKeyboardNavigation){N()}z();if(ar.hijackInternalLinks){m()}}if(ar.autoReinitialise&&!ao){ao=setInterval(function(){al(ar)},ar.autoReinitialiseDelay)}else{if(!ar.autoReinitialise&&ao){clearInterval(ao)}}A.trigger("jsp-initialised",[az||at])}function aA(){if(at){ah.append(b('
').append(b('
'),b('
').append(b('
').append(b('
'),b('
'))),b('
')));P=ah.find(">.jspVerticalBar");aj=P.find(">.jspTrack");an=aj.find(">.jspDrag");if(ar.showArrows){ak=b('').bind("mousedown.jsp",ax(0,-1)).bind("click.jsp",av);aa=b('').bind("mousedown.jsp",ax(0,1)).bind("click.jsp",av);if(ar.arrowScrollOnHover){ak.bind("mouseover.jsp",ax(0,-1,ak));aa.bind("mouseover.jsp",ax(0,1,aa))}ag(aj,ar.verticalArrowPositions,ak,aa)}r=u;ah.find(">.jspVerticalBar>.jspCap:visible,>.jspVerticalBar>.jspArrow").each(function(){r-=b(this).outerHeight()});an.hover(function(){an.addClass("jspHover")},function(){an.removeClass("jspHover")}).bind("mousedown.jsp",function(aD){b("html").bind("dragstart.jsp selectstart.jsp",function(){return false});an.addClass("jspActive");var s=aD.pageY-an.position().top;b("html").bind("mousemove.jsp",function(aE){Q(aE.pageY-s,false)}).bind("mouseup.jsp mouseleave.jsp",ap);return false});o();t()}}function o(){aj.height(r+"px");F=0;S=ar.verticalGutter+aj.outerWidth();T.width(af-S-g);if(P.position().left==0){T.css("margin-left",S+"px")}}function x(){if(az){ah.append(b('
').append(b('
'),b('
').append(b('
').append(b('
'),b('
'))),b('
')));ai=ah.find(">.jspHorizontalBar");D=ai.find(">.jspTrack");h=D.find(">.jspDrag");if(ar.showArrows){aq=b('').bind("mousedown.jsp",ax(-1,0)).bind("click.jsp",av);v=b('').bind("mousedown.jsp",ax(1,0)).bind("click.jsp",av);if(ar.arrowScrollOnHover){aq.bind("mouseover.jsp",ax(-1,0,aq)); +v.bind("mouseover.jsp",ax(1,0,v))}ag(D,ar.horizontalArrowPositions,aq,v)}h.hover(function(){h.addClass("jspHover")},function(){h.removeClass("jspHover")}).bind("mousedown.jsp",function(aD){b("html").bind("dragstart.jsp selectstart.jsp",function(){return false});h.addClass("jspActive");var s=aD.pageX-h.position().left;b("html").bind("mousemove.jsp",function(aE){R(aE.pageX-s,false)}).bind("mouseup.jsp mouseleave.jsp",ap);return false});l=ah.innerWidth();ac();q()}else{}}function ac(){ah.find(">.jspHorizontalBar>.jspCap:visible,>.jspHorizontalBar>.jspArrow").each(function(){l-=b(this).outerWidth()});D.width(l+"px");V=0}function C(){if(az&&at){var aD=D.outerHeight(),s=aj.outerWidth();r-=aD;b(ai).find(">.jspCap:visible,>.jspArrow").each(function(){l+=b(this).outerWidth()});l-=s;u-=s;af-=aD;D.parent().append(b('
').css("width",aD+"px"));o();ac()}if(az){T.width((ah.outerWidth()-g)+"px")}U=T.outerHeight();p=U/u;if(az){am=1/w*l;if(am>ar.horizontalDragMaxWidth){am=ar.horizontalDragMaxWidth}else{if(amar.verticalDragMaxHeight){y=ar.verticalDragMaxHeight}else{if(yi){s=i}}if(aD==c){aD=ar.animateScroll}if(aD){L.animate(an,"top",s,Y)}else{an.css("top",s);Y(s)}}function Y(aD){if(aD==c){aD=an.position().top}ah.scrollTop(0);F=aD;var aG=F==0,aE=F==i,aF=aD/i,s=-aF*(U-u);if(ae!=aG||aB!=aE){ae=aG;aB=aE;A.trigger("jsp-arrow-change",[ae,aB,K,k])}t(aG,aE);T.css("top",s);A.trigger("jsp-scroll-y",[-s,aG,aE])}function R(aD,s){if(!az){return}if(aD<0){aD=0}else{if(aD>j){aD=j}}if(s==c){s=ar.animateScroll}if(s){L.animate(h,"left",aD,Z)}else{h.css("left",aD);Z(aD)}}function Z(aD){if(aD==c){aD=h.position().left}ah.scrollTop(0);V=aD;var aG=V==0,aF=V==i,aE=aD/j,s=-aE*(O-af);if(K!=aG||k!=aF){K=aG;k=aF;A.trigger("jsp-arrow-change",[ae,aB,K,k])}q(aG,aF);T.css("left",s);A.trigger("jsp-scroll-x",[-s,aG,aF])}function t(aD,s){if(ar.showArrows){ak[aD?"addClass":"removeClass"]("jspDisabled");aa[s?"addClass":"removeClass"]("jspDisabled")}}function q(aD,s){if(ar.showArrows){aq[aD?"addClass":"removeClass"]("jspDisabled");v[s?"addClass":"removeClass"]("jspDisabled")}}function H(s,aD){var aE=s/(U-u);Q(aE*i,aD)}function I(aD,s){var aE=aD/(O-af);R(aE*j,s)}function W(aL,aJ,aD){var aH,aF,s=0,aE,aI,aK;try{aH=b(aL)}catch(aG){return}aF=aH.outerHeight();ah.scrollTop(0);while(!aH.is(".jspPane")){s+=aH.position().top;aH=aH.offsetParent();if(/^body|html$/i.test(aH[0].nodeName)){return}}aE=au();aI=aE+u;if(saI){aK=s-u+aF+ar.verticalGutter}}if(aK){H(aK,aD)}}function aw(){return -T.position().left}function au(){return -T.position().top}function ab(){ah.unbind(X).bind(X,function(aG,aH,aF,aD){var aE=V,s=F;R(V+aF*ar.mouseWheelSpeed,false);Q(F-aD*ar.mouseWheelSpeed,false);return aE==V&&s==F})}function n(){ah.unbind(X)}function av(){return false}function G(){T.unbind("focusin.jsp").bind("focusin.jsp",function(s){if(s.target===T[0]){return}W(s.target,false)})}function B(){T.unbind("focusin.jsp")}function N(){var aD,s;A.attr("tabindex",0).unbind("keydown.jsp").bind("keydown.jsp",function(aH){if(aH.target!==A[0]){return +}var aF=V,aE=F,aG=aD?2:16;switch(aH.keyCode){case 40:Q(F+aG,false);break;case 38:Q(F-aG,false);break;case 34:case 32:H(au()+Math.max(32,u)-16);break;case 33:H(au()-u+16);break;case 35:H(U-u);break;case 36:H(0);break;case 39:R(V+aG,false);break;case 37:R(V-aG,false);break}if(!(aF==V&&aE==F)){aD=true;clearTimeout(s);s=setTimeout(function(){aD=false},260);return false}});if(ar.hideFocus){A.css("outline","none");if("hideFocus" in ah[0]){A.attr("hideFocus",true)}}else{A.css("outline","");if("hideFocus" in ah[0]){A.attr("hideFocus",false)}}}function M(){A.attr("tabindex","-1").removeAttr("tabindex").unbind("keydown.jsp")}function z(){if(location.hash&&location.hash.length>1){var aE,aD;try{aE=b(location.hash)}catch(s){return}if(aE.length&&T.find(aE)){if(ah.scrollTop()==0){aD=setInterval(function(){if(ah.scrollTop()>0){W(location.hash,true);b(document).scrollTop(ah.position().top);clearInterval(aD)}},50)}else{W(location.hash,true);b(document).scrollTop(ah.position().top)}}}}function ad(){b("a.jspHijack").unbind("click.jsp-hijack").removeClass("jspHijack")}function m(){ad();b("a[href^=#]").addClass("jspHijack").bind("click.jsp-hijack",function(){var s=this.href.split("#"),aD;if(s.length>1){aD=s[1];if(aD.length>0&&T.find("#"+aD).length>0){W("#"+aD,true);return false}}})}b.extend(L,{reinitialise:function(aD){aD=b.extend({},aD,ar);al(aD)},scrollToElement:function(aE,aD,s){W(aE,aD,s)},scrollTo:function(aE,s,aD){I(aE,aD);H(s,aD)},scrollToX:function(aD,s){I(aD,s)},scrollToY:function(s,aD){H(s,aD)},scrollBy:function(aD,s,aE){L.scrollByX(aD,aE);L.scrollByY(s,aE)},scrollByX:function(s,aE){var aD=aw()+s,aF=aD/(O-af);R(aF*j,aE)},scrollByY:function(s,aE){var aD=au()+s,aF=aD/(U-u);Q(aF*i,aE)},animate:function(aD,aG,s,aF){var aE={};aE[aG]=s;aD.animate(aE,{duration:ar.animateDuration,ease:ar.animateEase,queue:false,step:aF})},getContentPositionX:function(){return aw()},getContentPositionY:function(){return au()},getIsScrollableH:function(){return az},getIsScrollableV:function(){return at},getContentPane:function(){return T},scrollToBottom:function(s){Q(i,s)},hijackInternalLinks:function(){m()}})}f=b.extend({},b.fn.jScrollPane.defaults,f);var e;this.each(function(){var g=b(this),h=g.data("jsp");if(h){h.reinitialise(f)}else{h=new d(g,f);g.data("jsp",h)}e=e?e.add(g):g});return e};b.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); \ No newline at end of file diff --git a/ajax/libs/jScrollPane/2.0.0beta3/style/jquery.jscrollpane.css b/ajax/libs/jScrollPane/2.0.0beta3/style/jquery.jscrollpane.css new file mode 100644 index 00000000000000..a051caed0a41b7 --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.0beta3/style/jquery.jscrollpane.css @@ -0,0 +1,120 @@ +/* + * CSS Styles that are needed by jScrollPane for it to operate correctly. + * + * Include this stylesheet in your site or copy and paste the styles below into your stylesheet - jScrollPane + * may not operate correctly without them. + */ + +.jspContainer +{ + overflow: hidden; + position: relative; +} + +.jspPane +{ + position: absolute; +} + +.jspVerticalBar +{ + position: absolute; + top: 0; + right: 0; + width: 16px; + height: 100%; + background: red; +} + +.jspHorizontalBar +{ + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 16px; + background: red; +} + +.jspVerticalBar *, +.jspHorizontalBar * +{ + margin: 0; + padding: 0; +} + +.jspCap +{ + display: none; +} + +.jspHorizontalBar .jspCap +{ + float: left; +} + +.jspTrack +{ + background: #dde; + position: relative; +} + +.jspDrag +{ + background: #bbd; + position: relative; + top: 0; + left: 0; + cursor: pointer; +} + +.jspHorizontalBar .jspTrack, +.jspHorizontalBar .jspDrag +{ + float: left; + height: 100%; +} + +.jspArrow +{ + background: #50506d; + text-indent: -20000px; + display: block; + cursor: pointer; +} + +.jspArrow.jspDisabled +{ + cursor: default; + background: #80808d; +} + +.jspVerticalBar .jspArrow +{ + height: 16px; +} + +.jspHorizontalBar .jspArrow +{ + width: 16px; + float: left; + height: 100%; +} + +.jspVerticalBar .jspArrow:focus +{ + outline: none; +} + +.jspCorner +{ + background: #eeeef4; + float: left; + height: 100%; +} + +/* Yuk! CSS Hack for IE6 3 pixel bug :( */ +* html .jspCorner +{ + margin: 0 -3px 0 0; +} \ No newline at end of file diff --git a/ajax/libs/jScrollPane/2.0.0beta3/style/jquery.jscrollpane.min.css b/ajax/libs/jScrollPane/2.0.0beta3/style/jquery.jscrollpane.min.css new file mode 100644 index 00000000000000..41eaed48ad7829 --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.0beta3/style/jquery.jscrollpane.min.css @@ -0,0 +1 @@ +.jspContainer{overflow:hidden;position:relative}.jspPane{position:absolute}.jspVerticalBar{position:absolute;top:0;right:0;width:16px;height:100%;background:red}.jspHorizontalBar{position:absolute;bottom:0;left:0;width:100%;height:16px;background:red}.jspVerticalBar *,.jspHorizontalBar *{margin:0;padding:0}.jspCap{display:none}.jspHorizontalBar .jspCap{float:left}.jspTrack{background:#dde;position:relative}.jspDrag{background:#bbd;position:relative;top:0;left:0;cursor:pointer}.jspHorizontalBar .jspTrack,.jspHorizontalBar .jspDrag{float:left;height:100%}.jspArrow{background:#50506d;text-indent:-20000px;display:block;cursor:pointer}.jspArrow.jspDisabled{cursor:default;background:#80808d}.jspVerticalBar .jspArrow{height:16px}.jspHorizontalBar .jspArrow{width:16px;float:left;height:100%}.jspVerticalBar .jspArrow:focus{outline:0}.jspCorner{background:#eeeef4;float:left;height:100%}* html .jspCorner{margin:0 -3px 0 0} \ No newline at end of file diff --git a/ajax/libs/jScrollPane/2.0.0beta4/script/jquery.jscrollpane.js b/ajax/libs/jScrollPane/2.0.0beta4/script/jquery.jscrollpane.js new file mode 100644 index 00000000000000..82afe2defeeebf --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.0beta4/script/jquery.jscrollpane.js @@ -0,0 +1,1146 @@ +/*! + * jScrollPane - v2.0.0beta4 - 2010-09-17 + * 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.0beta4, Last updated: 2010-09-17* +// +// 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.0beta4 - (2010-09-17) clickOnTrack support, bug fixes +// 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 = $('
').wrap( + $('
') + .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 ) + '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 = $('
').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': null + }); + removeMousewheel(); + removeFocusHandler(); + removeKeyboardNav(); + removeClickOnTrack(); + 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(); + } + if (settings.clickOnTrack) { + initClickOnTrack(); + } + + 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( + $('
').append( + $('
'), + $('
').append( + $('
').append( + $('
'), + $('
') + ) + ), + $('
') + ) + ); + + verticalBar = container.find('>.jspVerticalBar'); + verticalTrack = verticalBar.find('>.jspTrack'); + verticalDrag = verticalTrack.find('>.jspDrag'); + + if (settings.showArrows) { + arrowUp = $('').bind( + 'mousedown.jsp', getArrowScroll(0, -1) + ).bind('click.jsp', nil); + arrowDown = $('').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(); + } + } + + 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( + $('
').append( + $('
'), + $('
').append( + $('
').append( + $('
'), + $('
') + ) + ), + $('
') + ) + ); + + horizontalBar = container.find('>.jspHorizontalBar'); + horizontalTrack = horizontalBar.find('>.jspTrack'); + horizontalDrag = horizontalTrack.find('>.jspDrag'); + + if (settings.showArrows) { + arrowLeft = $('').bind( + 'mousedown.jsp', getArrowScroll(-1, 0) + ).bind('click.jsp', nil); + arrowRight = $('').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(); + } 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( + $('
').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; + _positionDragX(horizontalDragPosition); // To update the state for the arrow buttons + } + 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; + _positionDragY(verticalDragPosition); // To update the state for the arrow buttons + } + } + + 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 initClickOnTrack() + { + removeClickOnTrack(); + if (isScrollableV) { + verticalTrack.bind( + 'mousedown.jsp', + function(e) + { + if (e.originalTarget == undefined || e.originalTarget == e.currentTarget) { + var clickedTrack = $(this), + scrollInt = setInterval( + function() + { + var offset = clickedTrack.offset(), pos = e.pageY - offset.top; + if (verticalDragPosition + verticalDragHeight < pos) { + positionDragY(verticalDragPosition + settings.trackClickSpeed); + } else if (pos < verticalDragPosition) { + positionDragY(verticalDragPosition - settings.trackClickSpeed); + } else { + cancelClick(); + } + }, + settings.trackClickRepeatFreq + ), + cancelClick = function() + { + scrollInt && clearInterval(scrollInt); + scrollInt = null; + $(document).unbind('mouseup.jsp', cancelClick); + }; + $(document).bind('mouseup.jsp', cancelClick); + return false; + } + } + ); + } + if (isScrollableH) { + horizontalTrack.bind( + 'mousedown.jsp', + function(e) + { + if (e.originalTarget == undefined || e.originalTarget == e.currentTarget) { + var clickedTrack = $(this), + scrollInt = setInterval( + function() + { + var offset = clickedTrack.offset(), pos = e.pageX - offset.left; + if (horizontalDragPosition + horizontalDragWidth < pos) { + positionDragX(horizontalDragPosition + settings.trackClickSpeed); + } else if (pos < horizontalDragPosition) { + positionDragX(horizontalDragPosition - settings.trackClickSpeed); + } else { + cancelClick(); + } + }, + settings.trackClickRepeatFreq + ), + cancelClick = function() + { + scrollInt && clearInterval(scrollInt); + scrollInt = null; + $(document).unbind('mouseup.jsp', cancelClick); + }; + $(document).bind('mouseup.jsp', cancelClick); + return false; + } + } + ); + } + } + + function removeClickOnTrack() + { + horizontalTrack && horizontalTrack.unbind('mousedown.jsp'); + verticalTrack && verticalTrack.unbind('mousedown.jsp'); + } + + 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 == dragMaxX, + 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, + 'clickOnTrack' : 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, + 'trackClickSpeed' : 30, + 'trackClickRepeatFreq' : 100, + 'verticalArrowPositions' : 'split', + 'horizontalArrowPositions' : 'split', + 'enableKeyboardNavigation' : true, + 'hideFocus' : false + }; + +})(jQuery,this); diff --git a/ajax/libs/jScrollPane/2.0.0beta4/script/jquery.jscrollpane.min.js b/ajax/libs/jScrollPane/2.0.0beta4/script/jquery.jscrollpane.min.js new file mode 100644 index 00000000000000..707e804b449bc0 --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.0beta4/script/jquery.jscrollpane.min.js @@ -0,0 +1,10 @@ +/* + * jScrollPane - v2.0.0beta4 - 2010-09-17 + * http://jscrollpane.kelvinluck.com/ + * + * Copyright (c) 2010 Kelvin Luck + * Dual licensed under the MIT and GPL licenses. + */ +(function(b,a,c){b.fn.jScrollPane=function(f){function d(C,L){var au,N=this,V,ah,v,aj,Q,W,y,q,av,aB,ap,i,H,h,j,X,R,al,U,t,A,am,ac,ak,F,l,ao,at,x,aq,aE,g,aA,ag=true,M=true,aD=false,k=false,Z=b.fn.mwheelIntent?"mwheelIntent.jsp":"mousewheel.jsp";aE=C.css("paddingTop")+" "+C.css("paddingRight")+" "+C.css("paddingBottom")+" "+C.css("paddingLeft");g=(parseInt(C.css("paddingLeft"))||0)+(parseInt(C.css("paddingRight"))||0);an(L);function an(aH){var aL,aK,aJ,aG,aF,aI;au=aH;if(V==c){C.css({overflow:"hidden",padding:0});ah=C.innerWidth()+g;v=C.innerHeight();C.width(ah);V=b('
').wrap(b('
').css({width:ah+"px",height:v+"px"}));C.wrapInner(V.parent());aj=C.find(">.jspContainer");V=aj.find(">.jspPane");V.css("padding",aE)}else{C.css("width",null);aI=C.outerWidth()+g!=ah||C.outerHeight()!=v;if(aI){ah=C.innerWidth()+g;v=C.innerHeight();aj.css({width:ah+"px",height:v+"px"})}aA=V.innerWidth();if(!aI&&V.outerWidth()==Q&&V.outerHeight()==W){if(aB||av){V.css("width",aA+"px");C.css("width",(aA+g)+"px")}return}V.css("width",null);C.css("width",(ah)+"px");aj.find(">.jspVerticalBar,>.jspHorizontalBar").remove().end()}aL=V.clone().css("position","absolute");aK=b('
').append(aL);b("body").append(aK);Q=Math.max(V.outerWidth(),aL.outerWidth());aK.remove();W=V.outerHeight();y=Q/ah;q=W/v;av=q>1;aB=y>1;if(!(aB||av)){C.removeClass("jspScrollable");V.css({top:0,width:null});n();D();O();w();af()}else{C.addClass("jspScrollable");aJ=au.maintainPosition&&(H||X);if(aJ){aG=ay();aF=aw()}aC();z();E();if(aJ){K(aG);J(aF)}I();ad();if(au.enableKeyboardNavigation){P()}if(au.clickOnTrack){p()}B();if(au.hijackInternalLinks){m()}}if(au.autoReinitialise&&!aq){aq=setInterval(function(){an(au)},au.autoReinitialiseDelay)}else{if(!au.autoReinitialise&&aq){clearInterval(aq)}}C.trigger("jsp-initialised",[aB||av])}function aC(){if(av){aj.append(b('
').append(b('
'),b('
').append(b('
').append(b('
'),b('
'))),b('
')));R=aj.find(">.jspVerticalBar");al=R.find(">.jspTrack");ap=al.find(">.jspDrag");if(au.showArrows){am=b('').bind("mousedown.jsp",az(0,-1)).bind("click.jsp",ax);ac=b('').bind("mousedown.jsp",az(0,1)).bind("click.jsp",ax);if(au.arrowScrollOnHover){am.bind("mouseover.jsp",az(0,-1,am));ac.bind("mouseover.jsp",az(0,1,ac))}ai(al,au.verticalArrowPositions,am,ac)}t=v;aj.find(">.jspVerticalBar>.jspCap:visible,>.jspVerticalBar>.jspArrow").each(function(){t-=b(this).outerHeight()});ap.hover(function(){ap.addClass("jspHover")},function(){ap.removeClass("jspHover")}).bind("mousedown.jsp",function(aF){b("html").bind("dragstart.jsp selectstart.jsp",function(){return false});ap.addClass("jspActive");var s=aF.pageY-ap.position().top;b("html").bind("mousemove.jsp",function(aG){S(aG.pageY-s,false)}).bind("mouseup.jsp mouseleave.jsp",ar);return false});o()}}function o(){al.height(t+"px");H=0;U=au.verticalGutter+al.outerWidth();V.width(ah-U-g);if(R.position().left==0){V.css("margin-left",U+"px")}}function z(){if(aB){aj.append(b('
').append(b('
'),b('
').append(b('
').append(b('
'),b('
'))),b('
')));ak=aj.find(">.jspHorizontalBar");F=ak.find(">.jspTrack");h=F.find(">.jspDrag");if(au.showArrows){at=b('').bind("mousedown.jsp",az(-1,0)).bind("click.jsp",ax);x=b('').bind("mousedown.jsp",az(1,0)).bind("click.jsp",ax);if(au.arrowScrollOnHover){at.bind("mouseover.jsp",az(-1,0,at)); +x.bind("mouseover.jsp",az(1,0,x))}ai(F,au.horizontalArrowPositions,at,x)}h.hover(function(){h.addClass("jspHover")},function(){h.removeClass("jspHover")}).bind("mousedown.jsp",function(aF){b("html").bind("dragstart.jsp selectstart.jsp",function(){return false});h.addClass("jspActive");var s=aF.pageX-h.position().left;b("html").bind("mousemove.jsp",function(aG){T(aG.pageX-s,false)}).bind("mouseup.jsp mouseleave.jsp",ar);return false});l=aj.innerWidth();ae()}else{}}function ae(){aj.find(">.jspHorizontalBar>.jspCap:visible,>.jspHorizontalBar>.jspArrow").each(function(){l-=b(this).outerWidth()});F.width(l+"px");X=0}function E(){if(aB&&av){var aF=F.outerHeight(),s=al.outerWidth();t-=aF;b(ak).find(">.jspCap:visible,>.jspArrow").each(function(){l+=b(this).outerWidth()});l-=s;v-=s;ah-=aF;F.parent().append(b('
').css("width",aF+"px"));o();ae()}if(aB){V.width((aj.outerWidth()-g)+"px")}W=V.outerHeight();q=W/v;if(aB){ao=1/y*l;if(ao>au.horizontalDragMaxWidth){ao=au.horizontalDragMaxWidth}else{if(aoau.verticalDragMaxHeight){A=au.verticalDragMaxHeight}else{if(Ai){s=i}}if(aF==c){aF=au.animateScroll}if(aF){N.animate(ap,"top",s,aa)}else{ap.css("top",s);aa(s)}}function aa(aF){if(aF==c){aF=ap.position().top}aj.scrollTop(0);H=aF;var aI=H==0,aG=H==i,aH=aF/i,s=-aH*(W-v);if(ag!=aI||aD!=aG){ag=aI;aD=aG;C.trigger("jsp-arrow-change",[ag,aD,M,k])}u(aI,aG);V.css("top",s);C.trigger("jsp-scroll-y",[-s,aI,aG])}function T(aF,s){if(!aB){return}if(aF<0){aF=0}else{if(aF>j){aF=j}}if(s==c){s=au.animateScroll}if(s){N.animate(h,"left",aF,ab)}else{h.css("left",aF);ab(aF)}}function ab(aF){if(aF==c){aF=h.position().left}aj.scrollTop(0);X=aF;var aI=X==0,aH=X==j,aG=aF/j,s=-aG*(Q-ah);if(M!=aI||k!=aH){M=aI;k=aH;C.trigger("jsp-arrow-change",[ag,aD,M,k])}r(aI,aH);V.css("left",s);C.trigger("jsp-scroll-x",[-s,aI,aH])}function u(aF,s){if(au.showArrows){am[aF?"addClass":"removeClass"]("jspDisabled");ac[s?"addClass":"removeClass"]("jspDisabled")}}function r(aF,s){if(au.showArrows){at[aF?"addClass":"removeClass"]("jspDisabled"); +x[s?"addClass":"removeClass"]("jspDisabled")}}function J(s,aF){var aG=s/(W-v);S(aG*i,aF)}function K(aF,s){var aG=aF/(Q-ah);T(aG*j,s)}function Y(aN,aL,aF){var aJ,aH,s=0,aG,aK,aM;try{aJ=b(aN)}catch(aI){return}aH=aJ.outerHeight();aj.scrollTop(0);while(!aJ.is(".jspPane")){s+=aJ.position().top;aJ=aJ.offsetParent();if(/^body|html$/i.test(aJ[0].nodeName)){return}}aG=aw();aK=aG+v;if(saK){aM=s-v+aH+au.verticalGutter}}if(aM){J(aM,aF)}}function ay(){return -V.position().left}function aw(){return -V.position().top}function ad(){aj.unbind(Z).bind(Z,function(aI,aJ,aH,aF){var aG=X,s=H;T(X+aH*au.mouseWheelSpeed,false);S(H-aF*au.mouseWheelSpeed,false);return aG==X&&s==H})}function n(){aj.unbind(Z)}function ax(){return false}function I(){V.unbind("focusin.jsp").bind("focusin.jsp",function(s){if(s.target===V[0]){return}Y(s.target,false)})}function D(){V.unbind("focusin.jsp")}function P(){var aF,s;C.attr("tabindex",0).unbind("keydown.jsp").bind("keydown.jsp",function(aJ){if(aJ.target!==C[0]){return}var aH=X,aG=H,aI=aF?2:16;switch(aJ.keyCode){case 40:S(H+aI,false);break;case 38:S(H-aI,false);break;case 34:case 32:J(aw()+Math.max(32,v)-16);break;case 33:J(aw()-v+16);break;case 35:J(W-v);break;case 36:J(0);break;case 39:T(X+aI,false);break;case 37:T(X-aI,false);break}if(!(aH==X&&aG==H)){aF=true;clearTimeout(s);s=setTimeout(function(){aF=false},260);return false}});if(au.hideFocus){C.css("outline","none");if("hideFocus" in aj[0]){C.attr("hideFocus",true)}}else{C.css("outline","");if("hideFocus" in aj[0]){C.attr("hideFocus",false)}}}function O(){C.attr("tabindex","-1").removeAttr("tabindex").unbind("keydown.jsp")}function B(){if(location.hash&&location.hash.length>1){var aG,aF;try{aG=b(location.hash)}catch(s){return}if(aG.length&&V.find(aG)){if(aj.scrollTop()==0){aF=setInterval(function(){if(aj.scrollTop()>0){Y(location.hash,true);b(document).scrollTop(aj.position().top);clearInterval(aF)}},50)}else{Y(location.hash,true);b(document).scrollTop(aj.position().top)}}}}function af(){b("a.jspHijack").unbind("click.jsp-hijack").removeClass("jspHijack")}function m(){af();b("a[href^=#]").addClass("jspHijack").bind("click.jsp-hijack",function(){var s=this.href.split("#"),aF;if(s.length>1){aF=s[1];if(aF.length>0&&V.find("#"+aF).length>0){Y("#"+aF,true);return false}}})}b.extend(N,{reinitialise:function(aF){aF=b.extend({},aF,au);an(aF)},scrollToElement:function(aG,aF,s){Y(aG,aF,s)},scrollTo:function(aG,s,aF){K(aG,aF);J(s,aF)},scrollToX:function(aF,s){K(aF,s)},scrollToY:function(s,aF){J(s,aF)},scrollBy:function(aF,s,aG){N.scrollByX(aF,aG);N.scrollByY(s,aG)},scrollByX:function(s,aG){var aF=ay()+s,aH=aF/(Q-ah);T(aH*j,aG)},scrollByY:function(s,aG){var aF=aw()+s,aH=aF/(W-v);S(aH*i,aG)},animate:function(aF,aI,s,aH){var aG={};aG[aI]=s;aF.animate(aG,{duration:au.animateDuration,ease:au.animateEase,queue:false,step:aH})},getContentPositionX:function(){return ay()},getContentPositionY:function(){return aw()},getIsScrollableH:function(){return aB},getIsScrollableV:function(){return av},getContentPane:function(){return V},scrollToBottom:function(s){S(i,s)},hijackInternalLinks:function(){m()}})}f=b.extend({},b.fn.jScrollPane.defaults,f);var e;this.each(function(){var g=b(this),h=g.data("jsp");if(h){h.reinitialise(f)}else{h=new d(g,f);g.data("jsp",h)}e=e?e.add(g):g});return e};b.fn.jScrollPane.defaults={showArrows:false,maintainPosition:true,clickOnTrack: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,trackClickSpeed:30,trackClickRepeatFreq:100,verticalArrowPositions:"split",horizontalArrowPositions:"split",enableKeyboardNavigation:true,hideFocus:false}})(jQuery,this); \ No newline at end of file diff --git a/ajax/libs/jScrollPane/2.0.0beta4/style/jquery.jscrollpane.css b/ajax/libs/jScrollPane/2.0.0beta4/style/jquery.jscrollpane.css new file mode 100644 index 00000000000000..a051caed0a41b7 --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.0beta4/style/jquery.jscrollpane.css @@ -0,0 +1,120 @@ +/* + * CSS Styles that are needed by jScrollPane for it to operate correctly. + * + * Include this stylesheet in your site or copy and paste the styles below into your stylesheet - jScrollPane + * may not operate correctly without them. + */ + +.jspContainer +{ + overflow: hidden; + position: relative; +} + +.jspPane +{ + position: absolute; +} + +.jspVerticalBar +{ + position: absolute; + top: 0; + right: 0; + width: 16px; + height: 100%; + background: red; +} + +.jspHorizontalBar +{ + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 16px; + background: red; +} + +.jspVerticalBar *, +.jspHorizontalBar * +{ + margin: 0; + padding: 0; +} + +.jspCap +{ + display: none; +} + +.jspHorizontalBar .jspCap +{ + float: left; +} + +.jspTrack +{ + background: #dde; + position: relative; +} + +.jspDrag +{ + background: #bbd; + position: relative; + top: 0; + left: 0; + cursor: pointer; +} + +.jspHorizontalBar .jspTrack, +.jspHorizontalBar .jspDrag +{ + float: left; + height: 100%; +} + +.jspArrow +{ + background: #50506d; + text-indent: -20000px; + display: block; + cursor: pointer; +} + +.jspArrow.jspDisabled +{ + cursor: default; + background: #80808d; +} + +.jspVerticalBar .jspArrow +{ + height: 16px; +} + +.jspHorizontalBar .jspArrow +{ + width: 16px; + float: left; + height: 100%; +} + +.jspVerticalBar .jspArrow:focus +{ + outline: none; +} + +.jspCorner +{ + background: #eeeef4; + float: left; + height: 100%; +} + +/* Yuk! CSS Hack for IE6 3 pixel bug :( */ +* html .jspCorner +{ + margin: 0 -3px 0 0; +} \ No newline at end of file diff --git a/ajax/libs/jScrollPane/2.0.0beta4/style/jquery.jscrollpane.min.css b/ajax/libs/jScrollPane/2.0.0beta4/style/jquery.jscrollpane.min.css new file mode 100644 index 00000000000000..41eaed48ad7829 --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.0beta4/style/jquery.jscrollpane.min.css @@ -0,0 +1 @@ +.jspContainer{overflow:hidden;position:relative}.jspPane{position:absolute}.jspVerticalBar{position:absolute;top:0;right:0;width:16px;height:100%;background:red}.jspHorizontalBar{position:absolute;bottom:0;left:0;width:100%;height:16px;background:red}.jspVerticalBar *,.jspHorizontalBar *{margin:0;padding:0}.jspCap{display:none}.jspHorizontalBar .jspCap{float:left}.jspTrack{background:#dde;position:relative}.jspDrag{background:#bbd;position:relative;top:0;left:0;cursor:pointer}.jspHorizontalBar .jspTrack,.jspHorizontalBar .jspDrag{float:left;height:100%}.jspArrow{background:#50506d;text-indent:-20000px;display:block;cursor:pointer}.jspArrow.jspDisabled{cursor:default;background:#80808d}.jspVerticalBar .jspArrow{height:16px}.jspHorizontalBar .jspArrow{width:16px;float:left;height:100%}.jspVerticalBar .jspArrow:focus{outline:0}.jspCorner{background:#eeeef4;float:left;height:100%}* html .jspCorner{margin:0 -3px 0 0} \ No newline at end of file diff --git a/ajax/libs/jScrollPane/2.0.0beta5/script/jquery.jscrollpane.js b/ajax/libs/jScrollPane/2.0.0beta5/script/jquery.jscrollpane.js new file mode 100644 index 00000000000000..3c9501fcd8aeee --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.0beta5/script/jquery.jscrollpane.js @@ -0,0 +1,1146 @@ +/*! + * jScrollPane - v2.0.0beta5 - 2010-10-18 + * 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.0beta5, Last updated: 2010-10-18* +// +// 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 - tested in 1.4.2+ - reported to work in 1.3.x +// Browsers Tested - Firefox 3.6.8, Safari 5, Opera 10.6, Chrome 5.0, IE 6, 7, 8 +// +// About: Release History +// +// 2.0.0beta5 - (2010-10-18) jQuery 1.4.3 support, various bug fixes +// 2.0.0beta4 - (2010-09-17) clickOnTrack support, bug fixes +// 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 = $('
').wrap( + $('
') + .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', ''); + + 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', ''); + elem.css('width', (paneWidth ) + '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 = $('
').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() - originalPaddingTotalWidth + }); + removeMousewheel(); + removeFocusHandler(); + removeKeyboardNav(); + removeClickOnTrack(); + 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(); + } + if (settings.clickOnTrack) { + initClickOnTrack(); + } + + 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( + $('
').append( + $('
'), + $('
').append( + $('
').append( + $('
'), + $('
') + ) + ), + $('
') + ) + ); + + verticalBar = container.find('>.jspVerticalBar'); + verticalTrack = verticalBar.find('>.jspTrack'); + verticalDrag = verticalTrack.find('>.jspDrag'); + + if (settings.showArrows) { + arrowUp = $('').bind( + 'mousedown.jsp', getArrowScroll(0, -1) + ).bind('click.jsp', nil); + arrowDown = $('').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(); + } + } + + 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( + $('
').append( + $('
'), + $('
').append( + $('
').append( + $('
'), + $('
') + ) + ), + $('
') + ) + ); + + horizontalBar = container.find('>.jspHorizontalBar'); + horizontalTrack = horizontalBar.find('>.jspTrack'); + horizontalDrag = horizontalTrack.find('>.jspDrag'); + + if (settings.showArrows) { + arrowLeft = $('').bind( + 'mousedown.jsp', getArrowScroll(-1, 0) + ).bind('click.jsp', nil); + arrowRight = $('').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(); + } 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( + $('
').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; + _positionDragX(horizontalDragPosition); // To update the state for the arrow buttons + } + 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; + _positionDragY(verticalDragPosition); // To update the state for the arrow buttons + } + } + + 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 initClickOnTrack() + { + removeClickOnTrack(); + if (isScrollableV) { + verticalTrack.bind( + 'mousedown.jsp', + function(e) + { + if (e.originalTarget == undefined || e.originalTarget == e.currentTarget) { + var clickedTrack = $(this), + scrollInt = setInterval( + function() + { + var offset = clickedTrack.offset(), pos = e.pageY - offset.top; + if (verticalDragPosition + verticalDragHeight < pos) { + positionDragY(verticalDragPosition + settings.trackClickSpeed); + } else if (pos < verticalDragPosition) { + positionDragY(verticalDragPosition - settings.trackClickSpeed); + } else { + cancelClick(); + } + }, + settings.trackClickRepeatFreq + ), + cancelClick = function() + { + scrollInt && clearInterval(scrollInt); + scrollInt = null; + $(document).unbind('mouseup.jsp', cancelClick); + }; + $(document).bind('mouseup.jsp', cancelClick); + return false; + } + } + ); + } + if (isScrollableH) { + horizontalTrack.bind( + 'mousedown.jsp', + function(e) + { + if (e.originalTarget == undefined || e.originalTarget == e.currentTarget) { + var clickedTrack = $(this), + scrollInt = setInterval( + function() + { + var offset = clickedTrack.offset(), pos = e.pageX - offset.left; + if (horizontalDragPosition + horizontalDragWidth < pos) { + positionDragX(horizontalDragPosition + settings.trackClickSpeed); + } else if (pos < horizontalDragPosition) { + positionDragX(horizontalDragPosition - settings.trackClickSpeed); + } else { + cancelClick(); + } + }, + settings.trackClickRepeatFreq + ), + cancelClick = function() + { + scrollInt && clearInterval(scrollInt); + scrollInt = null; + $(document).unbind('mouseup.jsp', cancelClick); + }; + $(document).bind('mouseup.jsp', cancelClick); + return false; + } + } + ); + } + } + + function removeClickOnTrack() + { + horizontalTrack && horizontalTrack.unbind('mousedown.jsp'); + verticalTrack && verticalTrack.unbind('mousedown.jsp'); + } + + 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 == dragMaxX, + 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, + 'clickOnTrack' : 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, + 'trackClickSpeed' : 30, + 'trackClickRepeatFreq' : 100, + 'verticalArrowPositions' : 'split', + 'horizontalArrowPositions' : 'split', + 'enableKeyboardNavigation' : true, + 'hideFocus' : false + }; + +})(jQuery,this); diff --git a/ajax/libs/jScrollPane/2.0.0beta5/script/jquery.jscrollpane.min.js b/ajax/libs/jScrollPane/2.0.0beta5/script/jquery.jscrollpane.min.js new file mode 100644 index 00000000000000..073a4fcb1c0b80 --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.0beta5/script/jquery.jscrollpane.min.js @@ -0,0 +1,10 @@ +/* + * jScrollPane - v2.0.0beta5 - 2010-10-18 + * http://jscrollpane.kelvinluck.com/ + * + * Copyright (c) 2010 Kelvin Luck + * Dual licensed under the MIT and GPL licenses. + */ +(function(b,a,c){b.fn.jScrollPane=function(f){function d(C,L){var au,N=this,V,ah,v,aj,Q,W,y,q,av,aB,ap,i,H,h,j,X,R,al,U,t,A,am,ac,ak,F,l,ao,at,x,aq,aE,g,aA,ag=true,M=true,aD=false,k=false,Z=b.fn.mwheelIntent?"mwheelIntent.jsp":"mousewheel.jsp";aE=C.css("paddingTop")+" "+C.css("paddingRight")+" "+C.css("paddingBottom")+" "+C.css("paddingLeft");g=(parseInt(C.css("paddingLeft"))||0)+(parseInt(C.css("paddingRight"))||0);an(L);function an(aH){var aL,aK,aJ,aG,aF,aI;au=aH;if(V==c){C.css({overflow:"hidden",padding:0});ah=C.innerWidth()+g;v=C.innerHeight();C.width(ah);V=b('
').wrap(b('
').css({width:ah+"px",height:v+"px"}));C.wrapInner(V.parent());aj=C.find(">.jspContainer");V=aj.find(">.jspPane");V.css("padding",aE)}else{C.css("width","");aI=C.outerWidth()+g!=ah||C.outerHeight()!=v;if(aI){ah=C.innerWidth()+g;v=C.innerHeight();aj.css({width:ah+"px",height:v+"px"})}aA=V.innerWidth();if(!aI&&V.outerWidth()==Q&&V.outerHeight()==W){if(aB||av){V.css("width",aA+"px");C.css("width",(aA+g)+"px")}return}V.css("width","");C.css("width",(ah)+"px");aj.find(">.jspVerticalBar,>.jspHorizontalBar").remove().end()}aL=V.clone().css("position","absolute");aK=b('
').append(aL);b("body").append(aK);Q=Math.max(V.outerWidth(),aL.outerWidth());aK.remove();W=V.outerHeight();y=Q/ah;q=W/v;av=q>1;aB=y>1;if(!(aB||av)){C.removeClass("jspScrollable");V.css({top:0,width:aj.width()-g});n();D();O();w();af()}else{C.addClass("jspScrollable");aJ=au.maintainPosition&&(H||X);if(aJ){aG=ay();aF=aw()}aC();z();E();if(aJ){K(aG);J(aF)}I();ad();if(au.enableKeyboardNavigation){P()}if(au.clickOnTrack){p()}B();if(au.hijackInternalLinks){m()}}if(au.autoReinitialise&&!aq){aq=setInterval(function(){an(au)},au.autoReinitialiseDelay)}else{if(!au.autoReinitialise&&aq){clearInterval(aq)}}C.trigger("jsp-initialised",[aB||av])}function aC(){if(av){aj.append(b('
').append(b('
'),b('
').append(b('
').append(b('
'),b('
'))),b('
')));R=aj.find(">.jspVerticalBar");al=R.find(">.jspTrack");ap=al.find(">.jspDrag");if(au.showArrows){am=b('').bind("mousedown.jsp",az(0,-1)).bind("click.jsp",ax);ac=b('').bind("mousedown.jsp",az(0,1)).bind("click.jsp",ax);if(au.arrowScrollOnHover){am.bind("mouseover.jsp",az(0,-1,am));ac.bind("mouseover.jsp",az(0,1,ac))}ai(al,au.verticalArrowPositions,am,ac)}t=v;aj.find(">.jspVerticalBar>.jspCap:visible,>.jspVerticalBar>.jspArrow").each(function(){t-=b(this).outerHeight()});ap.hover(function(){ap.addClass("jspHover")},function(){ap.removeClass("jspHover")}).bind("mousedown.jsp",function(aF){b("html").bind("dragstart.jsp selectstart.jsp",function(){return false});ap.addClass("jspActive");var s=aF.pageY-ap.position().top;b("html").bind("mousemove.jsp",function(aG){S(aG.pageY-s,false)}).bind("mouseup.jsp mouseleave.jsp",ar);return false});o()}}function o(){al.height(t+"px");H=0;U=au.verticalGutter+al.outerWidth();V.width(ah-U-g);if(R.position().left==0){V.css("margin-left",U+"px")}}function z(){if(aB){aj.append(b('
').append(b('
'),b('
').append(b('
').append(b('
'),b('
'))),b('
')));ak=aj.find(">.jspHorizontalBar");F=ak.find(">.jspTrack");h=F.find(">.jspDrag");if(au.showArrows){at=b('').bind("mousedown.jsp",az(-1,0)).bind("click.jsp",ax);x=b('').bind("mousedown.jsp",az(1,0)).bind("click.jsp",ax);if(au.arrowScrollOnHover){at.bind("mouseover.jsp",az(-1,0,at)); +x.bind("mouseover.jsp",az(1,0,x))}ai(F,au.horizontalArrowPositions,at,x)}h.hover(function(){h.addClass("jspHover")},function(){h.removeClass("jspHover")}).bind("mousedown.jsp",function(aF){b("html").bind("dragstart.jsp selectstart.jsp",function(){return false});h.addClass("jspActive");var s=aF.pageX-h.position().left;b("html").bind("mousemove.jsp",function(aG){T(aG.pageX-s,false)}).bind("mouseup.jsp mouseleave.jsp",ar);return false});l=aj.innerWidth();ae()}else{}}function ae(){aj.find(">.jspHorizontalBar>.jspCap:visible,>.jspHorizontalBar>.jspArrow").each(function(){l-=b(this).outerWidth()});F.width(l+"px");X=0}function E(){if(aB&&av){var aF=F.outerHeight(),s=al.outerWidth();t-=aF;b(ak).find(">.jspCap:visible,>.jspArrow").each(function(){l+=b(this).outerWidth()});l-=s;v-=s;ah-=aF;F.parent().append(b('
').css("width",aF+"px"));o();ae()}if(aB){V.width((aj.outerWidth()-g)+"px")}W=V.outerHeight();q=W/v;if(aB){ao=1/y*l;if(ao>au.horizontalDragMaxWidth){ao=au.horizontalDragMaxWidth}else{if(aoau.verticalDragMaxHeight){A=au.verticalDragMaxHeight}else{if(Ai){s=i}}if(aF==c){aF=au.animateScroll}if(aF){N.animate(ap,"top",s,aa)}else{ap.css("top",s);aa(s)}}function aa(aF){if(aF==c){aF=ap.position().top}aj.scrollTop(0);H=aF;var aI=H==0,aG=H==i,aH=aF/i,s=-aH*(W-v);if(ag!=aI||aD!=aG){ag=aI;aD=aG;C.trigger("jsp-arrow-change",[ag,aD,M,k])}u(aI,aG);V.css("top",s);C.trigger("jsp-scroll-y",[-s,aI,aG])}function T(aF,s){if(!aB){return}if(aF<0){aF=0}else{if(aF>j){aF=j}}if(s==c){s=au.animateScroll}if(s){N.animate(h,"left",aF,ab)}else{h.css("left",aF);ab(aF)}}function ab(aF){if(aF==c){aF=h.position().left}aj.scrollTop(0);X=aF;var aI=X==0,aH=X==j,aG=aF/j,s=-aG*(Q-ah);if(M!=aI||k!=aH){M=aI;k=aH;C.trigger("jsp-arrow-change",[ag,aD,M,k])}r(aI,aH);V.css("left",s);C.trigger("jsp-scroll-x",[-s,aI,aH])}function u(aF,s){if(au.showArrows){am[aF?"addClass":"removeClass"]("jspDisabled");ac[s?"addClass":"removeClass"]("jspDisabled")}}function r(aF,s){if(au.showArrows){at[aF?"addClass":"removeClass"]("jspDisabled"); +x[s?"addClass":"removeClass"]("jspDisabled")}}function J(s,aF){var aG=s/(W-v);S(aG*i,aF)}function K(aF,s){var aG=aF/(Q-ah);T(aG*j,s)}function Y(aN,aL,aF){var aJ,aH,s=0,aG,aK,aM;try{aJ=b(aN)}catch(aI){return}aH=aJ.outerHeight();aj.scrollTop(0);while(!aJ.is(".jspPane")){s+=aJ.position().top;aJ=aJ.offsetParent();if(/^body|html$/i.test(aJ[0].nodeName)){return}}aG=aw();aK=aG+v;if(saK){aM=s-v+aH+au.verticalGutter}}if(aM){J(aM,aF)}}function ay(){return -V.position().left}function aw(){return -V.position().top}function ad(){aj.unbind(Z).bind(Z,function(aI,aJ,aH,aF){var aG=X,s=H;T(X+aH*au.mouseWheelSpeed,false);S(H-aF*au.mouseWheelSpeed,false);return aG==X&&s==H})}function n(){aj.unbind(Z)}function ax(){return false}function I(){V.unbind("focusin.jsp").bind("focusin.jsp",function(s){if(s.target===V[0]){return}Y(s.target,false)})}function D(){V.unbind("focusin.jsp")}function P(){var aF,s;C.attr("tabindex",0).unbind("keydown.jsp").bind("keydown.jsp",function(aJ){if(aJ.target!==C[0]){return}var aH=X,aG=H,aI=aF?2:16;switch(aJ.keyCode){case 40:S(H+aI,false);break;case 38:S(H-aI,false);break;case 34:case 32:J(aw()+Math.max(32,v)-16);break;case 33:J(aw()-v+16);break;case 35:J(W-v);break;case 36:J(0);break;case 39:T(X+aI,false);break;case 37:T(X-aI,false);break}if(!(aH==X&&aG==H)){aF=true;clearTimeout(s);s=setTimeout(function(){aF=false},260);return false}});if(au.hideFocus){C.css("outline","none");if("hideFocus" in aj[0]){C.attr("hideFocus",true)}}else{C.css("outline","");if("hideFocus" in aj[0]){C.attr("hideFocus",false)}}}function O(){C.attr("tabindex","-1").removeAttr("tabindex").unbind("keydown.jsp")}function B(){if(location.hash&&location.hash.length>1){var aG,aF;try{aG=b(location.hash)}catch(s){return}if(aG.length&&V.find(aG)){if(aj.scrollTop()==0){aF=setInterval(function(){if(aj.scrollTop()>0){Y(location.hash,true);b(document).scrollTop(aj.position().top);clearInterval(aF)}},50)}else{Y(location.hash,true);b(document).scrollTop(aj.position().top)}}}}function af(){b("a.jspHijack").unbind("click.jsp-hijack").removeClass("jspHijack")}function m(){af();b("a[href^=#]").addClass("jspHijack").bind("click.jsp-hijack",function(){var s=this.href.split("#"),aF;if(s.length>1){aF=s[1];if(aF.length>0&&V.find("#"+aF).length>0){Y("#"+aF,true);return false}}})}b.extend(N,{reinitialise:function(aF){aF=b.extend({},aF,au);an(aF)},scrollToElement:function(aG,aF,s){Y(aG,aF,s)},scrollTo:function(aG,s,aF){K(aG,aF);J(s,aF)},scrollToX:function(aF,s){K(aF,s)},scrollToY:function(s,aF){J(s,aF)},scrollBy:function(aF,s,aG){N.scrollByX(aF,aG);N.scrollByY(s,aG)},scrollByX:function(s,aG){var aF=ay()+s,aH=aF/(Q-ah);T(aH*j,aG)},scrollByY:function(s,aG){var aF=aw()+s,aH=aF/(W-v);S(aH*i,aG)},animate:function(aF,aI,s,aH){var aG={};aG[aI]=s;aF.animate(aG,{duration:au.animateDuration,ease:au.animateEase,queue:false,step:aH})},getContentPositionX:function(){return ay()},getContentPositionY:function(){return aw()},getIsScrollableH:function(){return aB},getIsScrollableV:function(){return av},getContentPane:function(){return V},scrollToBottom:function(s){S(i,s)},hijackInternalLinks:function(){m()}})}f=b.extend({},b.fn.jScrollPane.defaults,f);var e;this.each(function(){var g=b(this),h=g.data("jsp");if(h){h.reinitialise(f)}else{h=new d(g,f);g.data("jsp",h)}e=e?e.add(g):g});return e};b.fn.jScrollPane.defaults={showArrows:false,maintainPosition:true,clickOnTrack: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,trackClickSpeed:30,trackClickRepeatFreq:100,verticalArrowPositions:"split",horizontalArrowPositions:"split",enableKeyboardNavigation:true,hideFocus:false}})(jQuery,this); \ No newline at end of file diff --git a/ajax/libs/jScrollPane/2.0.0beta5/style/jquery.jscrollpane.css b/ajax/libs/jScrollPane/2.0.0beta5/style/jquery.jscrollpane.css new file mode 100644 index 00000000000000..a051caed0a41b7 --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.0beta5/style/jquery.jscrollpane.css @@ -0,0 +1,120 @@ +/* + * CSS Styles that are needed by jScrollPane for it to operate correctly. + * + * Include this stylesheet in your site or copy and paste the styles below into your stylesheet - jScrollPane + * may not operate correctly without them. + */ + +.jspContainer +{ + overflow: hidden; + position: relative; +} + +.jspPane +{ + position: absolute; +} + +.jspVerticalBar +{ + position: absolute; + top: 0; + right: 0; + width: 16px; + height: 100%; + background: red; +} + +.jspHorizontalBar +{ + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 16px; + background: red; +} + +.jspVerticalBar *, +.jspHorizontalBar * +{ + margin: 0; + padding: 0; +} + +.jspCap +{ + display: none; +} + +.jspHorizontalBar .jspCap +{ + float: left; +} + +.jspTrack +{ + background: #dde; + position: relative; +} + +.jspDrag +{ + background: #bbd; + position: relative; + top: 0; + left: 0; + cursor: pointer; +} + +.jspHorizontalBar .jspTrack, +.jspHorizontalBar .jspDrag +{ + float: left; + height: 100%; +} + +.jspArrow +{ + background: #50506d; + text-indent: -20000px; + display: block; + cursor: pointer; +} + +.jspArrow.jspDisabled +{ + cursor: default; + background: #80808d; +} + +.jspVerticalBar .jspArrow +{ + height: 16px; +} + +.jspHorizontalBar .jspArrow +{ + width: 16px; + float: left; + height: 100%; +} + +.jspVerticalBar .jspArrow:focus +{ + outline: none; +} + +.jspCorner +{ + background: #eeeef4; + float: left; + height: 100%; +} + +/* Yuk! CSS Hack for IE6 3 pixel bug :( */ +* html .jspCorner +{ + margin: 0 -3px 0 0; +} \ No newline at end of file diff --git a/ajax/libs/jScrollPane/2.0.0beta5/style/jquery.jscrollpane.min.css b/ajax/libs/jScrollPane/2.0.0beta5/style/jquery.jscrollpane.min.css new file mode 100644 index 00000000000000..41eaed48ad7829 --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.0beta5/style/jquery.jscrollpane.min.css @@ -0,0 +1 @@ +.jspContainer{overflow:hidden;position:relative}.jspPane{position:absolute}.jspVerticalBar{position:absolute;top:0;right:0;width:16px;height:100%;background:red}.jspHorizontalBar{position:absolute;bottom:0;left:0;width:100%;height:16px;background:red}.jspVerticalBar *,.jspHorizontalBar *{margin:0;padding:0}.jspCap{display:none}.jspHorizontalBar .jspCap{float:left}.jspTrack{background:#dde;position:relative}.jspDrag{background:#bbd;position:relative;top:0;left:0;cursor:pointer}.jspHorizontalBar .jspTrack,.jspHorizontalBar .jspDrag{float:left;height:100%}.jspArrow{background:#50506d;text-indent:-20000px;display:block;cursor:pointer}.jspArrow.jspDisabled{cursor:default;background:#80808d}.jspVerticalBar .jspArrow{height:16px}.jspHorizontalBar .jspArrow{width:16px;float:left;height:100%}.jspVerticalBar .jspArrow:focus{outline:0}.jspCorner{background:#eeeef4;float:left;height:100%}* html .jspCorner{margin:0 -3px 0 0} \ No newline at end of file diff --git a/ajax/libs/jScrollPane/2.0.0beta8/script/jquery.jscrollpane.js b/ajax/libs/jScrollPane/2.0.0beta8/script/jquery.jscrollpane.js new file mode 100644 index 00000000000000..178389c9a3a978 --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.0beta8/script/jquery.jscrollpane.js @@ -0,0 +1,1328 @@ +/*! + * jScrollPane - v2.0.0beta8 - 2011-01-29 + * 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.0beta8, Last updated: 2011-01-29* +// +// 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 - tested in 1.4.2+ - reported to work in 1.3.x +// Browsers Tested - Firefox 3.6.8, Safari 5, Opera 10.6, Chrome 5.0, IE 6, 7, 8 +// +// About: Release History +// +// 2.0.0beta8 - (2011-01-29) touchscreen support, improved keyboard support +// 2.0.0beta7 - (2011-01-23) scroll speed consistent (thanks Aivo Paas) +// 2.0.0beta6 - (2010-12-07) scrollToElement horizontal support +// 2.0.0beta5 - (2010-10-18) jQuery 1.4.3 support, various bug fixes +// 2.0.0beta4 - (2010-09-17) clickOnTrack support, bug fixes +// 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, previousContentWidth, + wasAtTop = true, wasAtLeft = true, wasAtBottom = false, wasAtRight = false, + keyDown, keyDownTimeout, + 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'), 10) || 0) + + (parseInt(elem.css('paddingRight'), 10) || 0); + + 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 = $('
').css('padding', originalPadding).append(elem.children()); + container = $('
') + .css({ + 'width': paneWidth + 'px', + 'height': paneHeight + 'px' + } + ).append(pane).appendTo(elem); + + /* + // 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', ''); + + hasContainingSpaceChanged = elem.innerWidth() + originalPaddingTotalWidth != paneWidth || elem.outerHeight() != paneHeight; + + if (hasContainingSpaceChanged) { + paneWidth = elem.innerWidth() + originalPaddingTotalWidth; + paneHeight = elem.innerHeight(); + container.css({ + width: paneWidth + 'px', + height: paneHeight + 'px' + }); + } + + // If nothing changed since last check... + if (!hasContainingSpaceChanged && previousContentWidth == contentWidth && pane.outerHeight() == contentHeight) { + elem.width(paneWidth); + return; + } + previousContentWidth = contentWidth; + + pane.css('width', ''); + elem.width(paneWidth); + + 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 = $('
').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() - originalPaddingTotalWidth + }); + removeMousewheel(); + removeFocusHandler(); + removeKeyboardNav(); + removeClickOnTrack(); + 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(); + initTouch(); + + if (settings.enableKeyboardNavigation) { + initKeyboardNav(); + } + if (settings.clickOnTrack) { + initClickOnTrack(); + } + + 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( + $('
').append( + $('
'), + $('
').append( + $('
').append( + $('
'), + $('
') + ) + ), + $('
') + ) + ); + + verticalBar = container.find('>.jspVerticalBar'); + verticalTrack = verticalBar.find('>.jspTrack'); + verticalDrag = verticalTrack.find('>.jspDrag'); + + if (settings.showArrows) { + arrowUp = $('').bind( + 'mousedown.jsp', getArrowScroll(0, -1) + ).bind('click.jsp', nil); + arrowDown = $('').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', nil); + + 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(); + } + } + + 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( + $('
').append( + $('
'), + $('
').append( + $('
').append( + $('
'), + $('
') + ) + ), + $('
') + ) + ); + + horizontalBar = container.find('>.jspHorizontalBar'); + horizontalTrack = horizontalBar.find('>.jspTrack'); + horizontalDrag = horizontalTrack.find('>.jspDrag'); + + if (settings.showArrows) { + arrowLeft = $('').bind( + 'mousedown.jsp', getArrowScroll(-1, 0) + ).bind('click.jsp', nil); + arrowRight = $('').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', nil); + + 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(); + } + } + + 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( + $('
').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; + _positionDragX(horizontalDragPosition); // To update the state for the arrow buttons + } + 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; + _positionDragY(verticalDragPosition); // To update the state for the arrow buttons + } + } + + 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, + scrollTimeout, + isFirst = true, + doScroll = function() + { + if (dirX !== 0) { + jsp.scrollByX(dirX * settings.arrowButtonSpeed); + } + if (dirY !== 0) { + jsp.scrollByY(dirY * settings.arrowButtonSpeed); + } + scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.arrowRepeatFreq); + isFirst = false; + }; + + doScroll(); + + eve = ele ? 'mouseout.jsp' : 'mouseup.jsp'; + ele = ele || $('html'); + ele.bind( + eve, + function() + { + arrow.removeClass('jspActive'); + scrollTimeout && clearTimeout(scrollTimeout); + scrollTimeout = null; + ele.unbind(eve); + focusElem(); + } + ); + } + + function initClickOnTrack() + { + removeClickOnTrack(); + if (isScrollableV) { + verticalTrack.bind( + 'mousedown.jsp', + function(e) + { + if (e.originalTarget === undefined || e.originalTarget == e.currentTarget) { + var clickedTrack = $(this), + offset = clickedTrack.offset(), + direction = e.pageY - offset.top - verticalDragPosition, + scrollTimeout, + isFirst = true, + doScroll = function() + { + var offset = clickedTrack.offset(), + pos = e.pageY - offset.top - verticalDragHeight / 2, + contentDragY = paneHeight * settings.scrollPagePercent, + dragY = dragMaxY * contentDragY / (contentHeight - paneHeight); + if (direction < 0) { + if (verticalDragPosition - dragY > pos) { + jsp.scrollByY(-contentDragY); + } else { + positionDragY(pos); + } + } else if (direction > 0) { + if (verticalDragPosition + dragY < pos) { + jsp.scrollByY(contentDragY); + } else { + positionDragY(pos); + } + } else { + cancelClick(); + return; + } + scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.trackClickRepeatFreq); + isFirst = false; + }, + cancelClick = function() + { + scrollTimeout && clearTimeout(scrollTimeout); + scrollTimeout = null; + $(document).unbind('mouseup.jsp', cancelClick); + focusElem(); + }; + doScroll(); + $(document).bind('mouseup.jsp', cancelClick); + return false; + } + } + ); + } + + if (isScrollableH) { + horizontalTrack.bind( + 'mousedown.jsp', + function(e) + { + if (e.originalTarget === undefined || e.originalTarget == e.currentTarget) { + var clickedTrack = $(this), + offset = clickedTrack.offset(), + direction = e.pageX - offset.left - horizontalDragPosition, + scrollTimeout, + isFirst = true, + doScroll = function() + { + var offset = clickedTrack.offset(), + pos = e.pageX - offset.left - horizontalDragWidth / 2, + contentDragX = paneWidth * settings.scrollPagePercent, + dragX = dragMaxX * contentDragX / (contentWidth - paneWidth); + if (direction < 0) { + if (horizontalDragPosition - dragX > pos) { + jsp.scrollByX(-contentDragX); + } else { + positionDragX(pos); + } + } else if (direction > 0) { + if (horizontalDragPosition + dragX < pos) { + jsp.scrollByX(contentDragX); + } else { + positionDragX(pos); + } + } else { + cancelClick(); + return; + } + scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.trackClickRepeatFreq); + isFirst = false; + }, + cancelClick = function() + { + scrollTimeout && clearTimeout(scrollTimeout); + scrollTimeout = null; + $(document).unbind('mouseup.jsp', cancelClick); + focusElem(); + }; + doScroll(); + $(document).bind('mouseup.jsp', cancelClick); + return false; + } + } + ); + } + } + + function removeClickOnTrack() + { + if (horizontalTrack) { + horizontalTrack.unbind('mousedown.jsp'); + } + if (verticalTrack) { + verticalTrack.unbind('mousedown.jsp'); + } + } + + function cancelDrag() + { + $('html').unbind('dragstart.jsp selectstart.jsp mousemove.jsp mouseup.jsp mouseleave.jsp'); + + if (verticalDrag) { + verticalDrag.removeClass('jspActive'); + } + if (horizontalDrag) { + horizontalDrag.removeClass('jspActive'); + } + focusElem(); + } + + 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 == dragMaxX, + 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, eleWidth, eleTop = 0, eleLeft = 0, viewportTop, maxVisibleEleTop, maxVisibleEleLeft, destY, destX; + + // 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(); + eleWidth= e.outerWidth(); + + container.scrollTop(0); + container.scrollLeft(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; + eleLeft += e.position().left; + 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); + } + + viewportLeft = contentPositionX(); + maxVisibleEleLeft = viewportLeft + paneWidth; + if (eleLeft < viewportLeft || stickToTop) { // element is to the left of viewport + destX = eleLeft - settings.horizontalGutter; + } else if (eleLeft + eleWidth > maxVisibleEleLeft) { // element is to the right viewport + destX = eleLeft - paneWidth + eleWidth + settings.horizontalGutter; + } + if (destX) { + scrollToX(destX, animate); + } + + } + + 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; + jsp.scrollBy(deltaX * settings.mouseWheelSpeed, -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.find(':input,a').unbind('focus.jsp').bind( + 'focus.jsp', + function(e) + { + scrollToElement(e.target, false); + } + ); + } + + function removeFocusHandler() + { + pane.find(':input,a').unbind('focus.jsp'); + } + + function keyDownHandler() + { + var dX = horizontalDragPosition, dY = verticalDragPosition; + switch(keyDown) { + case 40: // down + jsp.scrollByY(settings.keyboardSpeed, false); + break; + case 38: // up + jsp.scrollByY(-settings.keyboardSpeed, false); + break; + case 34: // page down + case 32: // space + jsp.scrollByY(paneHeight * settings.scrollPagePercent, false); + break; + case 33: // page up + jsp.scrollByY(-paneHeight * settings.scrollPagePercent, false); + break; + case 39: // right + jsp.scrollByX(settings.keyboardSpeed, false); + break; + case 37: // left + jsp.scrollByX(-settings.keyboardSpeed, false); + break; + } + + return dX != horizontalDragPosition || dY != verticalDragPosition; + } + + function holdKeyDown(initial) + { + keyDownTimeout = setTimeout( + function() + { + holdKeyDown(); + }, + initial ? settings.initialDelay : settings.keyboardRepeatFreq + ); + if (!keyDownHandler()) { + stopKeyDown(); + } + } + + function stopKeyDown() + { + keyDown = null; + keyDownTimeout && clearTimeout(keyDownTimeout); + keyDownTimeout = null; + } + + function initKeyboardNav() + { + // IE also focuses elements that don't have tabindex set. + pane.focus( + function() + { + elem.focus(); + } + ); + + elem.attr('tabindex', 0) + .unbind('keydown.jsp keyup.jsp') + .bind( + 'keydown.jsp', + function(e) + { + if (e.target !== this){ + return; + } + var dX = horizontalDragPosition, dY = verticalDragPosition; + switch(e.keyCode) { + case 40: // down + case 38: // up + case 34: // page down + case 32: // space + case 33: // page up + case 39: // right + case 37: // left + if (keyDown != e.keyCode) { + stopKeyDown(); + keyDown = e.keyCode; + holdKeyDown(true); + } + break; + case 35: // end + scrollToY(contentHeight - paneHeight); + keyDown = null; + break; + case 36: // home + scrollToY(0); + keyDown = null; + break; + } + + if (keyDown == e.keyCode || dX != horizontalDragPosition || dY != verticalDragPosition) { + return false; + } + } + ).bind( + 'keyup.jsp', + function(e) + { + stopKeyDown(); + } + ); + 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 keyup.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(location.hash)) { + // 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; + } + } + } + ); + } + + // If no element has focus, focus elem to support keyboard navigation + function focusElem() + { + if (!$(':focus').length) { + elem.focus(); + } + } + + // Init touch on iPad, iPhone, iPod, Android + function initTouch() + { + var startX, + startY, + touchStartX, + touchStartY, + moved, + moving = false; + + container.unbind('touchstart.jsp touchmove.jsp touchend.jsp click.jsp-touchclick').bind( + 'touchstart.jsp', + function(e) + { + var touch = e.originalEvent.touches[0]; + startX = contentPositionX(); + startY = contentPositionY(); + touchStartX = touch.pageX; + touchStartY = touch.pageY; + moved = false; + moving = true; + } + ).bind( + 'touchmove.jsp', + function(ev) + { + if(!moving) { + return; + } + + var touchPos = ev.originalEvent.touches[0], + dX = horizontalDragPosition, dY = verticalDragPosition; + + jsp.scrollTo(startX + touchStartX - touchPos.pageX, startY + touchStartY - touchPos.pageY); + + moved = moved || Math.abs(touchStartX - touchPos.pageX) > 5 || Math.abs(touchStartY - touchPos.pageY) > 5; + + // return true if there was no movement so rest of screen can scroll + return dX == horizontalDragPosition && dY == verticalDragPosition; + } + ).bind( + 'touchend.jsp', + function(e) + { + moving = false; + /*if(moved) { + return false; + }*/ + } + ).bind( + 'click.jsp-touchclick', + function(e) + { + if(moved) { + moved = false; + 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({}, settings, s); + 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(); + } + } + ); + + initialise(s); + } + + // Pluginifying code... + settings = $.extend({}, $.fn.jScrollPane.defaults, settings); + + // Apply default speed + $.each(['mouseWheelSpeed', 'arrowButtonSpeed', 'trackClickSpeed', 'keyboardSpeed'], function() { + settings[this] = settings[this] || settings.speed; + }); + + 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, + clickOnTrack : 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 : 0, + arrowButtonSpeed : 0, + arrowRepeatFreq : 50, + arrowScrollOnHover : false, + trackClickSpeed : 0, + trackClickRepeatFreq : 70, + verticalArrowPositions : 'split', + horizontalArrowPositions : 'split', + enableKeyboardNavigation : true, + hideFocus : false, + keyboardSpeed : 0, + keyboardRepeatFreq : 50, + initialDelay : 300, // Delay before starting repeating + speed : 30, // Default speed when others falsey + scrollPagePercent : .8 // Percent of visible area scrolled when pageUp/Down or track area pressed + }; + +})(jQuery,this); + diff --git a/ajax/libs/jScrollPane/2.0.0beta8/script/jquery.jscrollpane.min.js b/ajax/libs/jScrollPane/2.0.0beta8/script/jquery.jscrollpane.min.js new file mode 100644 index 00000000000000..7cb07fdf90b1c3 --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.0beta8/script/jquery.jscrollpane.min.js @@ -0,0 +1,11 @@ +/* + * jScrollPane - v2.0.0beta8 - 2011-01-29 + * http://jscrollpane.kelvinluck.com/ + * + * Copyright (c) 2010 Kelvin Luck + * Dual licensed under the MIT and GPL licenses. + */ +(function(b,a,c){b.fn.jScrollPane=function(f){function d(F,P){var aA,R=this,Z,al,w,an,U,aa,A,r,aB,aH,aw,j,K,i,k,ab,V,aq,Y,u,C,ar,ag,ao,I,m,au,az,z,ax,aL,h,M,ak=true,Q=true,aK=false,l=false,D,av,ad=b.fn.mwheelIntent?"mwheelIntent.jsp":"mousewheel.jsp";aL=F.css("paddingTop")+" "+F.css("paddingRight")+" "+F.css("paddingBottom")+" "+F.css("paddingLeft");h=(parseInt(F.css("paddingLeft"),10)||0)+(parseInt(F.css("paddingRight"),10)||0);function at(aO){var aS,aR,aQ,aN,aM,aP;aA=aO;if(Z===c){F.css({overflow:"hidden",padding:0});al=F.innerWidth()+h;w=F.innerHeight();F.width(al);Z=b('
').css("padding",aL).append(F.children());an=b('
').css({width:al+"px",height:w+"px"}).append(Z).appendTo(F)}else{F.css("width","");aP=F.innerWidth()+h!=al||F.outerHeight()!=w;if(aP){al=F.innerWidth()+h;w=F.innerHeight();an.css({width:al+"px",height:w+"px"})}if(!aP&&M==U&&Z.outerHeight()==aa){F.width(al);return}M=U;Z.css("width","");F.width(al);an.find(">.jspVerticalBar,>.jspHorizontalBar").remove().end()}aS=Z.clone().css("position","absolute");aR=b('
').append(aS);b("body").append(aR);U=Math.max(Z.outerWidth(),aS.outerWidth());aR.remove();aa=Z.outerHeight();A=U/al;r=aa/w;aB=r>1;aH=A>1;if(!(aH||aB)){F.removeClass("jspScrollable");Z.css({top:0,width:an.width()-h});o();G();S();x();aj()}else{F.addClass("jspScrollable");aQ=aA.maintainPosition&&(K||ab);if(aQ){aN=aE();aM=aC()}aI();B();H();if(aQ){O(aN);N(aM)}L();ah();ap();if(aA.enableKeyboardNavigation){T()}if(aA.clickOnTrack){q()}E();if(aA.hijackInternalLinks){n()}}if(aA.autoReinitialise&&!ax){ax=setInterval(function(){at(aA)},aA.autoReinitialiseDelay)}else{if(!aA.autoReinitialise&&ax){clearInterval(ax)}}F.trigger("jsp-initialised",[aH||aB])}function aI(){if(aB){an.append(b('
').append(b('
'),b('
').append(b('
').append(b('
'),b('
'))),b('
')));V=an.find(">.jspVerticalBar");aq=V.find(">.jspTrack");aw=aq.find(">.jspDrag");if(aA.showArrows){ar=b('').bind("mousedown.jsp",aF(0,-1)).bind("click.jsp",aD);ag=b('').bind("mousedown.jsp",aF(0,1)).bind("click.jsp",aD);if(aA.arrowScrollOnHover){ar.bind("mouseover.jsp",aF(0,-1,ar));ag.bind("mouseover.jsp",aF(0,1,ag))}am(aq,aA.verticalArrowPositions,ar,ag)}u=w;an.find(">.jspVerticalBar>.jspCap:visible,>.jspVerticalBar>.jspArrow").each(function(){u-=b(this).outerHeight()});aw.hover(function(){aw.addClass("jspHover")},function(){aw.removeClass("jspHover")}).bind("mousedown.jsp",function(aM){b("html").bind("dragstart.jsp selectstart.jsp",aD);aw.addClass("jspActive");var s=aM.pageY-aw.position().top;b("html").bind("mousemove.jsp",function(aN){W(aN.pageY-s,false)}).bind("mouseup.jsp mouseleave.jsp",ay);return false});p()}}function p(){aq.height(u+"px");K=0;Y=aA.verticalGutter+aq.outerWidth();Z.width(al-Y-h);if(V.position().left===0){Z.css("margin-left",Y+"px")}}function B(){if(aH){an.append(b('
').append(b('
'),b('
').append(b('
').append(b('
'),b('
'))),b('
')));ao=an.find(">.jspHorizontalBar");I=ao.find(">.jspTrack");i=I.find(">.jspDrag");if(aA.showArrows){az=b('').bind("mousedown.jsp",aF(-1,0)).bind("click.jsp",aD);z=b('').bind("mousedown.jsp",aF(1,0)).bind("click.jsp",aD);if(aA.arrowScrollOnHover){az.bind("mouseover.jsp",aF(-1,0,az));z.bind("mouseover.jsp",aF(1,0,z))}am(I,aA.horizontalArrowPositions,az,z) +}i.hover(function(){i.addClass("jspHover")},function(){i.removeClass("jspHover")}).bind("mousedown.jsp",function(aM){b("html").bind("dragstart.jsp selectstart.jsp",aD);i.addClass("jspActive");var s=aM.pageX-i.position().left;b("html").bind("mousemove.jsp",function(aN){X(aN.pageX-s,false)}).bind("mouseup.jsp mouseleave.jsp",ay);return false});m=an.innerWidth();ai()}}function ai(){an.find(">.jspHorizontalBar>.jspCap:visible,>.jspHorizontalBar>.jspArrow").each(function(){m-=b(this).outerWidth()});I.width(m+"px");ab=0}function H(){if(aH&&aB){var aM=I.outerHeight(),s=aq.outerWidth();u-=aM;b(ao).find(">.jspCap:visible,>.jspArrow").each(function(){m+=b(this).outerWidth()});m-=s;w-=s;al-=aM;I.parent().append(b('
').css("width",aM+"px"));p();ai()}if(aH){Z.width((an.outerWidth()-h)+"px")}aa=Z.outerHeight();r=aa/w;if(aH){au=1/A*m;if(au>aA.horizontalDragMaxWidth){au=aA.horizontalDragMaxWidth}else{if(auaA.verticalDragMaxHeight){C=aA.verticalDragMaxHeight}else{if(CaW){R.scrollByY(-aT)}else{W(aW)}}else{if(aQ>0){if(K+aUaW){R.scrollByX(-aT)}else{X(aW)}}else{if(aQ>0){if(ab+aUj){s=j}}if(aM===c){aM=aA.animateScroll}if(aM){R.animate(aw,"top",s,ae)}else{aw.css("top",s);ae(s)}}function ae(aM){if(aM===c){aM=aw.position().top}an.scrollTop(0);K=aM;var aP=K===0,aN=K==j,aO=aM/j,s=-aO*(aa-w);if(ak!=aP||aK!=aN){ak=aP;aK=aN;F.trigger("jsp-arrow-change",[ak,aK,Q,l])}v(aP,aN);Z.css("top",s);F.trigger("jsp-scroll-y",[-s,aP,aN])}function X(aM,s){if(!aH){return}if(aM<0){aM=0}else{if(aM>k){aM=k}}if(s===c){s=aA.animateScroll}if(s){R.animate(i,"left",aM,af)}else{i.css("left",aM);af(aM)}}function af(aM){if(aM===c){aM=i.position().left}an.scrollTop(0);ab=aM;var aP=ab===0,aO=ab==k,aN=aM/k,s=-aN*(U-al); +if(Q!=aP||l!=aO){Q=aP;l=aO;F.trigger("jsp-arrow-change",[ak,aK,Q,l])}t(aP,aO);Z.css("left",s);F.trigger("jsp-scroll-x",[-s,aP,aO])}function v(aM,s){if(aA.showArrows){ar[aM?"addClass":"removeClass"]("jspDisabled");ag[s?"addClass":"removeClass"]("jspDisabled")}}function t(aM,s){if(aA.showArrows){az[aM?"addClass":"removeClass"]("jspDisabled");z[s?"addClass":"removeClass"]("jspDisabled")}}function N(s,aM){var aN=s/(aa-w);W(aN*j,aM)}function O(aM,s){var aN=aM/(U-al);X(aN*k,s)}function ac(aY,aT,aN){var aR,aO,aP,s=0,aX=0,aM,aS,aV,aU,aW;try{aR=b(aY)}catch(aQ){return}aO=aR.outerHeight();aP=aR.outerWidth();an.scrollTop(0);an.scrollLeft(0);while(!aR.is(".jspPane")){s+=aR.position().top;aX+=aR.position().left;aR=aR.offsetParent();if(/^body|html$/i.test(aR[0].nodeName)){return}}aM=aC();aS=aM+w;if(saS){aU=s-w+aO+aA.verticalGutter}}if(aU){N(aU,aN)}viewportLeft=aE();aV=viewportLeft+al;if(aXaV){aW=aX-al+aP+aA.horizontalGutter}}if(aW){O(aW,aN)}}function aE(){return -Z.position().left}function aC(){return -Z.position().top}function ah(){an.unbind(ad).bind(ad,function(aP,aQ,aO,aM){var aN=ab,s=K;R.scrollBy(aO*aA.mouseWheelSpeed,-aM*aA.mouseWheelSpeed,false);return aN==ab&&s==K})}function o(){an.unbind(ad)}function aD(){return false}function L(){Z.find(":input,a").unbind("focus.jsp").bind("focus.jsp",function(s){ac(s.target,false)})}function G(){Z.find(":input,a").unbind("focus.jsp")}function y(){var aM=ab,s=K;switch(D){case 40:R.scrollByY(aA.keyboardSpeed,false);break;case 38:R.scrollByY(-aA.keyboardSpeed,false);break;case 34:case 32:R.scrollByY(w*aA.scrollPagePercent,false);break;case 33:R.scrollByY(-w*aA.scrollPagePercent,false);break;case 39:R.scrollByX(aA.keyboardSpeed,false);break;case 37:R.scrollByX(-aA.keyboardSpeed,false);break}return aM!=ab||s!=K}function g(s){av=setTimeout(function(){g()},s?aA.initialDelay:aA.keyboardRepeatFreq);if(!y()){aG()}}function aG(){D=null;av&&clearTimeout(av);av=null}function T(){Z.focus(function(){F.focus()});F.attr("tabindex",0).unbind("keydown.jsp keyup.jsp").bind("keydown.jsp",function(aN){if(aN.target!==this){return}var aM=ab,s=K;switch(aN.keyCode){case 40:case 38:case 34:case 32:case 33:case 39:case 37:if(D!=aN.keyCode){aG();D=aN.keyCode;g(true)}break;case 35:N(aa-w);D=null;break;case 36:N(0);D=null;break}if(D==aN.keyCode||aM!=ab||s!=K){return false}}).bind("keyup.jsp",function(s){aG()});if(aA.hideFocus){F.css("outline","none");if("hideFocus" in an[0]){F.attr("hideFocus",true)}}else{F.css("outline","");if("hideFocus" in an[0]){F.attr("hideFocus",false)}}}function S(){F.attr("tabindex","-1").removeAttr("tabindex").unbind("keydown.jsp keyup.jsp")}function E(){if(location.hash&&location.hash.length>1){var aN,aM;try{aN=b(location.hash)}catch(s){return}if(aN.length&&Z.find(location.hash)){if(an.scrollTop()===0){aM=setInterval(function(){if(an.scrollTop()>0){ac(location.hash,true);b(document).scrollTop(an.position().top);clearInterval(aM)}},50)}else{ac(location.hash,true);b(document).scrollTop(an.position().top)}}}}function aj(){b("a.jspHijack").unbind("click.jsp-hijack").removeClass("jspHijack")}function n(){aj();b("a[href^=#]").addClass("jspHijack").bind("click.jsp-hijack",function(){var s=this.href.split("#"),aM;if(s.length>1){aM=s[1];if(aM.length>0&&Z.find("#"+aM).length>0){ac("#"+aM,true);return false}}})}function aJ(){if(!b(":focus").length){F.focus()}}function ap(){var aN,aM,aP,aO,aQ,s=false;an.unbind("touchstart.jsp touchmove.jsp touchend.jsp click.jsp-touchclick").bind("touchstart.jsp",function(aR){var aS=aR.originalEvent.touches[0];aN=aE();aM=aC();aP=aS.pageX;aO=aS.pageY;aQ=false;s=true}).bind("touchmove.jsp",function(aU){if(!s){return}var aT=aU.originalEvent.touches[0],aS=ab,aR=K;R.scrollTo(aN+aP-aT.pageX,aM+aO-aT.pageY);aQ=aQ||Math.abs(aP-aT.pageX)>5||Math.abs(aO-aT.pageY)>5;return aS==ab&&aR==K}).bind("touchend.jsp",function(aR){s=false}).bind("click.jsp-touchclick",function(aR){if(aQ){aQ=false;return false +}})}b.extend(R,{reinitialise:function(aM){aM=b.extend({},aA,aM);at(aM)},scrollToElement:function(aN,aM,s){ac(aN,aM,s)},scrollTo:function(aN,s,aM){O(aN,aM);N(s,aM)},scrollToX:function(aM,s){O(aM,s)},scrollToY:function(s,aM){N(s,aM)},scrollBy:function(aM,s,aN){R.scrollByX(aM,aN);R.scrollByY(s,aN)},scrollByX:function(s,aN){var aM=aE()+s,aO=aM/(U-al);X(aO*k,aN)},scrollByY:function(s,aN){var aM=aC()+s,aO=aM/(aa-w);W(aO*j,aN)},animate:function(aM,aP,s,aO){var aN={};aN[aP]=s;aM.animate(aN,{duration:aA.animateDuration,ease:aA.animateEase,queue:false,step:aO})},getContentPositionX:function(){return aE()},getContentPositionY:function(){return aC()},getIsScrollableH:function(){return aH},getIsScrollableV:function(){return aB},getContentPane:function(){return Z},scrollToBottom:function(s){W(j,s)},hijackInternalLinks:function(){n()}});at(P)}f=b.extend({},b.fn.jScrollPane.defaults,f);b.each(["mouseWheelSpeed","arrowButtonSpeed","trackClickSpeed","keyboardSpeed"],function(){f[this]=f[this]||f.speed});var e;this.each(function(){var g=b(this),h=g.data("jsp");if(h){h.reinitialise(f)}else{h=new d(g,f);g.data("jsp",h)}e=e?e.add(g):g});return e};b.fn.jScrollPane.defaults={showArrows:false,maintainPosition:true,clickOnTrack: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:0,arrowButtonSpeed:0,arrowRepeatFreq:50,arrowScrollOnHover:false,trackClickSpeed:0,trackClickRepeatFreq:70,verticalArrowPositions:"split",horizontalArrowPositions:"split",enableKeyboardNavigation:true,hideFocus:false,keyboardSpeed:0,keyboardRepeatFreq:50,initialDelay:300,speed:30,scrollPagePercent:0.8}})(jQuery,this); \ No newline at end of file diff --git a/ajax/libs/jScrollPane/2.0.0beta8/style/jquery.jscrollpane.css b/ajax/libs/jScrollPane/2.0.0beta8/style/jquery.jscrollpane.css new file mode 100644 index 00000000000000..a051caed0a41b7 --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.0beta8/style/jquery.jscrollpane.css @@ -0,0 +1,120 @@ +/* + * CSS Styles that are needed by jScrollPane for it to operate correctly. + * + * Include this stylesheet in your site or copy and paste the styles below into your stylesheet - jScrollPane + * may not operate correctly without them. + */ + +.jspContainer +{ + overflow: hidden; + position: relative; +} + +.jspPane +{ + position: absolute; +} + +.jspVerticalBar +{ + position: absolute; + top: 0; + right: 0; + width: 16px; + height: 100%; + background: red; +} + +.jspHorizontalBar +{ + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 16px; + background: red; +} + +.jspVerticalBar *, +.jspHorizontalBar * +{ + margin: 0; + padding: 0; +} + +.jspCap +{ + display: none; +} + +.jspHorizontalBar .jspCap +{ + float: left; +} + +.jspTrack +{ + background: #dde; + position: relative; +} + +.jspDrag +{ + background: #bbd; + position: relative; + top: 0; + left: 0; + cursor: pointer; +} + +.jspHorizontalBar .jspTrack, +.jspHorizontalBar .jspDrag +{ + float: left; + height: 100%; +} + +.jspArrow +{ + background: #50506d; + text-indent: -20000px; + display: block; + cursor: pointer; +} + +.jspArrow.jspDisabled +{ + cursor: default; + background: #80808d; +} + +.jspVerticalBar .jspArrow +{ + height: 16px; +} + +.jspHorizontalBar .jspArrow +{ + width: 16px; + float: left; + height: 100%; +} + +.jspVerticalBar .jspArrow:focus +{ + outline: none; +} + +.jspCorner +{ + background: #eeeef4; + float: left; + height: 100%; +} + +/* Yuk! CSS Hack for IE6 3 pixel bug :( */ +* html .jspCorner +{ + margin: 0 -3px 0 0; +} \ No newline at end of file diff --git a/ajax/libs/jScrollPane/2.0.0beta8/style/jquery.jscrollpane.min.css b/ajax/libs/jScrollPane/2.0.0beta8/style/jquery.jscrollpane.min.css new file mode 100644 index 00000000000000..41eaed48ad7829 --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.0beta8/style/jquery.jscrollpane.min.css @@ -0,0 +1 @@ +.jspContainer{overflow:hidden;position:relative}.jspPane{position:absolute}.jspVerticalBar{position:absolute;top:0;right:0;width:16px;height:100%;background:red}.jspHorizontalBar{position:absolute;bottom:0;left:0;width:100%;height:16px;background:red}.jspVerticalBar *,.jspHorizontalBar *{margin:0;padding:0}.jspCap{display:none}.jspHorizontalBar .jspCap{float:left}.jspTrack{background:#dde;position:relative}.jspDrag{background:#bbd;position:relative;top:0;left:0;cursor:pointer}.jspHorizontalBar .jspTrack,.jspHorizontalBar .jspDrag{float:left;height:100%}.jspArrow{background:#50506d;text-indent:-20000px;display:block;cursor:pointer}.jspArrow.jspDisabled{cursor:default;background:#80808d}.jspVerticalBar .jspArrow{height:16px}.jspHorizontalBar .jspArrow{width:16px;float:left;height:100%}.jspVerticalBar .jspArrow:focus{outline:0}.jspCorner{background:#eeeef4;float:left;height:100%}* html .jspCorner{margin:0 -3px 0 0} \ No newline at end of file diff --git a/ajax/libs/jScrollPane/2.0.0beta9/script/jquery.jscrollpane.js b/ajax/libs/jScrollPane/2.0.0beta9/script/jquery.jscrollpane.js new file mode 100644 index 00000000000000..bd636dc549d3f4 --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.0beta9/script/jquery.jscrollpane.js @@ -0,0 +1,1376 @@ +/*! + * jScrollPane - v2.0.0beta9 - 2011-01-31 + * 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.0beta9, Last updated: 2011-01-31* +// +// 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 - tested in 1.4.2+ - reported to work in 1.3.x +// Browsers Tested - Firefox 3.6.8, Safari 5, Opera 10.6, Chrome 5.0, IE 6, 7, 8 +// +// About: Release History +// +// 2.0.0beta9 - (2011-01-31) new API methods, bug fixes and correct keyboard support for FF/OSX +// 2.0.0beta8 - (2011-01-29) touchscreen support, improved keyboard support +// 2.0.0beta7 - (2011-01-23) scroll speed consistent (thanks Aivo Paas) +// 2.0.0beta6 - (2010-12-07) scrollToElement horizontal support +// 2.0.0beta5 - (2010-10-18) jQuery 1.4.3 support, various bug fixes +// 2.0.0beta4 - (2010-09-17) clickOnTrack support, bug fixes +// 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, previousContentWidth, + wasAtTop = true, wasAtLeft = true, wasAtBottom = false, wasAtRight = false, + originalElement = elem.clone().empty(), + 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'), 10) || 0) + + (parseInt(elem.css('paddingRight'), 10) || 0); + + function initialise(s) + { + + var clonedElem, tempWrapper, /*firstChild, lastChild, */isMaintainingPositon, lastContentX, lastContentY, + hasContainingSpaceChanged, originalScrollTop, originalScrollLeft; + + settings = s; + + if (pane === undefined) { + originalScrollTop = elem.scrollTop(); + originalScrollLeft = elem.scrollLeft(); + 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 = $('
').css('padding', originalPadding).append(elem.children()); + container = $('
') + .css({ + 'width': paneWidth + 'px', + 'height': paneHeight + 'px' + } + ).append(pane).appendTo(elem); + + /* + // 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', ''); + + hasContainingSpaceChanged = elem.innerWidth() + originalPaddingTotalWidth != paneWidth || elem.outerHeight() != paneHeight; + + if (hasContainingSpaceChanged) { + paneWidth = elem.innerWidth() + originalPaddingTotalWidth; + paneHeight = elem.innerHeight(); + container.css({ + width: paneWidth + 'px', + height: paneHeight + 'px' + }); + } + + // If nothing changed since last check... + if (!hasContainingSpaceChanged && previousContentWidth == contentWidth && pane.outerHeight() == contentHeight) { + elem.width(paneWidth); + return; + } + previousContentWidth = contentWidth; + + pane.css('width', ''); + elem.width(paneWidth); + + 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 = $('
').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() - originalPaddingTotalWidth + }); + removeMousewheel(); + removeFocusHandler(); + removeKeyboardNav(); + removeClickOnTrack(); + unhijackInternalLinks(); + } else { + elem.addClass('jspScrollable'); + + isMaintainingPositon = settings.maintainPosition && (verticalDragPosition || horizontalDragPosition); + if (isMaintainingPositon) { + lastContentX = contentPositionX(); + lastContentY = contentPositionY(); + } + + initialiseVerticalScroll(); + initialiseHorizontalScroll(); + resizeScrollbars(); + + if (isMaintainingPositon) { + scrollToX(lastContentX, false); + scrollToY(lastContentY, false); + } + + initFocusHandler(); + initMousewheel(); + initTouch(); + + if (settings.enableKeyboardNavigation) { + initKeyboardNav(); + } + if (settings.clickOnTrack) { + initClickOnTrack(); + } + + observeHash(); + if (settings.hijackInternalLinks) { + hijackInternalLinks(); + } + } + + if (settings.autoReinitialise && !reinitialiseInterval) { + reinitialiseInterval = setInterval( + function() + { + initialise(settings); + }, + settings.autoReinitialiseDelay + ); + } else if (!settings.autoReinitialise && reinitialiseInterval) { + clearInterval(reinitialiseInterval); + } + + originalScrollTop && elem.scrollTop(0) && scrollToY(originalScrollTop, false); + originalScrollLeft && elem.scrollLeft(0) && scrollToX(originalScrollLeft, false); + + elem.trigger('jsp-initialised', [isScrollableH || isScrollableV]); + } + + function initialiseVerticalScroll() + { + if (isScrollableV) { + + container.append( + $('
').append( + $('
'), + $('
').append( + $('
').append( + $('
'), + $('
') + ) + ), + $('
') + ) + ); + + verticalBar = container.find('>.jspVerticalBar'); + verticalTrack = verticalBar.find('>.jspTrack'); + verticalDrag = verticalTrack.find('>.jspDrag'); + + if (settings.showArrows) { + arrowUp = $('').bind( + 'mousedown.jsp', getArrowScroll(0, -1) + ).bind('click.jsp', nil); + arrowDown = $('').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', nil); + + 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(); + } + } + + 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( + $('
').append( + $('
'), + $('
').append( + $('
').append( + $('
'), + $('
') + ) + ), + $('
') + ) + ); + + horizontalBar = container.find('>.jspHorizontalBar'); + horizontalTrack = horizontalBar.find('>.jspTrack'); + horizontalDrag = horizontalTrack.find('>.jspDrag'); + + if (settings.showArrows) { + arrowLeft = $('').bind( + 'mousedown.jsp', getArrowScroll(-1, 0) + ).bind('click.jsp', nil); + arrowRight = $('').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', nil); + + 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(); + } + } + + 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( + $('
').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 = Math.ceil(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; + _positionDragX(horizontalDragPosition); // To update the state for the arrow buttons + } + if (isScrollableV) { + verticalDragHeight = Math.ceil(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; + _positionDragY(verticalDragPosition); // To update the state for the arrow buttons + } + } + + 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, + scrollTimeout, + isFirst = true, + doScroll = function() + { + if (dirX !== 0) { + jsp.scrollByX(dirX * settings.arrowButtonSpeed); + } + if (dirY !== 0) { + jsp.scrollByY(dirY * settings.arrowButtonSpeed); + } + scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.arrowRepeatFreq); + isFirst = false; + }; + + doScroll(); + + eve = ele ? 'mouseout.jsp' : 'mouseup.jsp'; + ele = ele || $('html'); + ele.bind( + eve, + function() + { + arrow.removeClass('jspActive'); + scrollTimeout && clearTimeout(scrollTimeout); + scrollTimeout = null; + ele.unbind(eve); + focusElem(); + } + ); + } + + function initClickOnTrack() + { + removeClickOnTrack(); + if (isScrollableV) { + verticalTrack.bind( + 'mousedown.jsp', + function(e) + { + if (e.originalTarget === undefined || e.originalTarget == e.currentTarget) { + var clickedTrack = $(this), + offset = clickedTrack.offset(), + direction = e.pageY - offset.top - verticalDragPosition, + scrollTimeout, + isFirst = true, + doScroll = function() + { + var offset = clickedTrack.offset(), + pos = e.pageY - offset.top - verticalDragHeight / 2, + contentDragY = paneHeight * settings.scrollPagePercent, + dragY = dragMaxY * contentDragY / (contentHeight - paneHeight); + if (direction < 0) { + if (verticalDragPosition - dragY > pos) { + jsp.scrollByY(-contentDragY); + } else { + positionDragY(pos); + } + } else if (direction > 0) { + if (verticalDragPosition + dragY < pos) { + jsp.scrollByY(contentDragY); + } else { + positionDragY(pos); + } + } else { + cancelClick(); + return; + } + scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.trackClickRepeatFreq); + isFirst = false; + }, + cancelClick = function() + { + scrollTimeout && clearTimeout(scrollTimeout); + scrollTimeout = null; + $(document).unbind('mouseup.jsp', cancelClick); + focusElem(); + }; + doScroll(); + $(document).bind('mouseup.jsp', cancelClick); + return false; + } + } + ); + } + + if (isScrollableH) { + horizontalTrack.bind( + 'mousedown.jsp', + function(e) + { + if (e.originalTarget === undefined || e.originalTarget == e.currentTarget) { + var clickedTrack = $(this), + offset = clickedTrack.offset(), + direction = e.pageX - offset.left - horizontalDragPosition, + scrollTimeout, + isFirst = true, + doScroll = function() + { + var offset = clickedTrack.offset(), + pos = e.pageX - offset.left - horizontalDragWidth / 2, + contentDragX = paneWidth * settings.scrollPagePercent, + dragX = dragMaxX * contentDragX / (contentWidth - paneWidth); + if (direction < 0) { + if (horizontalDragPosition - dragX > pos) { + jsp.scrollByX(-contentDragX); + } else { + positionDragX(pos); + } + } else if (direction > 0) { + if (horizontalDragPosition + dragX < pos) { + jsp.scrollByX(contentDragX); + } else { + positionDragX(pos); + } + } else { + cancelClick(); + return; + } + scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.trackClickRepeatFreq); + isFirst = false; + }, + cancelClick = function() + { + scrollTimeout && clearTimeout(scrollTimeout); + scrollTimeout = null; + $(document).unbind('mouseup.jsp', cancelClick); + focusElem(); + }; + doScroll(); + $(document).bind('mouseup.jsp', cancelClick); + return false; + } + } + ); + } + } + + function removeClickOnTrack() + { + if (horizontalTrack) { + horizontalTrack.unbind('mousedown.jsp'); + } + if (verticalTrack) { + verticalTrack.unbind('mousedown.jsp'); + } + } + + function cancelDrag() + { + $('html').unbind('dragstart.jsp selectstart.jsp mousemove.jsp mouseup.jsp mouseleave.jsp'); + + if (verticalDrag) { + verticalDrag.removeClass('jspActive'); + } + if (horizontalDrag) { + horizontalDrag.removeClass('jspActive'); + } + focusElem(); + } + + 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]).trigger('scroll'); + } + + 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 == dragMaxX, + 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]).trigger('scroll'); + } + + 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, eleWidth, eleTop = 0, eleLeft = 0, viewportTop, maxVisibleEleTop, maxVisibleEleLeft, destY, destX; + + // 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(); + eleWidth= e.outerWidth(); + + container.scrollTop(0); + container.scrollLeft(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; + eleLeft += e.position().left; + 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); + } + + viewportLeft = contentPositionX(); + maxVisibleEleLeft = viewportLeft + paneWidth; + if (eleLeft < viewportLeft || stickToTop) { // element is to the left of viewport + destX = eleLeft - settings.horizontalGutter; + } else if (eleLeft + eleWidth > maxVisibleEleLeft) { // element is to the right viewport + destX = eleLeft - paneWidth + eleWidth + settings.horizontalGutter; + } + if (destX) { + scrollToX(destX, animate); + } + + } + + 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; + jsp.scrollBy(deltaX * settings.mouseWheelSpeed, -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.find(':input,a').unbind('focus.jsp').bind( + 'focus.jsp', + function(e) + { + scrollToElement(e.target, false); + } + ); + } + + function removeFocusHandler() + { + pane.find(':input,a').unbind('focus.jsp'); + } + + function initKeyboardNav() + { + var keyDown, elementHasScrolled; + // IE also focuses elements that don't have tabindex set. + pane.focus( + function() + { + elem.focus(); + } + ); + + elem.attr('tabindex', 0) + .unbind('keydown.jsp keypress.jsp') + .bind( + 'keydown.jsp', + function(e) + { + if (e.target !== this){ + return; + } + var dX = horizontalDragPosition, dY = verticalDragPosition; + switch(e.keyCode) { + case 40: // down + case 38: // up + case 34: // page down + case 32: // space + case 33: // page up + case 39: // right + case 37: // left + keyDown = e.keyCode; + keyDownHandler(); + break; + case 35: // end + scrollToY(contentHeight - paneHeight); + keyDown = null; + break; + case 36: // home + scrollToY(0); + keyDown = null; + break; + } + + elementHasScrolled = e.keyCode == keyDown && dX != horizontalDragPosition || dY != verticalDragPosition; + return !elementHasScrolled; + } + ).bind( + 'keypress.jsp', // For FF/ OSX so that we can cancel the repeat key presses if the JSP scrolls... + function(e) + { + if (e.keyCode == keyDown) { + keyDownHandler(); + } + return !elementHasScrolled; + } + ); + + 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 keyDownHandler() + { + var dX = horizontalDragPosition, dY = verticalDragPosition; + switch(keyDown) { + case 40: // down + jsp.scrollByY(settings.keyboardSpeed, false); + break; + case 38: // up + jsp.scrollByY(-settings.keyboardSpeed, false); + break; + case 34: // page down + case 32: // space + jsp.scrollByY(paneHeight * settings.scrollPagePercent, false); + break; + case 33: // page up + jsp.scrollByY(-paneHeight * settings.scrollPagePercent, false); + break; + case 39: // right + jsp.scrollByX(settings.keyboardSpeed, false); + break; + case 37: // left + jsp.scrollByX(-settings.keyboardSpeed, false); + break; + } + + elementHasScrolled = dX != horizontalDragPosition || dY != verticalDragPosition; + return elementHasScrolled; + } + } + + function removeKeyboardNav() + { + elem.attr('tabindex', '-1') + .removeAttr('tabindex') + .unbind('keydown.jsp keypress.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(location.hash)) { + // 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; + } + } + } + ); + } + + // If no element has focus, focus elem to support keyboard navigation + function focusElem() + { + if (!$(':focus').length) { + elem.focus(); + } + } + + // Init touch on iPad, iPhone, iPod, Android + function initTouch() + { + var startX, + startY, + touchStartX, + touchStartY, + moved, + moving = false; + + container.unbind('touchstart.jsp touchmove.jsp touchend.jsp click.jsp-touchclick').bind( + 'touchstart.jsp', + function(e) + { + var touch = e.originalEvent.touches[0]; + startX = contentPositionX(); + startY = contentPositionY(); + touchStartX = touch.pageX; + touchStartY = touch.pageY; + moved = false; + moving = true; + } + ).bind( + 'touchmove.jsp', + function(ev) + { + if(!moving) { + return; + } + + var touchPos = ev.originalEvent.touches[0], + dX = horizontalDragPosition, dY = verticalDragPosition; + + jsp.scrollTo(startX + touchStartX - touchPos.pageX, startY + touchStartY - touchPos.pageY); + + moved = moved || Math.abs(touchStartX - touchPos.pageX) > 5 || Math.abs(touchStartY - touchPos.pageY) > 5; + + // return true if there was no movement so rest of screen can scroll + return dX == horizontalDragPosition && dY == verticalDragPosition; + } + ).bind( + 'touchend.jsp', + function(e) + { + moving = false; + /*if(moved) { + return false; + }*/ + } + ).bind( + 'click.jsp-touchclick', + function(e) + { + if(moved) { + moved = false; + return false; + } + } + ); + } + + function destroy(){ + var currentY = contentPositionY(), + currentX = contentPositionX(); + elem.removeClass('jspScrollable').unbind('.jsp'); + elem.replaceWith(originalElement.append(pane.children())); + originalElement.scrollTop(currentY); + originalElement.scrollLeft(currentX); + } + + // 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({}, settings, s); + 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 to the specified percentage of its maximum horizontal scroll position. animate + // is optional and if not passed then the value of animateScroll from the settings object this + // jScrollPane was initialised with is used. + scrollToPercentX: function(destPercentX, animate) + { + scrollToX(destPercentX * (contentWidth - paneWidth), animate); + }, + // Scrolls the pane to the specified percentage of its maximum vertical scroll position. animate + // is optional and if not passed then the value of animateScroll from the settings object this + // jScrollPane was initialised with is used. + scrollToPercentY: function(destPercentY, animate) + { + scrollToY(destPercentY * (contentHeight - paneHeight), 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); + }, + // Positions the horizontal drag at the specified x position (and updates the viewport to reflect + // this). animate is optional and if not passed then the value of animateScroll from the settings + // object this jScrollPane was initialised with is used. + positionDragX: function(x, animate) + { + positionDragX(x, animate); + }, + // Positions the vertical drag at the specified y position (and updates the viewport to reflect + // this). animate is optional and if not passed then the value of animateScroll from the settings + // object this jScrollPane was initialised with is used. + positionDragY: function(y, animate) + { + positionDragX(y, 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 the width of the content within the scroll pane. + getContentWidth: function() + { + return contentWidth(); + }, + // Returns the height of the content within the scroll pane. + getContentHeight: function() + { + return contentHeight(); + }, + // Returns the horizontal position of the viewport within the pane content. + getPercentScrolledX: function() + { + return contentPositionX() / (contentWidth - paneWidth); + }, + // Returns the vertical position of the viewport within the pane content. + getPercentScrolledY: function() + { + return contentPositionY() / (contentHeight - paneHeight); + }, + // 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(); + }, + // Removes the jScrollPane and returns the page to the state it was in before jScrollPane was + // initialised. + destroy: function() + { + destroy(); + } + } + ); + + initialise(s); + } + + // Pluginifying code... + settings = $.extend({}, $.fn.jScrollPane.defaults, settings); + + // Apply default speed + $.each(['mouseWheelSpeed', 'arrowButtonSpeed', 'trackClickSpeed', 'keyboardSpeed'], function() { + settings[this] = settings[this] || settings.speed; + }); + + 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, + clickOnTrack : 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 : 0, + arrowButtonSpeed : 0, + arrowRepeatFreq : 50, + arrowScrollOnHover : false, + trackClickSpeed : 0, + trackClickRepeatFreq : 70, + verticalArrowPositions : 'split', + horizontalArrowPositions : 'split', + enableKeyboardNavigation : true, + hideFocus : false, + keyboardSpeed : 0, + initialDelay : 300, // Delay before starting repeating + speed : 30, // Default speed when others falsey + scrollPagePercent : .8 // Percent of visible area scrolled when pageUp/Down or track area pressed + }; + +})(jQuery,this); + diff --git a/ajax/libs/jScrollPane/2.0.0beta9/script/jquery.jscrollpane.min.js b/ajax/libs/jScrollPane/2.0.0beta9/script/jquery.jscrollpane.min.js new file mode 100644 index 00000000000000..2c339fdfcb1a1c --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.0beta9/script/jquery.jscrollpane.min.js @@ -0,0 +1,11 @@ +/* + * jScrollPane - v2.0.0beta9 - 2011-01-31 + * http://jscrollpane.kelvinluck.com/ + * + * Copyright (c) 2010 Kelvin Luck + * Dual licensed under the MIT and GPL licenses. + */ +(function(b,a,c){b.fn.jScrollPane=function(f){function d(D,N){var ay,P=this,X,aj,w,al,S,Y,z,r,az,aE,au,j,I,i,k,Z,T,ap,W,u,B,aq,ae,am,G,m,at,ax,y,av,aI,g,K,ai=true,O=true,aH=false,l=false,ao=D.clone().empty(),ab=b.fn.mwheelIntent?"mwheelIntent.jsp":"mousewheel.jsp";aI=D.css("paddingTop")+" "+D.css("paddingRight")+" "+D.css("paddingBottom")+" "+D.css("paddingLeft");g=(parseInt(D.css("paddingLeft"),10)||0)+(parseInt(D.css("paddingRight"),10)||0);function ar(aR){var aP,aQ,aL,aN,aM,aK,aJ,aO;ay=aR;if(X===c){aJ=D.scrollTop();aO=D.scrollLeft();D.css({overflow:"hidden",padding:0});aj=D.innerWidth()+g;w=D.innerHeight();D.width(aj);X=b('
').css("padding",aI).append(D.children());al=b('
').css({width:aj+"px",height:w+"px"}).append(X).appendTo(D)}else{D.css("width","");aK=D.innerWidth()+g!=aj||D.outerHeight()!=w;if(aK){aj=D.innerWidth()+g;w=D.innerHeight();al.css({width:aj+"px",height:w+"px"})}if(!aK&&K==S&&X.outerHeight()==Y){D.width(aj);return}K=S;X.css("width","");D.width(aj);al.find(">.jspVerticalBar,>.jspHorizontalBar").remove().end()}aP=X.clone().css("position","absolute");aQ=b('
').append(aP);b("body").append(aQ);S=Math.max(X.outerWidth(),aP.outerWidth());aQ.remove();Y=X.outerHeight();z=S/aj;r=Y/w;az=r>1;aE=z>1;if(!(aE||az)){D.removeClass("jspScrollable");X.css({top:0,width:al.width()-g});o();E();Q();x();ah()}else{D.addClass("jspScrollable");aL=ay.maintainPosition&&(I||Z);if(aL){aN=aC();aM=aA()}aF();A();F();if(aL){M(aN,false);L(aM,false)}J();af();an();if(ay.enableKeyboardNavigation){R()}if(ay.clickOnTrack){q()}C();if(ay.hijackInternalLinks){n()}}if(ay.autoReinitialise&&!av){av=setInterval(function(){ar(ay)},ay.autoReinitialiseDelay)}else{if(!ay.autoReinitialise&&av){clearInterval(av)}}aJ&&D.scrollTop(0)&&L(aJ,false);aO&&D.scrollLeft(0)&&M(aO,false);D.trigger("jsp-initialised",[aE||az])}function aF(){if(az){al.append(b('
').append(b('
'),b('
').append(b('
').append(b('
'),b('
'))),b('
')));T=al.find(">.jspVerticalBar");ap=T.find(">.jspTrack");au=ap.find(">.jspDrag");if(ay.showArrows){aq=b('').bind("mousedown.jsp",aD(0,-1)).bind("click.jsp",aB);ae=b('').bind("mousedown.jsp",aD(0,1)).bind("click.jsp",aB);if(ay.arrowScrollOnHover){aq.bind("mouseover.jsp",aD(0,-1,aq));ae.bind("mouseover.jsp",aD(0,1,ae))}ak(ap,ay.verticalArrowPositions,aq,ae)}u=w;al.find(">.jspVerticalBar>.jspCap:visible,>.jspVerticalBar>.jspArrow").each(function(){u-=b(this).outerHeight()});au.hover(function(){au.addClass("jspHover")},function(){au.removeClass("jspHover")}).bind("mousedown.jsp",function(aJ){b("html").bind("dragstart.jsp selectstart.jsp",aB);au.addClass("jspActive");var s=aJ.pageY-au.position().top;b("html").bind("mousemove.jsp",function(aK){U(aK.pageY-s,false)}).bind("mouseup.jsp mouseleave.jsp",aw);return false});p()}}function p(){ap.height(u+"px");I=0;W=ay.verticalGutter+ap.outerWidth();X.width(aj-W-g);if(T.position().left===0){X.css("margin-left",W+"px")}}function A(){if(aE){al.append(b('
').append(b('
'),b('
').append(b('
').append(b('
'),b('
'))),b('
')));am=al.find(">.jspHorizontalBar");G=am.find(">.jspTrack");i=G.find(">.jspDrag");if(ay.showArrows){ax=b('').bind("mousedown.jsp",aD(-1,0)).bind("click.jsp",aB);y=b('').bind("mousedown.jsp",aD(1,0)).bind("click.jsp",aB);if(ay.arrowScrollOnHover){ax.bind("mouseover.jsp",aD(-1,0,ax)); +y.bind("mouseover.jsp",aD(1,0,y))}ak(G,ay.horizontalArrowPositions,ax,y)}i.hover(function(){i.addClass("jspHover")},function(){i.removeClass("jspHover")}).bind("mousedown.jsp",function(aJ){b("html").bind("dragstart.jsp selectstart.jsp",aB);i.addClass("jspActive");var s=aJ.pageX-i.position().left;b("html").bind("mousemove.jsp",function(aK){V(aK.pageX-s,false)}).bind("mouseup.jsp mouseleave.jsp",aw);return false});m=al.innerWidth();ag()}}function ag(){al.find(">.jspHorizontalBar>.jspCap:visible,>.jspHorizontalBar>.jspArrow").each(function(){m-=b(this).outerWidth()});G.width(m+"px");Z=0}function F(){if(aE&&az){var aJ=G.outerHeight(),s=ap.outerWidth();u-=aJ;b(am).find(">.jspCap:visible,>.jspArrow").each(function(){m+=b(this).outerWidth()});m-=s;w-=s;aj-=aJ;G.parent().append(b('
').css("width",aJ+"px"));p();ag()}if(aE){X.width((al.outerWidth()-g)+"px")}Y=X.outerHeight();r=Y/w;if(aE){at=Math.ceil(1/z*m);if(at>ay.horizontalDragMaxWidth){at=ay.horizontalDragMaxWidth}else{if(atay.verticalDragMaxHeight){B=ay.verticalDragMaxHeight}else{if(BaT){P.scrollByY(-aQ)}else{U(aT)}}else{if(aN>0){if(I+aRaT){P.scrollByX(-aQ)}else{V(aT)}}else{if(aN>0){if(Z+aRj){s=j}}if(aJ===c){aJ=ay.animateScroll}if(aJ){P.animate(au,"top",s,ac)}else{au.css("top",s);ac(s)}}function ac(aJ){if(aJ===c){aJ=au.position().top}al.scrollTop(0);I=aJ;var aM=I===0,aK=I==j,aL=aJ/j,s=-aL*(Y-w);if(ai!=aM||aH!=aK){ai=aM;aH=aK;D.trigger("jsp-arrow-change",[ai,aH,O,l])}v(aM,aK);X.css("top",s);D.trigger("jsp-scroll-y",[-s,aM,aK]).trigger("scroll")}function V(aJ,s){if(!aE){return}if(aJ<0){aJ=0}else{if(aJ>k){aJ=k}}if(s===c){s=ay.animateScroll}if(s){P.animate(i,"left",aJ,ad)}else{i.css("left",aJ);ad(aJ)}}function ad(aJ){if(aJ===c){aJ=i.position().left +}al.scrollTop(0);Z=aJ;var aM=Z===0,aL=Z==k,aK=aJ/k,s=-aK*(S-aj);if(O!=aM||l!=aL){O=aM;l=aL;D.trigger("jsp-arrow-change",[ai,aH,O,l])}t(aM,aL);X.css("left",s);D.trigger("jsp-scroll-x",[-s,aM,aL]).trigger("scroll")}function v(aJ,s){if(ay.showArrows){aq[aJ?"addClass":"removeClass"]("jspDisabled");ae[s?"addClass":"removeClass"]("jspDisabled")}}function t(aJ,s){if(ay.showArrows){ax[aJ?"addClass":"removeClass"]("jspDisabled");y[s?"addClass":"removeClass"]("jspDisabled")}}function L(s,aJ){var aK=s/(Y-w);U(aK*j,aJ)}function M(aJ,s){var aK=aJ/(S-aj);V(aK*k,s)}function aa(aV,aQ,aK){var aO,aL,aM,s=0,aU=0,aJ,aP,aS,aR,aT;try{aO=b(aV)}catch(aN){return}aL=aO.outerHeight();aM=aO.outerWidth();al.scrollTop(0);al.scrollLeft(0);while(!aO.is(".jspPane")){s+=aO.position().top;aU+=aO.position().left;aO=aO.offsetParent();if(/^body|html$/i.test(aO[0].nodeName)){return}}aJ=aA();aP=aJ+w;if(saP){aR=s-w+aL+ay.verticalGutter}}if(aR){L(aR,aK)}viewportLeft=aC();aS=viewportLeft+aj;if(aUaS){aT=aU-aj+aM+ay.horizontalGutter}}if(aT){M(aT,aK)}}function aC(){return -X.position().left}function aA(){return -X.position().top}function af(){al.unbind(ab).bind(ab,function(aM,aN,aL,aJ){var aK=Z,s=I;P.scrollBy(aL*ay.mouseWheelSpeed,-aJ*ay.mouseWheelSpeed,false);return aK==Z&&s==I})}function o(){al.unbind(ab)}function aB(){return false}function J(){X.find(":input,a").unbind("focus.jsp").bind("focus.jsp",function(s){aa(s.target,false)})}function E(){X.find(":input,a").unbind("focus.jsp")}function R(){var s,aJ;X.focus(function(){D.focus()});D.attr("tabindex",0).unbind("keydown.jsp keypress.jsp").bind("keydown.jsp",function(aN){if(aN.target!==this){return}var aM=Z,aL=I;switch(aN.keyCode){case 40:case 38:case 34:case 32:case 33:case 39:case 37:s=aN.keyCode;aK();break;case 35:L(Y-w);s=null;break;case 36:L(0);s=null;break}aJ=aN.keyCode==s&&aM!=Z||aL!=I;return !aJ}).bind("keypress.jsp",function(aL){if(aL.keyCode==s){aK()}return !aJ});if(ay.hideFocus){D.css("outline","none");if("hideFocus" in al[0]){D.attr("hideFocus",true)}}else{D.css("outline","");if("hideFocus" in al[0]){D.attr("hideFocus",false)}}function aK(){var aM=Z,aL=I;switch(s){case 40:P.scrollByY(ay.keyboardSpeed,false);break;case 38:P.scrollByY(-ay.keyboardSpeed,false);break;case 34:case 32:P.scrollByY(w*ay.scrollPagePercent,false);break;case 33:P.scrollByY(-w*ay.scrollPagePercent,false);break;case 39:P.scrollByX(ay.keyboardSpeed,false);break;case 37:P.scrollByX(-ay.keyboardSpeed,false);break}aJ=aM!=Z||aL!=I;return aJ}}function Q(){D.attr("tabindex","-1").removeAttr("tabindex").unbind("keydown.jsp keypress.jsp")}function C(){if(location.hash&&location.hash.length>1){var aK,aJ;try{aK=b(location.hash)}catch(s){return}if(aK.length&&X.find(location.hash)){if(al.scrollTop()===0){aJ=setInterval(function(){if(al.scrollTop()>0){aa(location.hash,true);b(document).scrollTop(al.position().top);clearInterval(aJ)}},50)}else{aa(location.hash,true);b(document).scrollTop(al.position().top)}}}}function ah(){b("a.jspHijack").unbind("click.jsp-hijack").removeClass("jspHijack")}function n(){ah();b("a[href^=#]").addClass("jspHijack").bind("click.jsp-hijack",function(){var s=this.href.split("#"),aJ;if(s.length>1){aJ=s[1];if(aJ.length>0&&X.find("#"+aJ).length>0){aa("#"+aJ,true);return false}}})}function aG(){if(!b(":focus").length){D.focus()}}function an(){var aK,aJ,aM,aL,aN,s=false;al.unbind("touchstart.jsp touchmove.jsp touchend.jsp click.jsp-touchclick").bind("touchstart.jsp",function(aO){var aP=aO.originalEvent.touches[0];aK=aC();aJ=aA();aM=aP.pageX;aL=aP.pageY;aN=false;s=true}).bind("touchmove.jsp",function(aR){if(!s){return}var aQ=aR.originalEvent.touches[0],aP=Z,aO=I;P.scrollTo(aK+aM-aQ.pageX,aJ+aL-aQ.pageY);aN=aN||Math.abs(aM-aQ.pageX)>5||Math.abs(aL-aQ.pageY)>5;return aP==Z&&aO==I}).bind("touchend.jsp",function(aO){s=false}).bind("click.jsp-touchclick",function(aO){if(aN){aN=false;return false}})}function h(){var s=aA(),aJ=aC();D.removeClass("jspScrollable").unbind(".jsp"); +D.replaceWith(ao.append(X.children()));ao.scrollTop(s);ao.scrollLeft(aJ)}b.extend(P,{reinitialise:function(aJ){aJ=b.extend({},ay,aJ);ar(aJ)},scrollToElement:function(aK,aJ,s){aa(aK,aJ,s)},scrollTo:function(aK,s,aJ){M(aK,aJ);L(s,aJ)},scrollToX:function(aJ,s){M(aJ,s)},scrollToY:function(s,aJ){L(s,aJ)},scrollToPercentX:function(aJ,s){M(aJ*(S-aj),s)},scrollToPercentY:function(aJ,s){L(aJ*(Y-w),s)},scrollBy:function(aJ,s,aK){P.scrollByX(aJ,aK);P.scrollByY(s,aK)},scrollByX:function(s,aK){var aJ=aC()+s,aL=aJ/(S-aj);V(aL*k,aK)},scrollByY:function(s,aK){var aJ=aA()+s,aL=aJ/(Y-w);U(aL*j,aK)},positionDragX:function(s,aJ){V(s,aJ)},positionDragY:function(aJ,s){V(aJ,s)},animate:function(aJ,aM,s,aL){var aK={};aK[aM]=s;aJ.animate(aK,{duration:ay.animateDuration,ease:ay.animateEase,queue:false,step:aL})},getContentPositionX:function(){return aC()},getContentPositionY:function(){return aA()},getContentWidth:function(){return S()},getContentHeight:function(){return Y()},getPercentScrolledX:function(){return aC()/(S-aj)},getPercentScrolledY:function(){return aA()/(Y-w)},getIsScrollableH:function(){return aE},getIsScrollableV:function(){return az},getContentPane:function(){return X},scrollToBottom:function(s){U(j,s)},hijackInternalLinks:function(){n()},destroy:function(){h()}});ar(N)}f=b.extend({},b.fn.jScrollPane.defaults,f);b.each(["mouseWheelSpeed","arrowButtonSpeed","trackClickSpeed","keyboardSpeed"],function(){f[this]=f[this]||f.speed});var e;this.each(function(){var g=b(this),h=g.data("jsp");if(h){h.reinitialise(f)}else{h=new d(g,f);g.data("jsp",h)}e=e?e.add(g):g});return e};b.fn.jScrollPane.defaults={showArrows:false,maintainPosition:true,clickOnTrack: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:0,arrowButtonSpeed:0,arrowRepeatFreq:50,arrowScrollOnHover:false,trackClickSpeed:0,trackClickRepeatFreq:70,verticalArrowPositions:"split",horizontalArrowPositions:"split",enableKeyboardNavigation:true,hideFocus:false,keyboardSpeed:0,initialDelay:300,speed:30,scrollPagePercent:0.8}})(jQuery,this); \ No newline at end of file diff --git a/ajax/libs/jScrollPane/2.0.0beta9/style/jquery.jscrollpane.css b/ajax/libs/jScrollPane/2.0.0beta9/style/jquery.jscrollpane.css new file mode 100644 index 00000000000000..a051caed0a41b7 --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.0beta9/style/jquery.jscrollpane.css @@ -0,0 +1,120 @@ +/* + * CSS Styles that are needed by jScrollPane for it to operate correctly. + * + * Include this stylesheet in your site or copy and paste the styles below into your stylesheet - jScrollPane + * may not operate correctly without them. + */ + +.jspContainer +{ + overflow: hidden; + position: relative; +} + +.jspPane +{ + position: absolute; +} + +.jspVerticalBar +{ + position: absolute; + top: 0; + right: 0; + width: 16px; + height: 100%; + background: red; +} + +.jspHorizontalBar +{ + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 16px; + background: red; +} + +.jspVerticalBar *, +.jspHorizontalBar * +{ + margin: 0; + padding: 0; +} + +.jspCap +{ + display: none; +} + +.jspHorizontalBar .jspCap +{ + float: left; +} + +.jspTrack +{ + background: #dde; + position: relative; +} + +.jspDrag +{ + background: #bbd; + position: relative; + top: 0; + left: 0; + cursor: pointer; +} + +.jspHorizontalBar .jspTrack, +.jspHorizontalBar .jspDrag +{ + float: left; + height: 100%; +} + +.jspArrow +{ + background: #50506d; + text-indent: -20000px; + display: block; + cursor: pointer; +} + +.jspArrow.jspDisabled +{ + cursor: default; + background: #80808d; +} + +.jspVerticalBar .jspArrow +{ + height: 16px; +} + +.jspHorizontalBar .jspArrow +{ + width: 16px; + float: left; + height: 100%; +} + +.jspVerticalBar .jspArrow:focus +{ + outline: none; +} + +.jspCorner +{ + background: #eeeef4; + float: left; + height: 100%; +} + +/* Yuk! CSS Hack for IE6 3 pixel bug :( */ +* html .jspCorner +{ + margin: 0 -3px 0 0; +} \ No newline at end of file diff --git a/ajax/libs/jScrollPane/2.0.0beta9/style/jquery.jscrollpane.min.css b/ajax/libs/jScrollPane/2.0.0beta9/style/jquery.jscrollpane.min.css new file mode 100644 index 00000000000000..41eaed48ad7829 --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.0beta9/style/jquery.jscrollpane.min.css @@ -0,0 +1 @@ +.jspContainer{overflow:hidden;position:relative}.jspPane{position:absolute}.jspVerticalBar{position:absolute;top:0;right:0;width:16px;height:100%;background:red}.jspHorizontalBar{position:absolute;bottom:0;left:0;width:100%;height:16px;background:red}.jspVerticalBar *,.jspHorizontalBar *{margin:0;padding:0}.jspCap{display:none}.jspHorizontalBar .jspCap{float:left}.jspTrack{background:#dde;position:relative}.jspDrag{background:#bbd;position:relative;top:0;left:0;cursor:pointer}.jspHorizontalBar .jspTrack,.jspHorizontalBar .jspDrag{float:left;height:100%}.jspArrow{background:#50506d;text-indent:-20000px;display:block;cursor:pointer}.jspArrow.jspDisabled{cursor:default;background:#80808d}.jspVerticalBar .jspArrow{height:16px}.jspHorizontalBar .jspArrow{width:16px;float:left;height:100%}.jspVerticalBar .jspArrow:focus{outline:0}.jspCorner{background:#eeeef4;float:left;height:100%}* html .jspCorner{margin:0 -3px 0 0} \ No newline at end of file diff --git a/ajax/libs/jScrollPane/2.0.13/script/jquery.jscrollpane.js b/ajax/libs/jScrollPane/2.0.13/script/jquery.jscrollpane.js new file mode 100644 index 00000000000000..aa83cf4d8c96ac --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.13/script/jquery.jscrollpane.js @@ -0,0 +1,1437 @@ +/*! + * jScrollPane - v2.0.13 - 2013-05-01 + * 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.13, Last updated: 2013-05-01* +// +// 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) 2013 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 - tested in 1.4.2+ - reported to work in 1.3.x +// Browsers Tested - Firefox 3.6.8, Safari 5, Opera 10.6, Chrome 5.0, IE 6, 7, 8 +// +// About: Release History +// +// 2.0.13 - (2013-05-01) Switched to semver compatible version name +// 2.0.0beta12 - (2012-09-27) fix for jQuery 1.8+ +// 2.0.0beta11 - (2012-05-14) +// 2.0.0beta10 - (2011-04-17) cleaner required size calculation, improved keyboard support, stickToBottom/Left, other small fixes +// 2.0.0beta9 - (2011-01-31) new API methods, bug fixes and correct keyboard support for FF/OSX +// 2.0.0beta8 - (2011-01-29) touchscreen support, improved keyboard support +// 2.0.0beta7 - (2011-01-23) scroll speed consistent (thanks Aivo Paas) +// 2.0.0beta6 - (2010-12-07) scrollToElement horizontal support +// 2.0.0beta5 - (2010-10-18) jQuery 1.4.3 support, various bug fixes +// 2.0.0beta4 - (2010-09-17) clickOnTrack support, bug fixes +// 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, previousContentWidth, + wasAtTop = true, wasAtLeft = true, wasAtBottom = false, wasAtRight = false, + originalElement = elem.clone(false, false).empty(), + 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'), 10) || 0) + + (parseInt(elem.css('paddingRight'), 10) || 0); + + function initialise(s) + { + + var /*firstChild, lastChild, */isMaintainingPositon, lastContentX, lastContentY, + hasContainingSpaceChanged, originalScrollTop, originalScrollLeft, + maintainAtBottom = false, maintainAtRight = false; + + settings = s; + + if (pane === undefined) { + originalScrollTop = elem.scrollTop(); + originalScrollLeft = elem.scrollLeft(); + + 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 = $('
').css('padding', originalPadding).append(elem.children()); + container = $('
') + .css({ + 'width': paneWidth + 'px', + 'height': paneHeight + 'px' + } + ).append(pane).appendTo(elem); + + /* + // 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', ''); + + maintainAtBottom = settings.stickToBottom && isCloseToBottom(); + maintainAtRight = settings.stickToRight && isCloseToRight(); + + hasContainingSpaceChanged = elem.innerWidth() + originalPaddingTotalWidth != paneWidth || elem.outerHeight() != paneHeight; + + if (hasContainingSpaceChanged) { + paneWidth = elem.innerWidth() + originalPaddingTotalWidth; + paneHeight = elem.innerHeight(); + container.css({ + width: paneWidth + 'px', + height: paneHeight + 'px' + }); + } + + // If nothing changed since last check... + if (!hasContainingSpaceChanged && previousContentWidth == contentWidth && pane.outerHeight() == contentHeight) { + elem.width(paneWidth); + return; + } + previousContentWidth = contentWidth; + + pane.css('width', ''); + elem.width(paneWidth); + + container.find('>.jspVerticalBar,>.jspHorizontalBar').remove().end(); + } + + pane.css('overflow', 'auto'); + if (s.contentWidth) { + contentWidth = s.contentWidth; + } else { + contentWidth = pane[0].scrollWidth; + } + contentHeight = pane[0].scrollHeight; + pane.css('overflow', ''); + + 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() - originalPaddingTotalWidth + }); + removeMousewheel(); + removeFocusHandler(); + removeKeyboardNav(); + removeClickOnTrack(); + } else { + elem.addClass('jspScrollable'); + + isMaintainingPositon = settings.maintainPosition && (verticalDragPosition || horizontalDragPosition); + if (isMaintainingPositon) { + lastContentX = contentPositionX(); + lastContentY = contentPositionY(); + } + + initialiseVerticalScroll(); + initialiseHorizontalScroll(); + resizeScrollbars(); + + if (isMaintainingPositon) { + scrollToX(maintainAtRight ? (contentWidth - paneWidth ) : lastContentX, false); + scrollToY(maintainAtBottom ? (contentHeight - paneHeight) : lastContentY, false); + } + + initFocusHandler(); + initMousewheel(); + initTouch(); + + if (settings.enableKeyboardNavigation) { + initKeyboardNav(); + } + if (settings.clickOnTrack) { + initClickOnTrack(); + } + + observeHash(); + if (settings.hijackInternalLinks) { + hijackInternalLinks(); + } + } + + if (settings.autoReinitialise && !reinitialiseInterval) { + reinitialiseInterval = setInterval( + function() + { + initialise(settings); + }, + settings.autoReinitialiseDelay + ); + } else if (!settings.autoReinitialise && reinitialiseInterval) { + clearInterval(reinitialiseInterval); + } + + originalScrollTop && elem.scrollTop(0) && scrollToY(originalScrollTop, false); + originalScrollLeft && elem.scrollLeft(0) && scrollToX(originalScrollLeft, false); + + elem.trigger('jsp-initialised', [isScrollableH || isScrollableV]); + } + + function initialiseVerticalScroll() + { + if (isScrollableV) { + + container.append( + $('
').append( + $('
'), + $('
').append( + $('
').append( + $('
'), + $('
') + ) + ), + $('
') + ) + ); + + verticalBar = container.find('>.jspVerticalBar'); + verticalTrack = verticalBar.find('>.jspTrack'); + verticalDrag = verticalTrack.find('>.jspDrag'); + + if (settings.showArrows) { + arrowUp = $('').bind( + 'mousedown.jsp', getArrowScroll(0, -1) + ).bind('click.jsp', nil); + arrowDown = $('').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', nil); + + 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(); + } + } + + 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) + try { + if (verticalBar.position().left === 0) { + pane.css('margin-left', scrollbarWidth + 'px'); + } + } catch (err) { + } + } + + function initialiseHorizontalScroll() + { + if (isScrollableH) { + + container.append( + $('
').append( + $('
'), + $('
').append( + $('
').append( + $('
'), + $('
') + ) + ), + $('
') + ) + ); + + horizontalBar = container.find('>.jspHorizontalBar'); + horizontalTrack = horizontalBar.find('>.jspTrack'); + horizontalDrag = horizontalTrack.find('>.jspDrag'); + + if (settings.showArrows) { + arrowLeft = $('').bind( + 'mousedown.jsp', getArrowScroll(-1, 0) + ).bind('click.jsp', nil); + arrowRight = $('').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', nil); + + 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(); + } + } + + 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( + $('
').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 = Math.ceil(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; + _positionDragX(horizontalDragPosition); // To update the state for the arrow buttons + } + if (isScrollableV) { + verticalDragHeight = Math.ceil(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; + _positionDragY(verticalDragPosition); // To update the state for the arrow buttons + } + } + + 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, + scrollTimeout, + isFirst = true, + doScroll = function() + { + if (dirX !== 0) { + jsp.scrollByX(dirX * settings.arrowButtonSpeed); + } + if (dirY !== 0) { + jsp.scrollByY(dirY * settings.arrowButtonSpeed); + } + scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.arrowRepeatFreq); + isFirst = false; + }; + + doScroll(); + + eve = ele ? 'mouseout.jsp' : 'mouseup.jsp'; + ele = ele || $('html'); + ele.bind( + eve, + function() + { + arrow.removeClass('jspActive'); + scrollTimeout && clearTimeout(scrollTimeout); + scrollTimeout = null; + ele.unbind(eve); + } + ); + } + + function initClickOnTrack() + { + removeClickOnTrack(); + if (isScrollableV) { + verticalTrack.bind( + 'mousedown.jsp', + function(e) + { + if (e.originalTarget === undefined || e.originalTarget == e.currentTarget) { + var clickedTrack = $(this), + offset = clickedTrack.offset(), + direction = e.pageY - offset.top - verticalDragPosition, + scrollTimeout, + isFirst = true, + doScroll = function() + { + var offset = clickedTrack.offset(), + pos = e.pageY - offset.top - verticalDragHeight / 2, + contentDragY = paneHeight * settings.scrollPagePercent, + dragY = dragMaxY * contentDragY / (contentHeight - paneHeight); + if (direction < 0) { + if (verticalDragPosition - dragY > pos) { + jsp.scrollByY(-contentDragY); + } else { + positionDragY(pos); + } + } else if (direction > 0) { + if (verticalDragPosition + dragY < pos) { + jsp.scrollByY(contentDragY); + } else { + positionDragY(pos); + } + } else { + cancelClick(); + return; + } + scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.trackClickRepeatFreq); + isFirst = false; + }, + cancelClick = function() + { + scrollTimeout && clearTimeout(scrollTimeout); + scrollTimeout = null; + $(document).unbind('mouseup.jsp', cancelClick); + }; + doScroll(); + $(document).bind('mouseup.jsp', cancelClick); + return false; + } + } + ); + } + + if (isScrollableH) { + horizontalTrack.bind( + 'mousedown.jsp', + function(e) + { + if (e.originalTarget === undefined || e.originalTarget == e.currentTarget) { + var clickedTrack = $(this), + offset = clickedTrack.offset(), + direction = e.pageX - offset.left - horizontalDragPosition, + scrollTimeout, + isFirst = true, + doScroll = function() + { + var offset = clickedTrack.offset(), + pos = e.pageX - offset.left - horizontalDragWidth / 2, + contentDragX = paneWidth * settings.scrollPagePercent, + dragX = dragMaxX * contentDragX / (contentWidth - paneWidth); + if (direction < 0) { + if (horizontalDragPosition - dragX > pos) { + jsp.scrollByX(-contentDragX); + } else { + positionDragX(pos); + } + } else if (direction > 0) { + if (horizontalDragPosition + dragX < pos) { + jsp.scrollByX(contentDragX); + } else { + positionDragX(pos); + } + } else { + cancelClick(); + return; + } + scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.trackClickRepeatFreq); + isFirst = false; + }, + cancelClick = function() + { + scrollTimeout && clearTimeout(scrollTimeout); + scrollTimeout = null; + $(document).unbind('mouseup.jsp', cancelClick); + }; + doScroll(); + $(document).bind('mouseup.jsp', cancelClick); + return false; + } + } + ); + } + } + + function removeClickOnTrack() + { + if (horizontalTrack) { + horizontalTrack.unbind('mousedown.jsp'); + } + if (verticalTrack) { + verticalTrack.unbind('mousedown.jsp'); + } + } + + function cancelDrag() + { + $('html').unbind('dragstart.jsp selectstart.jsp mousemove.jsp mouseup.jsp mouseleave.jsp'); + + if (verticalDrag) { + verticalDrag.removeClass('jspActive'); + } + if (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]).trigger('scroll'); + } + + 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 == dragMaxX, + 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]).trigger('scroll'); + } + + 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, eleWidth, eleTop = 0, eleLeft = 0, viewportTop, viewportLeft, maxVisibleEleTop, maxVisibleEleLeft, destY, destX; + + // 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(); + eleWidth= e.outerWidth(); + + container.scrollTop(0); + container.scrollLeft(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; + eleLeft += e.position().left; + 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); + } + + viewportLeft = contentPositionX(); + maxVisibleEleLeft = viewportLeft + paneWidth; + if (eleLeft < viewportLeft || stickToTop) { // element is to the left of viewport + destX = eleLeft - settings.horizontalGutter; + } else if (eleLeft + eleWidth > maxVisibleEleLeft) { // element is to the right viewport + destX = eleLeft - paneWidth + eleWidth + settings.horizontalGutter; + } + if (destX) { + scrollToX(destX, animate); + } + + } + + function contentPositionX() + { + return -pane.position().left; + } + + function contentPositionY() + { + return -pane.position().top; + } + + function isCloseToBottom() + { + var scrollableHeight = contentHeight - paneHeight; + return (scrollableHeight > 20) && (scrollableHeight - contentPositionY() < 10); + } + + function isCloseToRight() + { + var scrollableWidth = contentWidth - paneWidth; + return (scrollableWidth > 20) && (scrollableWidth - contentPositionX() < 10); + } + + function initMousewheel() + { + container.unbind(mwEvent).bind( + mwEvent, + function (event, delta, deltaX, deltaY) { + var dX = horizontalDragPosition, dY = verticalDragPosition; + jsp.scrollBy(deltaX * settings.mouseWheelSpeed, -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.find(':input,a').unbind('focus.jsp').bind( + 'focus.jsp', + function(e) + { + scrollToElement(e.target, false); + } + ); + } + + function removeFocusHandler() + { + pane.find(':input,a').unbind('focus.jsp'); + } + + function initKeyboardNav() + { + var keyDown, elementHasScrolled, validParents = []; + isScrollableH && validParents.push(horizontalBar[0]); + isScrollableV && validParents.push(verticalBar[0]); + + // IE also focuses elements that don't have tabindex set. + pane.focus( + function() + { + elem.focus(); + } + ); + + elem.attr('tabindex', 0) + .unbind('keydown.jsp keypress.jsp') + .bind( + 'keydown.jsp', + function(e) + { + if (e.target !== this && !(validParents.length && $(e.target).closest(validParents).length)){ + return; + } + var dX = horizontalDragPosition, dY = verticalDragPosition; + switch(e.keyCode) { + case 40: // down + case 38: // up + case 34: // page down + case 32: // space + case 33: // page up + case 39: // right + case 37: // left + keyDown = e.keyCode; + keyDownHandler(); + break; + case 35: // end + scrollToY(contentHeight - paneHeight); + keyDown = null; + break; + case 36: // home + scrollToY(0); + keyDown = null; + break; + } + + elementHasScrolled = e.keyCode == keyDown && dX != horizontalDragPosition || dY != verticalDragPosition; + return !elementHasScrolled; + } + ).bind( + 'keypress.jsp', // For FF/ OSX so that we can cancel the repeat key presses if the JSP scrolls... + function(e) + { + if (e.keyCode == keyDown) { + keyDownHandler(); + } + return !elementHasScrolled; + } + ); + + 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 keyDownHandler() + { + var dX = horizontalDragPosition, dY = verticalDragPosition; + switch(keyDown) { + case 40: // down + jsp.scrollByY(settings.keyboardSpeed, false); + break; + case 38: // up + jsp.scrollByY(-settings.keyboardSpeed, false); + break; + case 34: // page down + case 32: // space + jsp.scrollByY(paneHeight * settings.scrollPagePercent, false); + break; + case 33: // page up + jsp.scrollByY(-paneHeight * settings.scrollPagePercent, false); + break; + case 39: // right + jsp.scrollByX(settings.keyboardSpeed, false); + break; + case 37: // left + jsp.scrollByX(-settings.keyboardSpeed, false); + break; + } + + elementHasScrolled = dX != horizontalDragPosition || dY != verticalDragPosition; + return elementHasScrolled; + } + } + + function removeKeyboardNav() + { + elem.attr('tabindex', '-1') + .removeAttr('tabindex') + .unbind('keydown.jsp keypress.jsp'); + } + + function observeHash() + { + if (location.hash && location.hash.length > 1) { + var e, + retryInt, + hash = escape(location.hash.substr(1)) // hash must be escaped to prevent XSS + ; + try { + e = $('#' + hash + ', a[name="' + hash + '"]'); + } catch (err) { + return; + } + + if (e.length && pane.find(hash)) { + // 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(e, true); + $(document).scrollTop(container.position().top); + clearInterval(retryInt); + } + }, + 50 + ); + } else { + scrollToElement(e, true); + $(document).scrollTop(container.position().top); + } + } + } + } + + function hijackInternalLinks() + { + // only register the link handler once + if ($(document.body).data('jspHijack')) { + return; + } + + // remember that the handler was bound + $(document.body).data('jspHijack', true); + + // use live handler to also capture newly created links + $(document.body).delegate('a[href*=#]', 'click', function(event) { + // does the link point to the same page? + // this also takes care of cases with a -Tag or Links not starting with the hash # + // e.g. when the current url already is index.html + var href = this.href.substr(0, this.href.indexOf('#')), + locationHref = location.href, + hash, + element, + container, + jsp, + scrollTop, + elementTop; + if (location.href.indexOf('#') !== -1) { + locationHref = location.href.substr(0, location.href.indexOf('#')); + } + if (href !== locationHref) { + // the link points to another page + return; + } + + // check if jScrollPane should handle this click event + hash = escape(this.href.substr(this.href.indexOf('#') + 1)); + + // find the element on the page + element; + try { + element = $('#' + hash + ', a[name="' + hash + '"]'); + } catch (e) { + // hash is not a valid jQuery identifier + return; + } + + if (!element.length) { + // this link does not point to an element on this page + return; + } + + container = element.closest('.jspScrollable'); + jsp = container.data('jsp'); + + // jsp might be another jsp instance than the one, that bound this event + // remember: this event is only bound once for all instances. + jsp.scrollToElement(element, true); + + if (container[0].scrollIntoView) { + // also scroll to the top of the container (if it is not visible) + scrollTop = $(window).scrollTop(); + elementTop = element.offset().top; + if (elementTop < scrollTop || elementTop > scrollTop + $(window).height()) { + container[0].scrollIntoView(); + } + } + + // jsp handled this event, prevent the browser default (scrolling :P) + event.preventDefault(); + }); + } + + // Init touch on iPad, iPhone, iPod, Android + function initTouch() + { + var startX, + startY, + touchStartX, + touchStartY, + moved, + moving = false; + + container.unbind('touchstart.jsp touchmove.jsp touchend.jsp click.jsp-touchclick').bind( + 'touchstart.jsp', + function(e) + { + var touch = e.originalEvent.touches[0]; + startX = contentPositionX(); + startY = contentPositionY(); + touchStartX = touch.pageX; + touchStartY = touch.pageY; + moved = false; + moving = true; + } + ).bind( + 'touchmove.jsp', + function(ev) + { + if(!moving) { + return; + } + + var touchPos = ev.originalEvent.touches[0], + dX = horizontalDragPosition, dY = verticalDragPosition; + + jsp.scrollTo(startX + touchStartX - touchPos.pageX, startY + touchStartY - touchPos.pageY); + + moved = moved || Math.abs(touchStartX - touchPos.pageX) > 5 || Math.abs(touchStartY - touchPos.pageY) > 5; + + // return true if there was no movement so rest of screen can scroll + return dX == horizontalDragPosition && dY == verticalDragPosition; + } + ).bind( + 'touchend.jsp', + function(e) + { + moving = false; + /*if(moved) { + return false; + }*/ + } + ).bind( + 'click.jsp-touchclick', + function(e) + { + if(moved) { + moved = false; + return false; + } + } + ); + } + + function destroy(){ + var currentY = contentPositionY(), + currentX = contentPositionX(); + elem.removeClass('jspScrollable').unbind('.jsp'); + elem.replaceWith(originalElement.append(pane.children())); + originalElement.scrollTop(currentY); + originalElement.scrollLeft(currentX); + + // clear reinitialize timer if active + if (reinitialiseInterval) { + clearInterval(reinitialiseInterval); + } + } + + // 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({}, settings, s); + 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 to the specified percentage of its maximum horizontal scroll position. animate + // is optional and if not passed then the value of animateScroll from the settings object this + // jScrollPane was initialised with is used. + scrollToPercentX: function(destPercentX, animate) + { + scrollToX(destPercentX * (contentWidth - paneWidth), animate); + }, + // Scrolls the pane to the specified percentage of its maximum vertical scroll position. animate + // is optional and if not passed then the value of animateScroll from the settings object this + // jScrollPane was initialised with is used. + scrollToPercentY: function(destPercentY, animate) + { + scrollToY(destPercentY * (contentHeight - paneHeight), 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() + Math[deltaX<0 ? 'floor' : 'ceil'](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() + Math[deltaY<0 ? 'floor' : 'ceil'](deltaY), + percentScrolled = destY / (contentHeight - paneHeight); + positionDragY(percentScrolled * dragMaxY, animate); + }, + // Positions the horizontal drag at the specified x position (and updates the viewport to reflect + // this). animate is optional and if not passed then the value of animateScroll from the settings + // object this jScrollPane was initialised with is used. + positionDragX: function(x, animate) + { + positionDragX(x, animate); + }, + // Positions the vertical drag at the specified y position (and updates the viewport to reflect + // this). animate is optional and if not passed then the value of animateScroll from the settings + // object this jScrollPane was initialised with is used. + positionDragY: function(y, animate) + { + positionDragY(y, 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, + 'easing' : 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 the width of the content within the scroll pane. + getContentWidth: function() + { + return contentWidth; + }, + // Returns the height of the content within the scroll pane. + getContentHeight: function() + { + return contentHeight; + }, + // Returns the horizontal position of the viewport within the pane content. + getPercentScrolledX: function() + { + return contentPositionX() / (contentWidth - paneWidth); + }, + // Returns the vertical position of the viewport within the pane content. + getPercentScrolledY: function() + { + return contentPositionY() / (contentHeight - paneHeight); + }, + // 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: $.noop, + // Removes the jScrollPane and returns the page to the state it was in before jScrollPane was + // initialised. + destroy: function() + { + destroy(); + } + } + ); + + initialise(s); + } + + // Pluginifying code... + settings = $.extend({}, $.fn.jScrollPane.defaults, settings); + + // Apply default speed + $.each(['mouseWheelSpeed', 'arrowButtonSpeed', 'trackClickSpeed', 'keyboardSpeed'], function() { + settings[this] = settings[this] || settings.speed; + }); + + return this.each( + function() + { + var elem = $(this), jspApi = elem.data('jsp'); + if (jspApi) { + jspApi.reinitialise(settings); + } else { + $("script",elem).filter('[type="text/javascript"],:not([type])').remove(); + jspApi = new JScrollPane(elem, settings); + elem.data('jsp', jspApi); + } + } + ); + }; + + $.fn.jScrollPane.defaults = { + showArrows : false, + maintainPosition : true, + stickToBottom : false, + stickToRight : false, + clickOnTrack : true, + autoReinitialise : false, + autoReinitialiseDelay : 500, + verticalDragMinHeight : 0, + verticalDragMaxHeight : 99999, + horizontalDragMinWidth : 0, + horizontalDragMaxWidth : 99999, + contentWidth : undefined, + animateScroll : false, + animateDuration : 300, + animateEase : 'linear', + hijackInternalLinks : false, + verticalGutter : 4, + horizontalGutter : 4, + mouseWheelSpeed : 0, + arrowButtonSpeed : 0, + arrowRepeatFreq : 50, + arrowScrollOnHover : false, + trackClickSpeed : 0, + trackClickRepeatFreq : 70, + verticalArrowPositions : 'split', + horizontalArrowPositions : 'split', + enableKeyboardNavigation : true, + hideFocus : false, + keyboardSpeed : 0, + initialDelay : 300, // Delay before starting repeating + speed : 30, // Default speed when others falsey + scrollPagePercent : .8 // Percent of visible area scrolled when pageUp/Down or track area pressed + }; + +})(jQuery,this); + diff --git a/ajax/libs/jScrollPane/2.0.0beta12/jquery.jscrollpane.min.js b/ajax/libs/jScrollPane/2.0.13/script/jquery.jscrollpane.min.js similarity index 99% rename from ajax/libs/jScrollPane/2.0.0beta12/jquery.jscrollpane.min.js rename to ajax/libs/jScrollPane/2.0.13/script/jquery.jscrollpane.min.js index 09539b7503381b..52470da9f753f2 100644 --- a/ajax/libs/jScrollPane/2.0.0beta12/jquery.jscrollpane.min.js +++ b/ajax/libs/jScrollPane/2.0.13/script/jquery.jscrollpane.min.js @@ -1,11 +1,11 @@ -/* - * jScrollPane - v2.0.0beta12 - 2012-07-24 +/*! + * jScrollPane - v2.0.13 - 2013-05-01 * http://jscrollpane.kelvinluck.com/ * * Copyright (c) 2010 Kelvin Luck - * Dual licensed under the MIT and GPL licenses. + * Dual licensed under the MIT or GPL licenses. */ (function(b,a,c){b.fn.jScrollPane=function(e){function d(D,O){var ay,Q=this,Y,aj,v,al,T,Z,y,q,az,aE,au,i,I,h,j,aa,U,ap,X,t,A,aq,af,am,G,l,at,ax,x,av,aH,f,L,ai=true,P=true,aG=false,k=false,ao=D.clone(false,false).empty(),ac=b.fn.mwheelIntent?"mwheelIntent.jsp":"mousewheel.jsp";aH=D.css("paddingTop")+" "+D.css("paddingRight")+" "+D.css("paddingBottom")+" "+D.css("paddingLeft");f=(parseInt(D.css("paddingLeft"),10)||0)+(parseInt(D.css("paddingRight"),10)||0);function ar(aQ){var aL,aN,aM,aJ,aI,aP,aO=false,aK=false;ay=aQ;if(Y===c){aI=D.scrollTop();aP=D.scrollLeft();D.css({overflow:"hidden",padding:0});aj=D.innerWidth()+f;v=D.innerHeight();D.width(aj);Y=b('
').css("padding",aH).append(D.children());al=b('
').css({width:aj+"px",height:v+"px"}).append(Y).appendTo(D)}else{D.css("width","");aO=ay.stickToBottom&&K();aK=ay.stickToRight&&B();aJ=D.innerWidth()+f!=aj||D.outerHeight()!=v;if(aJ){aj=D.innerWidth()+f;v=D.innerHeight();al.css({width:aj+"px",height:v+"px"})}if(!aJ&&L==T&&Y.outerHeight()==Z){D.width(aj);return}L=T;Y.css("width","");D.width(aj);al.find(">.jspVerticalBar,>.jspHorizontalBar").remove().end()}Y.css("overflow","auto");if(aQ.contentWidth){T=aQ.contentWidth}else{T=Y[0].scrollWidth}Z=Y[0].scrollHeight;Y.css("overflow","");y=T/aj;q=Z/v;az=q>1;aE=y>1;if(!(aE||az)){D.removeClass("jspScrollable");Y.css({top:0,width:al.width()-f});n();E();R();w()}else{D.addClass("jspScrollable");aL=ay.maintainPosition&&(I||aa);if(aL){aN=aC();aM=aA()}aF();z();F();if(aL){N(aK?(T-aj):aN,false);M(aO?(Z-v):aM,false)}J();ag();an();if(ay.enableKeyboardNavigation){S()}if(ay.clickOnTrack){p()}C();if(ay.hijackInternalLinks){m()}}if(ay.autoReinitialise&&!av){av=setInterval(function(){ar(ay)},ay.autoReinitialiseDelay)}else{if(!ay.autoReinitialise&&av){clearInterval(av)}}aI&&D.scrollTop(0)&&M(aI,false);aP&&D.scrollLeft(0)&&N(aP,false);D.trigger("jsp-initialised",[aE||az])}function aF(){if(az){al.append(b('
').append(b('
'),b('
').append(b('
').append(b('
'),b('
'))),b('
')));U=al.find(">.jspVerticalBar");ap=U.find(">.jspTrack");au=ap.find(">.jspDrag");if(ay.showArrows){aq=b('').bind("mousedown.jsp",aD(0,-1)).bind("click.jsp",aB);af=b('').bind("mousedown.jsp",aD(0,1)).bind("click.jsp",aB);if(ay.arrowScrollOnHover){aq.bind("mouseover.jsp",aD(0,-1,aq));af.bind("mouseover.jsp",aD(0,1,af))}ak(ap,ay.verticalArrowPositions,aq,af)}t=v;al.find(">.jspVerticalBar>.jspCap:visible,>.jspVerticalBar>.jspArrow").each(function(){t-=b(this).outerHeight()});au.hover(function(){au.addClass("jspHover")},function(){au.removeClass("jspHover")}).bind("mousedown.jsp",function(aI){b("html").bind("dragstart.jsp selectstart.jsp",aB);au.addClass("jspActive");var s=aI.pageY-au.position().top;b("html").bind("mousemove.jsp",function(aJ){V(aJ.pageY-s,false)}).bind("mouseup.jsp mouseleave.jsp",aw);return false});o()}}function o(){ap.height(t+"px");I=0;X=ay.verticalGutter+ap.outerWidth();Y.width(aj-X-f);try{if(U.position().left===0){Y.css("margin-left",X+"px")}}catch(s){}}function z(){if(aE){al.append(b('
').append(b('
'),b('
').append(b('
').append(b('
'),b('
'))),b('
')));am=al.find(">.jspHorizontalBar");G=am.find(">.jspTrack");h=G.find(">.jspDrag");if(ay.showArrows){ax=b('').bind("mousedown.jsp",aD(-1,0)).bind("click.jsp",aB);x=b('').bind("mousedown.jsp",aD(1,0)).bind("click.jsp",aB); if(ay.arrowScrollOnHover){ax.bind("mouseover.jsp",aD(-1,0,ax));x.bind("mouseover.jsp",aD(1,0,x))}ak(G,ay.horizontalArrowPositions,ax,x)}h.hover(function(){h.addClass("jspHover")},function(){h.removeClass("jspHover")}).bind("mousedown.jsp",function(aI){b("html").bind("dragstart.jsp selectstart.jsp",aB);h.addClass("jspActive");var s=aI.pageX-h.position().left;b("html").bind("mousemove.jsp",function(aJ){W(aJ.pageX-s,false)}).bind("mouseup.jsp mouseleave.jsp",aw);return false});l=al.innerWidth();ah()}}function ah(){al.find(">.jspHorizontalBar>.jspCap:visible,>.jspHorizontalBar>.jspArrow").each(function(){l-=b(this).outerWidth()});G.width(l+"px");aa=0}function F(){if(aE&&az){var aI=G.outerHeight(),s=ap.outerWidth();t-=aI;b(am).find(">.jspCap:visible,>.jspArrow").each(function(){l+=b(this).outerWidth()});l-=s;v-=s;aj-=aI;G.parent().append(b('
').css("width",aI+"px"));o();ah()}if(aE){Y.width((al.outerWidth()-f)+"px")}Z=Y.outerHeight();q=Z/v;if(aE){at=Math.ceil(1/y*l);if(at>ay.horizontalDragMaxWidth){at=ay.horizontalDragMaxWidth}else{if(atay.verticalDragMaxHeight){A=ay.verticalDragMaxHeight}else{if(AaS){Q.scrollByY(-aP)}else{V(aS)}}else{if(aM>0){if(I+aQaS){Q.scrollByX(-aP)}else{W(aS)}}else{if(aM>0){if(aa+aQi){s=i}}if(aI===c){aI=ay.animateScroll}if(aI){Q.animate(au,"top",s,ad)}else{au.css("top",s);ad(s)}}function ad(aI){if(aI===c){aI=au.position().top}al.scrollTop(0);I=aI;var aL=I===0,aJ=I==i,aK=aI/i,s=-aK*(Z-v);if(ai!=aL||aG!=aJ){ai=aL;aG=aJ;D.trigger("jsp-arrow-change",[ai,aG,P,k])}u(aL,aJ);Y.css("top",s);D.trigger("jsp-scroll-y",[-s,aL,aJ]).trigger("scroll")}function W(aI,s){if(!aE){return}if(aI<0){aI=0}else{if(aI>j){aI=j}}if(s===c){s=ay.animateScroll}if(s){Q.animate(h,"left",aI,ae) }else{h.css("left",aI);ae(aI)}}function ae(aI){if(aI===c){aI=h.position().left}al.scrollTop(0);aa=aI;var aL=aa===0,aK=aa==j,aJ=aI/j,s=-aJ*(T-aj);if(P!=aL||k!=aK){P=aL;k=aK;D.trigger("jsp-arrow-change",[ai,aG,P,k])}r(aL,aK);Y.css("left",s);D.trigger("jsp-scroll-x",[-s,aL,aK]).trigger("scroll")}function u(aI,s){if(ay.showArrows){aq[aI?"addClass":"removeClass"]("jspDisabled");af[s?"addClass":"removeClass"]("jspDisabled")}}function r(aI,s){if(ay.showArrows){ax[aI?"addClass":"removeClass"]("jspDisabled");x[s?"addClass":"removeClass"]("jspDisabled")}}function M(s,aI){var aJ=s/(Z-v);V(aJ*i,aI)}function N(aI,s){var aJ=aI/(T-aj);W(aJ*j,s)}function ab(aV,aQ,aJ){var aN,aK,aL,s=0,aU=0,aI,aP,aO,aS,aR,aT;try{aN=b(aV)}catch(aM){return}aK=aN.outerHeight();aL=aN.outerWidth();al.scrollTop(0);al.scrollLeft(0);while(!aN.is(".jspPane")){s+=aN.position().top;aU+=aN.position().left;aN=aN.offsetParent();if(/^body|html$/i.test(aN[0].nodeName)){return}}aI=aA();aO=aI+v;if(saO){aR=s-v+aK+ay.verticalGutter}}if(aR){M(aR,aJ)}aP=aC();aS=aP+aj;if(aUaS){aT=aU-aj+aL+ay.horizontalGutter}}if(aT){N(aT,aJ)}}function aC(){return -Y.position().left}function aA(){return -Y.position().top}function K(){var s=Z-v;return(s>20)&&(s-aA()<10)}function B(){var s=T-aj;return(s>20)&&(s-aC()<10)}function ag(){al.unbind(ac).bind(ac,function(aL,aM,aK,aI){var aJ=aa,s=I;Q.scrollBy(aK*ay.mouseWheelSpeed,-aI*ay.mouseWheelSpeed,false);return aJ==aa&&s==I})}function n(){al.unbind(ac)}function aB(){return false}function J(){Y.find(":input,a").unbind("focus.jsp").bind("focus.jsp",function(s){ab(s.target,false)})}function E(){Y.find(":input,a").unbind("focus.jsp")}function S(){var s,aI,aK=[];aE&&aK.push(am[0]);az&&aK.push(U[0]);Y.focus(function(){D.focus()});D.attr("tabindex",0).unbind("keydown.jsp keypress.jsp").bind("keydown.jsp",function(aN){if(aN.target!==this&&!(aK.length&&b(aN.target).closest(aK).length)){return}var aM=aa,aL=I;switch(aN.keyCode){case 40:case 38:case 34:case 32:case 33:case 39:case 37:s=aN.keyCode;aJ();break;case 35:M(Z-v);s=null;break;case 36:M(0);s=null;break}aI=aN.keyCode==s&&aM!=aa||aL!=I;return !aI}).bind("keypress.jsp",function(aL){if(aL.keyCode==s){aJ()}return !aI});if(ay.hideFocus){D.css("outline","none");if("hideFocus" in al[0]){D.attr("hideFocus",true)}}else{D.css("outline","");if("hideFocus" in al[0]){D.attr("hideFocus",false)}}function aJ(){var aM=aa,aL=I;switch(s){case 40:Q.scrollByY(ay.keyboardSpeed,false);break;case 38:Q.scrollByY(-ay.keyboardSpeed,false);break;case 34:case 32:Q.scrollByY(v*ay.scrollPagePercent,false);break;case 33:Q.scrollByY(-v*ay.scrollPagePercent,false);break;case 39:Q.scrollByX(ay.keyboardSpeed,false);break;case 37:Q.scrollByX(-ay.keyboardSpeed,false);break}aI=aM!=aa||aL!=I;return aI}}function R(){D.attr("tabindex","-1").removeAttr("tabindex").unbind("keydown.jsp keypress.jsp")}function C(){if(location.hash&&location.hash.length>1){var aK,aI,aJ=escape(location.hash.substr(1));try{aK=b("#"+aJ+', a[name="'+aJ+'"]')}catch(s){return}if(aK.length&&Y.find(aJ)){if(al.scrollTop()===0){aI=setInterval(function(){if(al.scrollTop()>0){ab(aK,true);b(document).scrollTop(al.position().top);clearInterval(aI)}},50)}else{ab(aK,true);b(document).scrollTop(al.position().top)}}}}function m(){if(b(document.body).data("jspHijack")){return}b(document.body).data("jspHijack",true);b(document.body).delegate("a[href*=#]","click",function(s){var aI=this.href.substr(0,this.href.indexOf("#")),aK=location.href,aO,aP,aJ,aM,aL,aN;if(location.href.indexOf("#")!==-1){aK=location.href.substr(0,location.href.indexOf("#"))}if(aI!==aK){return}aO=escape(this.href.substr(this.href.indexOf("#")+1));aP;try{aP=b("#"+aO+', a[name="'+aO+'"]')}catch(aQ){return}if(!aP.length){return}aJ=aP.closest(".jspScrollable");aM=aJ.data("jsp");aM.scrollToElement(aP,true);if(aJ[0].scrollIntoView){aL=b(a).scrollTop();aN=aP.offset().top;if(aNaL+b(a).height()){aJ[0].scrollIntoView()}}s.preventDefault() -})}function an(){var aJ,aI,aL,aK,aM,s=false;al.unbind("touchstart.jsp touchmove.jsp touchend.jsp click.jsp-touchclick").bind("touchstart.jsp",function(aN){var aO=aN.originalEvent.touches[0];aJ=aC();aI=aA();aL=aO.pageX;aK=aO.pageY;aM=false;s=true}).bind("touchmove.jsp",function(aQ){if(!s){return}var aP=aQ.originalEvent.touches[0],aO=aa,aN=I;Q.scrollTo(aJ+aL-aP.pageX,aI+aK-aP.pageY);aM=aM||Math.abs(aL-aP.pageX)>5||Math.abs(aK-aP.pageY)>5;return aO==aa&&aN==I}).bind("touchend.jsp",function(aN){s=false}).bind("click.jsp-touchclick",function(aN){if(aM){aM=false;return false}})}function g(){var s=aA(),aI=aC();D.removeClass("jspScrollable").unbind(".jsp");D.replaceWith(ao.append(Y.children()));ao.scrollTop(s);ao.scrollLeft(aI);if(av){clearInterval(av)}}b.extend(Q,{reinitialise:function(aI){aI=b.extend({},ay,aI);ar(aI)},scrollToElement:function(aJ,aI,s){ab(aJ,aI,s)},scrollTo:function(aJ,s,aI){N(aJ,aI);M(s,aI)},scrollToX:function(aI,s){N(aI,s)},scrollToY:function(s,aI){M(s,aI)},scrollToPercentX:function(aI,s){N(aI*(T-aj),s)},scrollToPercentY:function(aI,s){M(aI*(Z-v),s)},scrollBy:function(aI,s,aJ){Q.scrollByX(aI,aJ);Q.scrollByY(s,aJ)},scrollByX:function(s,aJ){var aI=aC()+Math[s<0?"floor":"ceil"](s),aK=aI/(T-aj);W(aK*j,aJ)},scrollByY:function(s,aJ){var aI=aA()+Math[s<0?"floor":"ceil"](s),aK=aI/(Z-v);V(aK*i,aJ)},positionDragX:function(s,aI){W(s,aI)},positionDragY:function(aI,s){V(aI,s)},animate:function(aI,aL,s,aK){var aJ={};aJ[aL]=s;aI.animate(aJ,{duration:ay.animateDuration,easing:ay.animateEase,queue:false,step:aK})},getContentPositionX:function(){return aC()},getContentPositionY:function(){return aA()},getContentWidth:function(){return T},getContentHeight:function(){return Z},getPercentScrolledX:function(){return aC()/(T-aj)},getPercentScrolledY:function(){return aA()/(Z-v)},getIsScrollableH:function(){return aE},getIsScrollableV:function(){return az},getContentPane:function(){return Y},scrollToBottom:function(s){V(i,s)},hijackInternalLinks:b.noop,destroy:function(){g()}});ar(O)}e=b.extend({},b.fn.jScrollPane.defaults,e);b.each(["mouseWheelSpeed","arrowButtonSpeed","trackClickSpeed","keyboardSpeed"],function(){e[this]=e[this]||e.speed});return this.each(function(){var f=b(this),g=f.data("jsp");if(g){g.reinitialise(e)}else{b("script",f).filter('[type="text/javascript"],:not([type])').remove();g=new d(f,e);f.data("jsp",g)}})};b.fn.jScrollPane.defaults={showArrows:false,maintainPosition:true,stickToBottom:false,stickToRight:false,clickOnTrack:true,autoReinitialise:false,autoReinitialiseDelay:500,verticalDragMinHeight:0,verticalDragMaxHeight:99999,horizontalDragMinWidth:0,horizontalDragMaxWidth:99999,contentWidth:c,animateScroll:false,animateDuration:300,animateEase:"linear",hijackInternalLinks:false,verticalGutter:4,horizontalGutter:4,mouseWheelSpeed:0,arrowButtonSpeed:0,arrowRepeatFreq:50,arrowScrollOnHover:false,trackClickSpeed:0,trackClickRepeatFreq:70,verticalArrowPositions:"split",horizontalArrowPositions:"split",enableKeyboardNavigation:true,hideFocus:false,keyboardSpeed:0,initialDelay:300,speed:30,scrollPagePercent:0.8}})(jQuery,this); +})}function an(){var aJ,aI,aL,aK,aM,s=false;al.unbind("touchstart.jsp touchmove.jsp touchend.jsp click.jsp-touchclick").bind("touchstart.jsp",function(aN){var aO=aN.originalEvent.touches[0];aJ=aC();aI=aA();aL=aO.pageX;aK=aO.pageY;aM=false;s=true}).bind("touchmove.jsp",function(aQ){if(!s){return}var aP=aQ.originalEvent.touches[0],aO=aa,aN=I;Q.scrollTo(aJ+aL-aP.pageX,aI+aK-aP.pageY);aM=aM||Math.abs(aL-aP.pageX)>5||Math.abs(aK-aP.pageY)>5;return aO==aa&&aN==I}).bind("touchend.jsp",function(aN){s=false}).bind("click.jsp-touchclick",function(aN){if(aM){aM=false;return false}})}function g(){var s=aA(),aI=aC();D.removeClass("jspScrollable").unbind(".jsp");D.replaceWith(ao.append(Y.children()));ao.scrollTop(s);ao.scrollLeft(aI);if(av){clearInterval(av)}}b.extend(Q,{reinitialise:function(aI){aI=b.extend({},ay,aI);ar(aI)},scrollToElement:function(aJ,aI,s){ab(aJ,aI,s)},scrollTo:function(aJ,s,aI){N(aJ,aI);M(s,aI)},scrollToX:function(aI,s){N(aI,s)},scrollToY:function(s,aI){M(s,aI)},scrollToPercentX:function(aI,s){N(aI*(T-aj),s)},scrollToPercentY:function(aI,s){M(aI*(Z-v),s)},scrollBy:function(aI,s,aJ){Q.scrollByX(aI,aJ);Q.scrollByY(s,aJ)},scrollByX:function(s,aJ){var aI=aC()+Math[s<0?"floor":"ceil"](s),aK=aI/(T-aj);W(aK*j,aJ)},scrollByY:function(s,aJ){var aI=aA()+Math[s<0?"floor":"ceil"](s),aK=aI/(Z-v);V(aK*i,aJ)},positionDragX:function(s,aI){W(s,aI)},positionDragY:function(aI,s){V(aI,s)},animate:function(aI,aL,s,aK){var aJ={};aJ[aL]=s;aI.animate(aJ,{duration:ay.animateDuration,easing:ay.animateEase,queue:false,step:aK})},getContentPositionX:function(){return aC()},getContentPositionY:function(){return aA()},getContentWidth:function(){return T},getContentHeight:function(){return Z},getPercentScrolledX:function(){return aC()/(T-aj)},getPercentScrolledY:function(){return aA()/(Z-v)},getIsScrollableH:function(){return aE},getIsScrollableV:function(){return az},getContentPane:function(){return Y},scrollToBottom:function(s){V(i,s)},hijackInternalLinks:b.noop,destroy:function(){g()}});ar(O)}e=b.extend({},b.fn.jScrollPane.defaults,e);b.each(["mouseWheelSpeed","arrowButtonSpeed","trackClickSpeed","keyboardSpeed"],function(){e[this]=e[this]||e.speed});return this.each(function(){var f=b(this),g=f.data("jsp");if(g){g.reinitialise(e)}else{b("script",f).filter('[type="text/javascript"],:not([type])').remove();g=new d(f,e);f.data("jsp",g)}})};b.fn.jScrollPane.defaults={showArrows:false,maintainPosition:true,stickToBottom:false,stickToRight:false,clickOnTrack:true,autoReinitialise:false,autoReinitialiseDelay:500,verticalDragMinHeight:0,verticalDragMaxHeight:99999,horizontalDragMinWidth:0,horizontalDragMaxWidth:99999,contentWidth:c,animateScroll:false,animateDuration:300,animateEase:"linear",hijackInternalLinks:false,verticalGutter:4,horizontalGutter:4,mouseWheelSpeed:0,arrowButtonSpeed:0,arrowRepeatFreq:50,arrowScrollOnHover:false,trackClickSpeed:0,trackClickRepeatFreq:70,verticalArrowPositions:"split",horizontalArrowPositions:"split",enableKeyboardNavigation:true,hideFocus:false,keyboardSpeed:0,initialDelay:300,speed:30,scrollPagePercent:0.8}})(jQuery,this); \ No newline at end of file diff --git a/ajax/libs/jScrollPane/2.0.13/style/jquery.jscrollpane.css b/ajax/libs/jScrollPane/2.0.13/style/jquery.jscrollpane.css new file mode 100644 index 00000000000000..a051caed0a41b7 --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.13/style/jquery.jscrollpane.css @@ -0,0 +1,120 @@ +/* + * CSS Styles that are needed by jScrollPane for it to operate correctly. + * + * Include this stylesheet in your site or copy and paste the styles below into your stylesheet - jScrollPane + * may not operate correctly without them. + */ + +.jspContainer +{ + overflow: hidden; + position: relative; +} + +.jspPane +{ + position: absolute; +} + +.jspVerticalBar +{ + position: absolute; + top: 0; + right: 0; + width: 16px; + height: 100%; + background: red; +} + +.jspHorizontalBar +{ + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 16px; + background: red; +} + +.jspVerticalBar *, +.jspHorizontalBar * +{ + margin: 0; + padding: 0; +} + +.jspCap +{ + display: none; +} + +.jspHorizontalBar .jspCap +{ + float: left; +} + +.jspTrack +{ + background: #dde; + position: relative; +} + +.jspDrag +{ + background: #bbd; + position: relative; + top: 0; + left: 0; + cursor: pointer; +} + +.jspHorizontalBar .jspTrack, +.jspHorizontalBar .jspDrag +{ + float: left; + height: 100%; +} + +.jspArrow +{ + background: #50506d; + text-indent: -20000px; + display: block; + cursor: pointer; +} + +.jspArrow.jspDisabled +{ + cursor: default; + background: #80808d; +} + +.jspVerticalBar .jspArrow +{ + height: 16px; +} + +.jspHorizontalBar .jspArrow +{ + width: 16px; + float: left; + height: 100%; +} + +.jspVerticalBar .jspArrow:focus +{ + outline: none; +} + +.jspCorner +{ + background: #eeeef4; + float: left; + height: 100%; +} + +/* Yuk! CSS Hack for IE6 3 pixel bug :( */ +* html .jspCorner +{ + margin: 0 -3px 0 0; +} \ No newline at end of file diff --git a/ajax/libs/jScrollPane/2.0.13/style/jquery.jscrollpane.min.css b/ajax/libs/jScrollPane/2.0.13/style/jquery.jscrollpane.min.css new file mode 100644 index 00000000000000..41eaed48ad7829 --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.13/style/jquery.jscrollpane.min.css @@ -0,0 +1 @@ +.jspContainer{overflow:hidden;position:relative}.jspPane{position:absolute}.jspVerticalBar{position:absolute;top:0;right:0;width:16px;height:100%;background:red}.jspHorizontalBar{position:absolute;bottom:0;left:0;width:100%;height:16px;background:red}.jspVerticalBar *,.jspHorizontalBar *{margin:0;padding:0}.jspCap{display:none}.jspHorizontalBar .jspCap{float:left}.jspTrack{background:#dde;position:relative}.jspDrag{background:#bbd;position:relative;top:0;left:0;cursor:pointer}.jspHorizontalBar .jspTrack,.jspHorizontalBar .jspDrag{float:left;height:100%}.jspArrow{background:#50506d;text-indent:-20000px;display:block;cursor:pointer}.jspArrow.jspDisabled{cursor:default;background:#80808d}.jspVerticalBar .jspArrow{height:16px}.jspHorizontalBar .jspArrow{width:16px;float:left;height:100%}.jspVerticalBar .jspArrow:focus{outline:0}.jspCorner{background:#eeeef4;float:left;height:100%}* html .jspCorner{margin:0 -3px 0 0} \ No newline at end of file diff --git a/ajax/libs/jScrollPane/2.0.14/jquery.jscrollpane.js b/ajax/libs/jScrollPane/2.0.14/script/jquery.jscrollpane.js similarity index 100% rename from ajax/libs/jScrollPane/2.0.14/jquery.jscrollpane.js rename to ajax/libs/jScrollPane/2.0.14/script/jquery.jscrollpane.js diff --git a/ajax/libs/jScrollPane/2.0.14/jquery.jscrollpane.min.js b/ajax/libs/jScrollPane/2.0.14/script/jquery.jscrollpane.min.js similarity index 100% rename from ajax/libs/jScrollPane/2.0.14/jquery.jscrollpane.min.js rename to ajax/libs/jScrollPane/2.0.14/script/jquery.jscrollpane.min.js diff --git a/ajax/libs/jScrollPane/2.0.14/style/jquery.jscrollpane.css b/ajax/libs/jScrollPane/2.0.14/style/jquery.jscrollpane.css new file mode 100644 index 00000000000000..a051caed0a41b7 --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.14/style/jquery.jscrollpane.css @@ -0,0 +1,120 @@ +/* + * CSS Styles that are needed by jScrollPane for it to operate correctly. + * + * Include this stylesheet in your site or copy and paste the styles below into your stylesheet - jScrollPane + * may not operate correctly without them. + */ + +.jspContainer +{ + overflow: hidden; + position: relative; +} + +.jspPane +{ + position: absolute; +} + +.jspVerticalBar +{ + position: absolute; + top: 0; + right: 0; + width: 16px; + height: 100%; + background: red; +} + +.jspHorizontalBar +{ + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 16px; + background: red; +} + +.jspVerticalBar *, +.jspHorizontalBar * +{ + margin: 0; + padding: 0; +} + +.jspCap +{ + display: none; +} + +.jspHorizontalBar .jspCap +{ + float: left; +} + +.jspTrack +{ + background: #dde; + position: relative; +} + +.jspDrag +{ + background: #bbd; + position: relative; + top: 0; + left: 0; + cursor: pointer; +} + +.jspHorizontalBar .jspTrack, +.jspHorizontalBar .jspDrag +{ + float: left; + height: 100%; +} + +.jspArrow +{ + background: #50506d; + text-indent: -20000px; + display: block; + cursor: pointer; +} + +.jspArrow.jspDisabled +{ + cursor: default; + background: #80808d; +} + +.jspVerticalBar .jspArrow +{ + height: 16px; +} + +.jspHorizontalBar .jspArrow +{ + width: 16px; + float: left; + height: 100%; +} + +.jspVerticalBar .jspArrow:focus +{ + outline: none; +} + +.jspCorner +{ + background: #eeeef4; + float: left; + height: 100%; +} + +/* Yuk! CSS Hack for IE6 3 pixel bug :( */ +* html .jspCorner +{ + margin: 0 -3px 0 0; +} \ No newline at end of file diff --git a/ajax/libs/jScrollPane/2.0.14/style/jquery.jscrollpane.min.css b/ajax/libs/jScrollPane/2.0.14/style/jquery.jscrollpane.min.css new file mode 100644 index 00000000000000..41eaed48ad7829 --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.14/style/jquery.jscrollpane.min.css @@ -0,0 +1 @@ +.jspContainer{overflow:hidden;position:relative}.jspPane{position:absolute}.jspVerticalBar{position:absolute;top:0;right:0;width:16px;height:100%;background:red}.jspHorizontalBar{position:absolute;bottom:0;left:0;width:100%;height:16px;background:red}.jspVerticalBar *,.jspHorizontalBar *{margin:0;padding:0}.jspCap{display:none}.jspHorizontalBar .jspCap{float:left}.jspTrack{background:#dde;position:relative}.jspDrag{background:#bbd;position:relative;top:0;left:0;cursor:pointer}.jspHorizontalBar .jspTrack,.jspHorizontalBar .jspDrag{float:left;height:100%}.jspArrow{background:#50506d;text-indent:-20000px;display:block;cursor:pointer}.jspArrow.jspDisabled{cursor:default;background:#80808d}.jspVerticalBar .jspArrow{height:16px}.jspHorizontalBar .jspArrow{width:16px;float:left;height:100%}.jspVerticalBar .jspArrow:focus{outline:0}.jspCorner{background:#eeeef4;float:left;height:100%}* html .jspCorner{margin:0 -3px 0 0} \ No newline at end of file diff --git a/ajax/libs/jScrollPane/2.0.20/script/jquery.jscrollpane.js b/ajax/libs/jScrollPane/2.0.20/script/jquery.jscrollpane.js new file mode 100644 index 00000000000000..c0243744ceb90d --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.20/script/jquery.jscrollpane.js @@ -0,0 +1,1467 @@ +/*! + * jScrollPane - v2.0.20 - 2014-10-23 + * http://jscrollpane.kelvinluck.com/ + * + * Copyright (c) 2014 Kelvin Luck + * Dual licensed under the MIT or GPL licenses. + */ + +// Script: jScrollPane - cross browser customisable scrollbars +// +// *Version: 2.0.20, Last updated: 2014-10-23* +// +// 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) 2014 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 - tested in 1.4.2+ - reported to work in 1.3.x +// Browsers Tested - Firefox 3.6.8, Safari 5, Opera 10.6, Chrome 5.0, IE 6, 7, 8 +// +// About: Release History +// +// 2.0.20 - (2014-10-23) Adds AMD support (thanks @carlosrberto) and support for overflow-x/overflow-y (thanks @darimpulso) +// 2.0.19 - (2013-11-16) Changes for more reliable scroll amount with latest mousewheel plugin (thanks @brandonaaron) +// 2.0.18 - (2013-10-23) Fix for issue with gutters and scrollToElement (thanks @Dubiy) +// 2.0.17 - (2013-08-17) Working correctly when box-sizing is set to border-box (thanks @pieht) +// 2.0.16 - (2013-07-30) Resetting left position when scroll is removed. Fixes #189 +// 2.0.15 - (2013-07-29) Fixed issue with scrollToElement where the destX and destY are undefined. +// 2.0.14 - (2013-05-01) Updated to most recent mouse wheel plugin (see #106) and related changes for sensible scroll speed +// 2.0.13 - (2013-05-01) Switched to semver compatible version name +// 2.0.0beta12 - (2012-09-27) fix for jQuery 1.8+ +// 2.0.0beta11 - (2012-05-14) +// 2.0.0beta10 - (2011-04-17) cleaner required size calculation, improved keyboard support, stickToBottom/Left, other small fixes +// 2.0.0beta9 - (2011-01-31) new API methods, bug fixes and correct keyboard support for FF/OSX +// 2.0.0beta8 - (2011-01-29) touchscreen support, improved keyboard support +// 2.0.0beta7 - (2011-01-23) scroll speed consistent (thanks Aivo Paas) +// 2.0.0beta6 - (2010-12-07) scrollToElement horizontal support +// 2.0.0beta5 - (2010-10-18) jQuery 1.4.3 support, various bug fixes +// 2.0.0beta4 - (2010-09-17) clickOnTrack support, bug fixes +// 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 (plugin, window) { + var factory = function($){ + return plugin($, window); + } + if ( typeof define === 'function' && define.amd ) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof exports === 'object') { + // Node/CommonJS style for Browserify + module.exports = factory; + } else { + // Browser globals + factory(jQuery); + } +}(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, previousContentWidth, + wasAtTop = true, wasAtLeft = true, wasAtBottom = false, wasAtRight = false, + originalElement = elem.clone(false, false).empty(), + mwEvent = $.fn.mwheelIntent ? 'mwheelIntent.jsp' : 'mousewheel.jsp'; + + if (elem.css('box-sizing') === 'border-box') { + originalPadding = 0; + originalPaddingTotalWidth = 0; + } else { + originalPadding = elem.css('paddingTop') + ' ' + + elem.css('paddingRight') + ' ' + + elem.css('paddingBottom') + ' ' + + elem.css('paddingLeft'); + originalPaddingTotalWidth = (parseInt(elem.css('paddingLeft'), 10) || 0) + + (parseInt(elem.css('paddingRight'), 10) || 0); + } + + function initialise(s) + { + + var /*firstChild, lastChild, */isMaintainingPositon, lastContentX, lastContentY, + hasContainingSpaceChanged, originalScrollTop, originalScrollLeft, + maintainAtBottom = false, maintainAtRight = false; + + settings = s; + + if (pane === undefined) { + originalScrollTop = elem.scrollTop(); + originalScrollLeft = elem.scrollLeft(); + + 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 = $('
').css('padding', originalPadding).append(elem.children()); + container = $('
') + .css({ + 'width': paneWidth + 'px', + 'height': paneHeight + 'px' + } + ).append(pane).appendTo(elem); + + /* + // 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', ''); + + maintainAtBottom = settings.stickToBottom && isCloseToBottom(); + maintainAtRight = settings.stickToRight && isCloseToRight(); + + hasContainingSpaceChanged = elem.innerWidth() + originalPaddingTotalWidth != paneWidth || elem.outerHeight() != paneHeight; + + if (hasContainingSpaceChanged) { + paneWidth = elem.innerWidth() + originalPaddingTotalWidth; + paneHeight = elem.innerHeight(); + container.css({ + width: paneWidth + 'px', + height: paneHeight + 'px' + }); + } + + // If nothing changed since last check... + if (!hasContainingSpaceChanged && previousContentWidth == contentWidth && pane.outerHeight() == contentHeight) { + elem.width(paneWidth); + return; + } + previousContentWidth = contentWidth; + + pane.css('width', ''); + elem.width(paneWidth); + + container.find('>.jspVerticalBar,>.jspHorizontalBar').remove().end(); + } + + pane.css('overflow', 'auto'); + if (s.contentWidth) { + contentWidth = s.contentWidth; + } else { + contentWidth = pane[0].scrollWidth; + } + contentHeight = pane[0].scrollHeight; + pane.css('overflow', ''); + + 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, + left: 0, + width: container.width() - originalPaddingTotalWidth + }); + removeMousewheel(); + removeFocusHandler(); + removeKeyboardNav(); + removeClickOnTrack(); + } else { + elem.addClass('jspScrollable'); + + isMaintainingPositon = settings.maintainPosition && (verticalDragPosition || horizontalDragPosition); + if (isMaintainingPositon) { + lastContentX = contentPositionX(); + lastContentY = contentPositionY(); + } + + initialiseVerticalScroll(); + initialiseHorizontalScroll(); + resizeScrollbars(); + + if (isMaintainingPositon) { + scrollToX(maintainAtRight ? (contentWidth - paneWidth ) : lastContentX, false); + scrollToY(maintainAtBottom ? (contentHeight - paneHeight) : lastContentY, false); + } + + initFocusHandler(); + initMousewheel(); + initTouch(); + + if (settings.enableKeyboardNavigation) { + initKeyboardNav(); + } + if (settings.clickOnTrack) { + initClickOnTrack(); + } + + observeHash(); + if (settings.hijackInternalLinks) { + hijackInternalLinks(); + } + } + + if (settings.autoReinitialise && !reinitialiseInterval) { + reinitialiseInterval = setInterval( + function() + { + initialise(settings); + }, + settings.autoReinitialiseDelay + ); + } else if (!settings.autoReinitialise && reinitialiseInterval) { + clearInterval(reinitialiseInterval); + } + + originalScrollTop && elem.scrollTop(0) && scrollToY(originalScrollTop, false); + originalScrollLeft && elem.scrollLeft(0) && scrollToX(originalScrollLeft, false); + + elem.trigger('jsp-initialised', [isScrollableH || isScrollableV]); + } + + function initialiseVerticalScroll() + { + if (isScrollableV) { + + container.append( + $('
').append( + $('
'), + $('
').append( + $('
').append( + $('
'), + $('
') + ) + ), + $('
') + ) + ); + + verticalBar = container.find('>.jspVerticalBar'); + verticalTrack = verticalBar.find('>.jspTrack'); + verticalDrag = verticalTrack.find('>.jspDrag'); + + if (settings.showArrows) { + arrowUp = $('').bind( + 'mousedown.jsp', getArrowScroll(0, -1) + ).bind('click.jsp', nil); + arrowDown = $('').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', nil); + + 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(); + } + } + + 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) + try { + if (verticalBar.position().left === 0) { + pane.css('margin-left', scrollbarWidth + 'px'); + } + } catch (err) { + } + } + + function initialiseHorizontalScroll() + { + if (isScrollableH) { + + container.append( + $('
').append( + $('
'), + $('
').append( + $('
').append( + $('
'), + $('
') + ) + ), + $('
') + ) + ); + + horizontalBar = container.find('>.jspHorizontalBar'); + horizontalTrack = horizontalBar.find('>.jspTrack'); + horizontalDrag = horizontalTrack.find('>.jspDrag'); + + if (settings.showArrows) { + arrowLeft = $('').bind( + 'mousedown.jsp', getArrowScroll(-1, 0) + ).bind('click.jsp', nil); + arrowRight = $('').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', nil); + + 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(); + } + } + + 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( + $('
').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 = Math.ceil(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; + _positionDragX(horizontalDragPosition); // To update the state for the arrow buttons + } + if (isScrollableV) { + verticalDragHeight = Math.ceil(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; + _positionDragY(verticalDragPosition); // To update the state for the arrow buttons + } + } + + 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, + scrollTimeout, + isFirst = true, + doScroll = function() + { + if (dirX !== 0) { + jsp.scrollByX(dirX * settings.arrowButtonSpeed); + } + if (dirY !== 0) { + jsp.scrollByY(dirY * settings.arrowButtonSpeed); + } + scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.arrowRepeatFreq); + isFirst = false; + }; + + doScroll(); + + eve = ele ? 'mouseout.jsp' : 'mouseup.jsp'; + ele = ele || $('html'); + ele.bind( + eve, + function() + { + arrow.removeClass('jspActive'); + scrollTimeout && clearTimeout(scrollTimeout); + scrollTimeout = null; + ele.unbind(eve); + } + ); + } + + function initClickOnTrack() + { + removeClickOnTrack(); + if (isScrollableV) { + verticalTrack.bind( + 'mousedown.jsp', + function(e) + { + if (e.originalTarget === undefined || e.originalTarget == e.currentTarget) { + var clickedTrack = $(this), + offset = clickedTrack.offset(), + direction = e.pageY - offset.top - verticalDragPosition, + scrollTimeout, + isFirst = true, + doScroll = function() + { + var offset = clickedTrack.offset(), + pos = e.pageY - offset.top - verticalDragHeight / 2, + contentDragY = paneHeight * settings.scrollPagePercent, + dragY = dragMaxY * contentDragY / (contentHeight - paneHeight); + if (direction < 0) { + if (verticalDragPosition - dragY > pos) { + jsp.scrollByY(-contentDragY); + } else { + positionDragY(pos); + } + } else if (direction > 0) { + if (verticalDragPosition + dragY < pos) { + jsp.scrollByY(contentDragY); + } else { + positionDragY(pos); + } + } else { + cancelClick(); + return; + } + scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.trackClickRepeatFreq); + isFirst = false; + }, + cancelClick = function() + { + scrollTimeout && clearTimeout(scrollTimeout); + scrollTimeout = null; + $(document).unbind('mouseup.jsp', cancelClick); + }; + doScroll(); + $(document).bind('mouseup.jsp', cancelClick); + return false; + } + } + ); + } + + if (isScrollableH) { + horizontalTrack.bind( + 'mousedown.jsp', + function(e) + { + if (e.originalTarget === undefined || e.originalTarget == e.currentTarget) { + var clickedTrack = $(this), + offset = clickedTrack.offset(), + direction = e.pageX - offset.left - horizontalDragPosition, + scrollTimeout, + isFirst = true, + doScroll = function() + { + var offset = clickedTrack.offset(), + pos = e.pageX - offset.left - horizontalDragWidth / 2, + contentDragX = paneWidth * settings.scrollPagePercent, + dragX = dragMaxX * contentDragX / (contentWidth - paneWidth); + if (direction < 0) { + if (horizontalDragPosition - dragX > pos) { + jsp.scrollByX(-contentDragX); + } else { + positionDragX(pos); + } + } else if (direction > 0) { + if (horizontalDragPosition + dragX < pos) { + jsp.scrollByX(contentDragX); + } else { + positionDragX(pos); + } + } else { + cancelClick(); + return; + } + scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.trackClickRepeatFreq); + isFirst = false; + }, + cancelClick = function() + { + scrollTimeout && clearTimeout(scrollTimeout); + scrollTimeout = null; + $(document).unbind('mouseup.jsp', cancelClick); + }; + doScroll(); + $(document).bind('mouseup.jsp', cancelClick); + return false; + } + } + ); + } + } + + function removeClickOnTrack() + { + if (horizontalTrack) { + horizontalTrack.unbind('mousedown.jsp'); + } + if (verticalTrack) { + verticalTrack.unbind('mousedown.jsp'); + } + } + + function cancelDrag() + { + $('html').unbind('dragstart.jsp selectstart.jsp mousemove.jsp mouseup.jsp mouseleave.jsp'); + + if (verticalDrag) { + verticalDrag.removeClass('jspActive'); + } + if (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 || 0; + + 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]).trigger('scroll'); + } + + 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 ||0; + + var isAtLeft = horizontalDragPosition === 0, + isAtRight = horizontalDragPosition == dragMaxX, + 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]).trigger('scroll'); + } + + 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, eleWidth, eleTop = 0, eleLeft = 0, viewportTop, viewportLeft, maxVisibleEleTop, maxVisibleEleLeft, destY, destX; + + // 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(); + eleWidth= e.outerWidth(); + + container.scrollTop(0); + container.scrollLeft(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; + eleLeft += e.position().left; + 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.horizontalGutter; + } else if (eleTop + eleHeight > maxVisibleEleTop) { // element is below viewport + destY = eleTop - paneHeight + eleHeight + settings.horizontalGutter; + } + if (!isNaN(destY)) { + scrollToY(destY, animate); + } + + viewportLeft = contentPositionX(); + maxVisibleEleLeft = viewportLeft + paneWidth; + if (eleLeft < viewportLeft || stickToTop) { // element is to the left of viewport + destX = eleLeft - settings.horizontalGutter; + } else if (eleLeft + eleWidth > maxVisibleEleLeft) { // element is to the right viewport + destX = eleLeft - paneWidth + eleWidth + settings.horizontalGutter; + } + if (!isNaN(destX)) { + scrollToX(destX, animate); + } + + } + + function contentPositionX() + { + return -pane.position().left; + } + + function contentPositionY() + { + return -pane.position().top; + } + + function isCloseToBottom() + { + var scrollableHeight = contentHeight - paneHeight; + return (scrollableHeight > 20) && (scrollableHeight - contentPositionY() < 10); + } + + function isCloseToRight() + { + var scrollableWidth = contentWidth - paneWidth; + return (scrollableWidth > 20) && (scrollableWidth - contentPositionX() < 10); + } + + function initMousewheel() + { + container.unbind(mwEvent).bind( + mwEvent, + function (event, delta, deltaX, deltaY) { + + if (!horizontalDragPosition) horizontalDragPosition = 0; + if (!verticalDragPosition) verticalDragPosition = 0; + + var dX = horizontalDragPosition, dY = verticalDragPosition, factor = event.deltaFactor || settings.mouseWheelSpeed; + jsp.scrollBy(deltaX * factor, -deltaY * factor, 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.find(':input,a').unbind('focus.jsp').bind( + 'focus.jsp', + function(e) + { + scrollToElement(e.target, false); + } + ); + } + + function removeFocusHandler() + { + pane.find(':input,a').unbind('focus.jsp'); + } + + function initKeyboardNav() + { + var keyDown, elementHasScrolled, validParents = []; + isScrollableH && validParents.push(horizontalBar[0]); + isScrollableV && validParents.push(verticalBar[0]); + + // IE also focuses elements that don't have tabindex set. + pane.focus( + function() + { + elem.focus(); + } + ); + + elem.attr('tabindex', 0) + .unbind('keydown.jsp keypress.jsp') + .bind( + 'keydown.jsp', + function(e) + { + if (e.target !== this && !(validParents.length && $(e.target).closest(validParents).length)){ + return; + } + var dX = horizontalDragPosition, dY = verticalDragPosition; + switch(e.keyCode) { + case 40: // down + case 38: // up + case 34: // page down + case 32: // space + case 33: // page up + case 39: // right + case 37: // left + keyDown = e.keyCode; + keyDownHandler(); + break; + case 35: // end + scrollToY(contentHeight - paneHeight); + keyDown = null; + break; + case 36: // home + scrollToY(0); + keyDown = null; + break; + } + + elementHasScrolled = e.keyCode == keyDown && dX != horizontalDragPosition || dY != verticalDragPosition; + return !elementHasScrolled; + } + ).bind( + 'keypress.jsp', // For FF/ OSX so that we can cancel the repeat key presses if the JSP scrolls... + function(e) + { + if (e.keyCode == keyDown) { + keyDownHandler(); + } + return !elementHasScrolled; + } + ); + + 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 keyDownHandler() + { + var dX = horizontalDragPosition, dY = verticalDragPosition; + switch(keyDown) { + case 40: // down + jsp.scrollByY(settings.keyboardSpeed, false); + break; + case 38: // up + jsp.scrollByY(-settings.keyboardSpeed, false); + break; + case 34: // page down + case 32: // space + jsp.scrollByY(paneHeight * settings.scrollPagePercent, false); + break; + case 33: // page up + jsp.scrollByY(-paneHeight * settings.scrollPagePercent, false); + break; + case 39: // right + jsp.scrollByX(settings.keyboardSpeed, false); + break; + case 37: // left + jsp.scrollByX(-settings.keyboardSpeed, false); + break; + } + + elementHasScrolled = dX != horizontalDragPosition || dY != verticalDragPosition; + return elementHasScrolled; + } + } + + function removeKeyboardNav() + { + elem.attr('tabindex', '-1') + .removeAttr('tabindex') + .unbind('keydown.jsp keypress.jsp'); + } + + function observeHash() + { + if (location.hash && location.hash.length > 1) { + var e, + retryInt, + hash = escape(location.hash.substr(1)) // hash must be escaped to prevent XSS + ; + try { + e = $('#' + hash + ', a[name="' + hash + '"]'); + } catch (err) { + return; + } + + if (e.length && pane.find(hash)) { + // 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(e, true); + $(document).scrollTop(container.position().top); + clearInterval(retryInt); + } + }, + 50 + ); + } else { + scrollToElement(e, true); + $(document).scrollTop(container.position().top); + } + } + } + } + + function hijackInternalLinks() + { + // only register the link handler once + if ($(document.body).data('jspHijack')) { + return; + } + + // remember that the handler was bound + $(document.body).data('jspHijack', true); + + // use live handler to also capture newly created links + $(document.body).delegate('a[href*=#]', 'click', function(event) { + // does the link point to the same page? + // this also takes care of cases with a -Tag or Links not starting with the hash # + // e.g. when the current url already is index.html + var href = this.href.substr(0, this.href.indexOf('#')), + locationHref = location.href, + hash, + element, + container, + jsp, + scrollTop, + elementTop; + if (location.href.indexOf('#') !== -1) { + locationHref = location.href.substr(0, location.href.indexOf('#')); + } + if (href !== locationHref) { + // the link points to another page + return; + } + + // check if jScrollPane should handle this click event + hash = escape(this.href.substr(this.href.indexOf('#') + 1)); + + // find the element on the page + element; + try { + element = $('#' + hash + ', a[name="' + hash + '"]'); + } catch (e) { + // hash is not a valid jQuery identifier + return; + } + + if (!element.length) { + // this link does not point to an element on this page + return; + } + + container = element.closest('.jspScrollable'); + jsp = container.data('jsp'); + + // jsp might be another jsp instance than the one, that bound this event + // remember: this event is only bound once for all instances. + jsp.scrollToElement(element, true); + + if (container[0].scrollIntoView) { + // also scroll to the top of the container (if it is not visible) + scrollTop = $(window).scrollTop(); + elementTop = element.offset().top; + if (elementTop < scrollTop || elementTop > scrollTop + $(window).height()) { + container[0].scrollIntoView(); + } + } + + // jsp handled this event, prevent the browser default (scrolling :P) + event.preventDefault(); + }); + } + + // Init touch on iPad, iPhone, iPod, Android + function initTouch() + { + var startX, + startY, + touchStartX, + touchStartY, + moved, + moving = false; + + container.unbind('touchstart.jsp touchmove.jsp touchend.jsp click.jsp-touchclick').bind( + 'touchstart.jsp', + function(e) + { + var touch = e.originalEvent.touches[0]; + startX = contentPositionX(); + startY = contentPositionY(); + touchStartX = touch.pageX; + touchStartY = touch.pageY; + moved = false; + moving = true; + } + ).bind( + 'touchmove.jsp', + function(ev) + { + if(!moving) { + return; + } + + var touchPos = ev.originalEvent.touches[0], + dX = horizontalDragPosition, dY = verticalDragPosition; + + jsp.scrollTo(startX + touchStartX - touchPos.pageX, startY + touchStartY - touchPos.pageY); + + moved = moved || Math.abs(touchStartX - touchPos.pageX) > 5 || Math.abs(touchStartY - touchPos.pageY) > 5; + + // return true if there was no movement so rest of screen can scroll + return dX == horizontalDragPosition && dY == verticalDragPosition; + } + ).bind( + 'touchend.jsp', + function(e) + { + moving = false; + /*if(moved) { + return false; + }*/ + } + ).bind( + 'click.jsp-touchclick', + function(e) + { + if(moved) { + moved = false; + return false; + } + } + ); + } + + function destroy(){ + var currentY = contentPositionY(), + currentX = contentPositionX(); + elem.removeClass('jspScrollable').unbind('.jsp'); + elem.replaceWith(originalElement.append(pane.children())); + originalElement.scrollTop(currentY); + originalElement.scrollLeft(currentX); + + // clear reinitialize timer if active + if (reinitialiseInterval) { + clearInterval(reinitialiseInterval); + } + } + + // 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({}, settings, s); + 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 to the specified percentage of its maximum horizontal scroll position. animate + // is optional and if not passed then the value of animateScroll from the settings object this + // jScrollPane was initialised with is used. + scrollToPercentX: function(destPercentX, animate) + { + scrollToX(destPercentX * (contentWidth - paneWidth), animate); + }, + // Scrolls the pane to the specified percentage of its maximum vertical scroll position. animate + // is optional and if not passed then the value of animateScroll from the settings object this + // jScrollPane was initialised with is used. + scrollToPercentY: function(destPercentY, animate) + { + scrollToY(destPercentY * (contentHeight - paneHeight), 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() + Math[deltaX<0 ? 'floor' : 'ceil'](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() + Math[deltaY<0 ? 'floor' : 'ceil'](deltaY), + percentScrolled = destY / (contentHeight - paneHeight); + positionDragY(percentScrolled * dragMaxY, animate); + }, + // Positions the horizontal drag at the specified x position (and updates the viewport to reflect + // this). animate is optional and if not passed then the value of animateScroll from the settings + // object this jScrollPane was initialised with is used. + positionDragX: function(x, animate) + { + positionDragX(x, animate); + }, + // Positions the vertical drag at the specified y position (and updates the viewport to reflect + // this). animate is optional and if not passed then the value of animateScroll from the settings + // object this jScrollPane was initialised with is used. + positionDragY: function(y, animate) + { + positionDragY(y, 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, + 'easing' : 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 the width of the content within the scroll pane. + getContentWidth: function() + { + return contentWidth; + }, + // Returns the height of the content within the scroll pane. + getContentHeight: function() + { + return contentHeight; + }, + // Returns the horizontal position of the viewport within the pane content. + getPercentScrolledX: function() + { + return contentPositionX() / (contentWidth - paneWidth); + }, + // Returns the vertical position of the viewport within the pane content. + getPercentScrolledY: function() + { + return contentPositionY() / (contentHeight - paneHeight); + }, + // 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: $.noop, + // Removes the jScrollPane and returns the page to the state it was in before jScrollPane was + // initialised. + destroy: function() + { + destroy(); + } + } + ); + + initialise(s); + } + + // Pluginifying code... + settings = $.extend({}, $.fn.jScrollPane.defaults, settings); + + // Apply default speed + $.each(['arrowButtonSpeed', 'trackClickSpeed', 'keyboardSpeed'], function() { + settings[this] = settings[this] || settings.speed; + }); + + return this.each( + function() + { + var elem = $(this), jspApi = elem.data('jsp'); + if (jspApi) { + jspApi.reinitialise(settings); + } else { + $("script",elem).filter('[type="text/javascript"],:not([type])').remove(); + jspApi = new JScrollPane(elem, settings); + elem.data('jsp', jspApi); + } + } + ); + }; + + $.fn.jScrollPane.defaults = { + showArrows : false, + maintainPosition : true, + stickToBottom : false, + stickToRight : false, + clickOnTrack : true, + autoReinitialise : false, + autoReinitialiseDelay : 500, + verticalDragMinHeight : 0, + verticalDragMaxHeight : 99999, + horizontalDragMinWidth : 0, + horizontalDragMaxWidth : 99999, + contentWidth : undefined, + animateScroll : false, + animateDuration : 300, + animateEase : 'linear', + hijackInternalLinks : false, + verticalGutter : 4, + horizontalGutter : 4, + mouseWheelSpeed : 3, + arrowButtonSpeed : 0, + arrowRepeatFreq : 50, + arrowScrollOnHover : false, + trackClickSpeed : 0, + trackClickRepeatFreq : 70, + verticalArrowPositions : 'split', + horizontalArrowPositions : 'split', + enableKeyboardNavigation : true, + hideFocus : false, + keyboardSpeed : 0, + initialDelay : 300, // Delay before starting repeating + speed : 30, // Default speed when others falsey + scrollPagePercent : .8 // Percent of visible area scrolled when pageUp/Down or track area pressed + }; + +},this)); \ No newline at end of file diff --git a/ajax/libs/jScrollPane/2.0.20/script/jquery.jscrollpane.min.js b/ajax/libs/jScrollPane/2.0.20/script/jquery.jscrollpane.min.js new file mode 100644 index 00000000000000..fbe698811b8f8a --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.20/script/jquery.jscrollpane.min.js @@ -0,0 +1,11 @@ +/* + * jScrollPane - v2.0.20 - 2014-10-23 + * http://jscrollpane.kelvinluck.com/ + * + * Copyright (c) 2014 Kelvin Luck + * Dual licensed under the MIT or GPL licenses. + */ +(function(c,b){var a=function(d){return c(d,b)};if(typeof define==="function"&&define.amd){define(["jquery"],a)}else{if(typeof exports==="object"){module.exports=a}else{a(jQuery)}}}(function(b,a,c){b.fn.jScrollPane=function(e){function d(D,O){var ay,Q=this,Y,aj,v,al,T,Z,y,q,az,aE,au,i,I,h,j,aa,U,ap,X,t,A,aq,af,am,G,l,at,ax,x,av,aH,f,L,ai=true,P=true,aG=false,k=false,ao=D.clone(false,false).empty(),ac=b.fn.mwheelIntent?"mwheelIntent.jsp":"mousewheel.jsp";if(D.css("box-sizing")==="border-box"){aH=0;f=0}else{aH=D.css("paddingTop")+" "+D.css("paddingRight")+" "+D.css("paddingBottom")+" "+D.css("paddingLeft");f=(parseInt(D.css("paddingLeft"),10)||0)+(parseInt(D.css("paddingRight"),10)||0)}function ar(aQ){var aL,aN,aM,aJ,aI,aP,aO=false,aK=false;ay=aQ;if(Y===c){aI=D.scrollTop();aP=D.scrollLeft();D.css({overflow:"hidden",padding:0});aj=D.innerWidth()+f;v=D.innerHeight();D.width(aj);Y=b('
').css("padding",aH).append(D.children());al=b('
').css({width:aj+"px",height:v+"px"}).append(Y).appendTo(D)}else{D.css("width","");aO=ay.stickToBottom&&K();aK=ay.stickToRight&&B();aJ=D.innerWidth()+f!=aj||D.outerHeight()!=v;if(aJ){aj=D.innerWidth()+f;v=D.innerHeight();al.css({width:aj+"px",height:v+"px"})}if(!aJ&&L==T&&Y.outerHeight()==Z){D.width(aj);return}L=T;Y.css("width","");D.width(aj);al.find(">.jspVerticalBar,>.jspHorizontalBar").remove().end()}Y.css("overflow","auto");if(aQ.contentWidth){T=aQ.contentWidth}else{T=Y[0].scrollWidth}Z=Y[0].scrollHeight;Y.css("overflow","");y=T/aj;q=Z/v;az=q>1;aE=y>1;if(!(aE||az)){D.removeClass("jspScrollable");Y.css({top:0,left:0,width:al.width()-f});n();E();R();w()}else{D.addClass("jspScrollable");aL=ay.maintainPosition&&(I||aa);if(aL){aN=aC();aM=aA()}aF();z();F();if(aL){N(aK?(T-aj):aN,false);M(aO?(Z-v):aM,false)}J();ag();an();if(ay.enableKeyboardNavigation){S()}if(ay.clickOnTrack){p()}C();if(ay.hijackInternalLinks){m()}}if(ay.autoReinitialise&&!av){av=setInterval(function(){ar(ay)},ay.autoReinitialiseDelay)}else{if(!ay.autoReinitialise&&av){clearInterval(av)}}aI&&D.scrollTop(0)&&M(aI,false);aP&&D.scrollLeft(0)&&N(aP,false);D.trigger("jsp-initialised",[aE||az])}function aF(){if(az){al.append(b('
').append(b('
'),b('
').append(b('
').append(b('
'),b('
'))),b('
')));U=al.find(">.jspVerticalBar");ap=U.find(">.jspTrack");au=ap.find(">.jspDrag");if(ay.showArrows){aq=b('').bind("mousedown.jsp",aD(0,-1)).bind("click.jsp",aB);af=b('').bind("mousedown.jsp",aD(0,1)).bind("click.jsp",aB);if(ay.arrowScrollOnHover){aq.bind("mouseover.jsp",aD(0,-1,aq));af.bind("mouseover.jsp",aD(0,1,af))}ak(ap,ay.verticalArrowPositions,aq,af)}t=v;al.find(">.jspVerticalBar>.jspCap:visible,>.jspVerticalBar>.jspArrow").each(function(){t-=b(this).outerHeight()});au.hover(function(){au.addClass("jspHover")},function(){au.removeClass("jspHover")}).bind("mousedown.jsp",function(aI){b("html").bind("dragstart.jsp selectstart.jsp",aB);au.addClass("jspActive");var s=aI.pageY-au.position().top;b("html").bind("mousemove.jsp",function(aJ){V(aJ.pageY-s,false)}).bind("mouseup.jsp mouseleave.jsp",aw);return false});o()}}function o(){ap.height(t+"px");I=0;X=ay.verticalGutter+ap.outerWidth();Y.width(aj-X-f);try{if(U.position().left===0){Y.css("margin-left",X+"px")}}catch(s){}}function z(){if(aE){al.append(b('
').append(b('
'),b('
').append(b('
').append(b('
'),b('
'))),b('
')));am=al.find(">.jspHorizontalBar"); +G=am.find(">.jspTrack");h=G.find(">.jspDrag");if(ay.showArrows){ax=b('').bind("mousedown.jsp",aD(-1,0)).bind("click.jsp",aB);x=b('').bind("mousedown.jsp",aD(1,0)).bind("click.jsp",aB);if(ay.arrowScrollOnHover){ax.bind("mouseover.jsp",aD(-1,0,ax));x.bind("mouseover.jsp",aD(1,0,x))}ak(G,ay.horizontalArrowPositions,ax,x)}h.hover(function(){h.addClass("jspHover")},function(){h.removeClass("jspHover")}).bind("mousedown.jsp",function(aI){b("html").bind("dragstart.jsp selectstart.jsp",aB);h.addClass("jspActive");var s=aI.pageX-h.position().left;b("html").bind("mousemove.jsp",function(aJ){W(aJ.pageX-s,false)}).bind("mouseup.jsp mouseleave.jsp",aw);return false});l=al.innerWidth();ah()}}function ah(){al.find(">.jspHorizontalBar>.jspCap:visible,>.jspHorizontalBar>.jspArrow").each(function(){l-=b(this).outerWidth()});G.width(l+"px");aa=0}function F(){if(aE&&az){var aI=G.outerHeight(),s=ap.outerWidth();t-=aI;b(am).find(">.jspCap:visible,>.jspArrow").each(function(){l+=b(this).outerWidth()});l-=s;v-=s;aj-=aI;G.parent().append(b('
').css("width",aI+"px"));o();ah()}if(aE){Y.width((al.outerWidth()-f)+"px")}Z=Y.outerHeight();q=Z/v;if(aE){at=Math.ceil(1/y*l);if(at>ay.horizontalDragMaxWidth){at=ay.horizontalDragMaxWidth}else{if(atay.verticalDragMaxHeight){A=ay.verticalDragMaxHeight}else{if(AaS){Q.scrollByY(-aP)}else{V(aS)}}else{if(aM>0){if(I+aQaS){Q.scrollByX(-aP)}else{W(aS)}}else{if(aM>0){if(aa+aQi){s=i}}if(aI===c){aI=ay.animateScroll}if(aI){Q.animate(au,"top",s,ad)}else{au.css("top",s);ad(s)}}function ad(aI){if(aI===c){aI=au.position().top}al.scrollTop(0);I=aI||0;var aL=I===0,aJ=I==i,aK=aI/i,s=-aK*(Z-v);if(ai!=aL||aG!=aJ){ai=aL; +aG=aJ;D.trigger("jsp-arrow-change",[ai,aG,P,k])}u(aL,aJ);Y.css("top",s);D.trigger("jsp-scroll-y",[-s,aL,aJ]).trigger("scroll")}function W(aI,s){if(!aE){return}if(aI<0){aI=0}else{if(aI>j){aI=j}}if(s===c){s=ay.animateScroll}if(s){Q.animate(h,"left",aI,ae)}else{h.css("left",aI);ae(aI)}}function ae(aI){if(aI===c){aI=h.position().left}al.scrollTop(0);aa=aI||0;var aL=aa===0,aK=aa==j,aJ=aI/j,s=-aJ*(T-aj);if(P!=aL||k!=aK){P=aL;k=aK;D.trigger("jsp-arrow-change",[ai,aG,P,k])}r(aL,aK);Y.css("left",s);D.trigger("jsp-scroll-x",[-s,aL,aK]).trigger("scroll")}function u(aI,s){if(ay.showArrows){aq[aI?"addClass":"removeClass"]("jspDisabled");af[s?"addClass":"removeClass"]("jspDisabled")}}function r(aI,s){if(ay.showArrows){ax[aI?"addClass":"removeClass"]("jspDisabled");x[s?"addClass":"removeClass"]("jspDisabled")}}function M(s,aI){var aJ=s/(Z-v);V(aJ*i,aI)}function N(aI,s){var aJ=aI/(T-aj);W(aJ*j,s)}function ab(aV,aQ,aJ){var aN,aK,aL,s=0,aU=0,aI,aP,aO,aS,aR,aT;try{aN=b(aV)}catch(aM){return}aK=aN.outerHeight();aL=aN.outerWidth();al.scrollTop(0);al.scrollLeft(0);while(!aN.is(".jspPane")){s+=aN.position().top;aU+=aN.position().left;aN=aN.offsetParent();if(/^body|html$/i.test(aN[0].nodeName)){return}}aI=aA();aO=aI+v;if(saO){aR=s-v+aK+ay.horizontalGutter}}if(!isNaN(aR)){M(aR,aJ)}aP=aC();aS=aP+aj;if(aUaS){aT=aU-aj+aL+ay.horizontalGutter}}if(!isNaN(aT)){N(aT,aJ)}}function aC(){return -Y.position().left}function aA(){return -Y.position().top}function K(){var s=Z-v;return(s>20)&&(s-aA()<10)}function B(){var s=T-aj;return(s>20)&&(s-aC()<10)}function ag(){al.unbind(ac).bind(ac,function(aM,aN,aK,aI){if(!aa){aa=0}if(!I){I=0}var aJ=aa,s=I,aL=aM.deltaFactor||ay.mouseWheelSpeed;Q.scrollBy(aK*aL,-aI*aL,false);return aJ==aa&&s==I})}function n(){al.unbind(ac)}function aB(){return false}function J(){Y.find(":input,a").unbind("focus.jsp").bind("focus.jsp",function(s){ab(s.target,false)})}function E(){Y.find(":input,a").unbind("focus.jsp")}function S(){var s,aI,aK=[];aE&&aK.push(am[0]);az&&aK.push(U[0]);Y.focus(function(){D.focus()});D.attr("tabindex",0).unbind("keydown.jsp keypress.jsp").bind("keydown.jsp",function(aN){if(aN.target!==this&&!(aK.length&&b(aN.target).closest(aK).length)){return}var aM=aa,aL=I;switch(aN.keyCode){case 40:case 38:case 34:case 32:case 33:case 39:case 37:s=aN.keyCode;aJ();break;case 35:M(Z-v);s=null;break;case 36:M(0);s=null;break}aI=aN.keyCode==s&&aM!=aa||aL!=I;return !aI}).bind("keypress.jsp",function(aL){if(aL.keyCode==s){aJ()}return !aI});if(ay.hideFocus){D.css("outline","none");if("hideFocus" in al[0]){D.attr("hideFocus",true)}}else{D.css("outline","");if("hideFocus" in al[0]){D.attr("hideFocus",false)}}function aJ(){var aM=aa,aL=I;switch(s){case 40:Q.scrollByY(ay.keyboardSpeed,false);break;case 38:Q.scrollByY(-ay.keyboardSpeed,false);break;case 34:case 32:Q.scrollByY(v*ay.scrollPagePercent,false);break;case 33:Q.scrollByY(-v*ay.scrollPagePercent,false);break;case 39:Q.scrollByX(ay.keyboardSpeed,false);break;case 37:Q.scrollByX(-ay.keyboardSpeed,false);break}aI=aM!=aa||aL!=I;return aI}}function R(){D.attr("tabindex","-1").removeAttr("tabindex").unbind("keydown.jsp keypress.jsp")}function C(){if(location.hash&&location.hash.length>1){var aK,aI,aJ=escape(location.hash.substr(1));try{aK=b("#"+aJ+', a[name="'+aJ+'"]')}catch(s){return}if(aK.length&&Y.find(aJ)){if(al.scrollTop()===0){aI=setInterval(function(){if(al.scrollTop()>0){ab(aK,true);b(document).scrollTop(al.position().top);clearInterval(aI)}},50)}else{ab(aK,true);b(document).scrollTop(al.position().top)}}}}function m(){if(b(document.body).data("jspHijack")){return}b(document.body).data("jspHijack",true);b(document.body).delegate("a[href*=#]","click",function(s){var aI=this.href.substr(0,this.href.indexOf("#")),aK=location.href,aO,aP,aJ,aM,aL,aN;if(location.href.indexOf("#")!==-1){aK=location.href.substr(0,location.href.indexOf("#"))}if(aI!==aK){return}aO=escape(this.href.substr(this.href.indexOf("#")+1)); +aP;try{aP=b("#"+aO+', a[name="'+aO+'"]')}catch(aQ){return}if(!aP.length){return}aJ=aP.closest(".jspScrollable");aM=aJ.data("jsp");aM.scrollToElement(aP,true);if(aJ[0].scrollIntoView){aL=b(a).scrollTop();aN=aP.offset().top;if(aNaL+b(a).height()){aJ[0].scrollIntoView()}}s.preventDefault()})}function an(){var aJ,aI,aL,aK,aM,s=false;al.unbind("touchstart.jsp touchmove.jsp touchend.jsp click.jsp-touchclick").bind("touchstart.jsp",function(aN){var aO=aN.originalEvent.touches[0];aJ=aC();aI=aA();aL=aO.pageX;aK=aO.pageY;aM=false;s=true}).bind("touchmove.jsp",function(aQ){if(!s){return}var aP=aQ.originalEvent.touches[0],aO=aa,aN=I;Q.scrollTo(aJ+aL-aP.pageX,aI+aK-aP.pageY);aM=aM||Math.abs(aL-aP.pageX)>5||Math.abs(aK-aP.pageY)>5;return aO==aa&&aN==I}).bind("touchend.jsp",function(aN){s=false}).bind("click.jsp-touchclick",function(aN){if(aM){aM=false;return false}})}function g(){var s=aA(),aI=aC();D.removeClass("jspScrollable").unbind(".jsp");D.replaceWith(ao.append(Y.children()));ao.scrollTop(s);ao.scrollLeft(aI);if(av){clearInterval(av)}}b.extend(Q,{reinitialise:function(aI){aI=b.extend({},ay,aI);ar(aI)},scrollToElement:function(aJ,aI,s){ab(aJ,aI,s)},scrollTo:function(aJ,s,aI){N(aJ,aI);M(s,aI)},scrollToX:function(aI,s){N(aI,s)},scrollToY:function(s,aI){M(s,aI)},scrollToPercentX:function(aI,s){N(aI*(T-aj),s)},scrollToPercentY:function(aI,s){M(aI*(Z-v),s)},scrollBy:function(aI,s,aJ){Q.scrollByX(aI,aJ);Q.scrollByY(s,aJ)},scrollByX:function(s,aJ){var aI=aC()+Math[s<0?"floor":"ceil"](s),aK=aI/(T-aj);W(aK*j,aJ)},scrollByY:function(s,aJ){var aI=aA()+Math[s<0?"floor":"ceil"](s),aK=aI/(Z-v);V(aK*i,aJ)},positionDragX:function(s,aI){W(s,aI)},positionDragY:function(aI,s){V(aI,s)},animate:function(aI,aL,s,aK){var aJ={};aJ[aL]=s;aI.animate(aJ,{duration:ay.animateDuration,easing:ay.animateEase,queue:false,step:aK})},getContentPositionX:function(){return aC()},getContentPositionY:function(){return aA()},getContentWidth:function(){return T},getContentHeight:function(){return Z},getPercentScrolledX:function(){return aC()/(T-aj)},getPercentScrolledY:function(){return aA()/(Z-v)},getIsScrollableH:function(){return aE},getIsScrollableV:function(){return az},getContentPane:function(){return Y},scrollToBottom:function(s){V(i,s)},hijackInternalLinks:b.noop,destroy:function(){g()}});ar(O)}e=b.extend({},b.fn.jScrollPane.defaults,e);b.each(["arrowButtonSpeed","trackClickSpeed","keyboardSpeed"],function(){e[this]=e[this]||e.speed});return this.each(function(){var f=b(this),g=f.data("jsp");if(g){g.reinitialise(e)}else{b("script",f).filter('[type="text/javascript"],:not([type])').remove();g=new d(f,e);f.data("jsp",g)}})};b.fn.jScrollPane.defaults={showArrows:false,maintainPosition:true,stickToBottom:false,stickToRight:false,clickOnTrack:true,autoReinitialise:false,autoReinitialiseDelay:500,verticalDragMinHeight:0,verticalDragMaxHeight:99999,horizontalDragMinWidth:0,horizontalDragMaxWidth:99999,contentWidth:c,animateScroll:false,animateDuration:300,animateEase:"linear",hijackInternalLinks:false,verticalGutter:4,horizontalGutter:4,mouseWheelSpeed:3,arrowButtonSpeed:0,arrowRepeatFreq:50,arrowScrollOnHover:false,trackClickSpeed:0,trackClickRepeatFreq:70,verticalArrowPositions:"split",horizontalArrowPositions:"split",enableKeyboardNavigation:true,hideFocus:false,keyboardSpeed:0,initialDelay:300,speed:30,scrollPagePercent:0.8}},this)); \ No newline at end of file diff --git a/ajax/libs/jScrollPane/2.0.20/style/jquery.jscrollpane.css b/ajax/libs/jScrollPane/2.0.20/style/jquery.jscrollpane.css new file mode 100644 index 00000000000000..57ccca25316d53 --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.20/style/jquery.jscrollpane.css @@ -0,0 +1,115 @@ +/* + * CSS Styles that are needed by jScrollPane for it to operate correctly. + * + * Include this stylesheet in your site or copy and paste the styles below into your stylesheet - jScrollPane + * may not operate correctly without them. + */ + +.jspContainer +{ + overflow: hidden; + position: relative; +} + +.jspPane +{ + position: absolute; +} + +.jspVerticalBar +{ + position: absolute; + top: 0; + right: 0; + width: 16px; + height: 100%; + background: red; +} + +.jspHorizontalBar +{ + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 16px; + background: red; +} + +.jspCap +{ + display: none; +} + +.jspHorizontalBar .jspCap +{ + float: left; +} + +.jspTrack +{ + background: #dde; + position: relative; +} + +.jspDrag +{ + background: #bbd; + position: relative; + top: 0; + left: 0; + cursor: pointer; +} + +.jspHorizontalBar .jspTrack, +.jspHorizontalBar .jspDrag +{ + float: left; + height: 100%; +} + +.jspArrow +{ + background: #50506d; + text-indent: -20000px; + display: block; + cursor: pointer; + padding: 0; + margin: 0; +} + +.jspArrow.jspDisabled +{ + cursor: default; + background: #80808d; +} + +.jspVerticalBar .jspArrow +{ + height: 16px; +} + +.jspHorizontalBar .jspArrow +{ + width: 16px; + float: left; + height: 100%; +} + +.jspVerticalBar .jspArrow:focus +{ + outline: none; +} + +.jspCorner +{ + background: #eeeef4; + float: left; + height: 100%; +} + +/* Yuk! CSS Hack for IE6 3 pixel bug :( */ +* html .jspCorner +{ + margin: 0 -3px 0 0; +} \ No newline at end of file diff --git a/ajax/libs/jScrollPane/2.0.20/style/jquery.jscrollpane.min.css b/ajax/libs/jScrollPane/2.0.20/style/jquery.jscrollpane.min.css new file mode 100644 index 00000000000000..9a0eed96f15c3a --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.20/style/jquery.jscrollpane.min.css @@ -0,0 +1 @@ +.jspContainer{overflow:hidden;position:relative}.jspPane{position:absolute}.jspVerticalBar{position:absolute;top:0;right:0;width:16px;height:100%;background:red}.jspHorizontalBar{position:absolute;bottom:0;left:0;width:100%;height:16px;background:red}.jspCap{display:none}.jspHorizontalBar .jspCap{float:left}.jspTrack{background:#dde;position:relative}.jspDrag{background:#bbd;position:relative;top:0;left:0;cursor:pointer}.jspHorizontalBar .jspTrack,.jspHorizontalBar .jspDrag{float:left;height:100%}.jspArrow{background:#50506d;text-indent:-20000px;display:block;cursor:pointer;padding:0;margin:0}.jspArrow.jspDisabled{cursor:default;background:#80808d}.jspVerticalBar .jspArrow{height:16px}.jspHorizontalBar .jspArrow{width:16px;float:left;height:100%}.jspVerticalBar .jspArrow:focus{outline:0}.jspCorner{background:#eeeef4;float:left;height:100%}* html .jspCorner{margin:0 -3px 0 0} \ No newline at end of file diff --git a/ajax/libs/jScrollPane/2.0.21/script/jquery.jscrollpane.js b/ajax/libs/jScrollPane/2.0.21/script/jquery.jscrollpane.js new file mode 100644 index 00000000000000..6847e377f740e0 --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.21/script/jquery.jscrollpane.js @@ -0,0 +1,1465 @@ +/*! + * jScrollPane - v2.0.21 - 2015-02-24 + * http://jscrollpane.kelvinluck.com/ + * + * Copyright (c) 2014 Kelvin Luck + * Dual licensed under the MIT or GPL licenses. + */ + +// Script: jScrollPane - cross browser customisable scrollbars +// +// *Version: 2.0.21, Last updated: 2015-02-24* +// +// 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) 2014 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 - tested in 1.4.2+ - reported to work in 1.3.x +// Browsers Tested - Firefox 3.6.8, Safari 5, Opera 10.6, Chrome 5.0, IE 6, 7, 8 +// +// About: Release History +// +// 2.0.21 - (2015-02-24) Simplify UMD pattern: fixes browserify when loading jQuery outside of bundle +// 2.0.20 - (2014-10-23) Adds AMD support (thanks @carlosrberto) and support for overflow-x/overflow-y (thanks @darimpulso) +// 2.0.19 - (2013-11-16) Changes for more reliable scroll amount with latest mousewheel plugin (thanks @brandonaaron) +// 2.0.18 - (2013-10-23) Fix for issue with gutters and scrollToElement (thanks @Dubiy) +// 2.0.17 - (2013-08-17) Working correctly when box-sizing is set to border-box (thanks @pieht) +// 2.0.16 - (2013-07-30) Resetting left position when scroll is removed. Fixes #189 +// 2.0.15 - (2013-07-29) Fixed issue with scrollToElement where the destX and destY are undefined. +// 2.0.14 - (2013-05-01) Updated to most recent mouse wheel plugin (see #106) and related changes for sensible scroll speed +// 2.0.13 - (2013-05-01) Switched to semver compatible version name +// 2.0.0beta12 - (2012-09-27) fix for jQuery 1.8+ +// 2.0.0beta11 - (2012-05-14) +// 2.0.0beta10 - (2011-04-17) cleaner required size calculation, improved keyboard support, stickToBottom/Left, other small fixes +// 2.0.0beta9 - (2011-01-31) new API methods, bug fixes and correct keyboard support for FF/OSX +// 2.0.0beta8 - (2011-01-29) touchscreen support, improved keyboard support +// 2.0.0beta7 - (2011-01-23) scroll speed consistent (thanks Aivo Paas) +// 2.0.0beta6 - (2010-12-07) scrollToElement horizontal support +// 2.0.0beta5 - (2010-10-18) jQuery 1.4.3 support, various bug fixes +// 2.0.0beta4 - (2010-09-17) clickOnTrack support, bug fixes +// 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 (factory) { + if ( typeof define === 'function' && define.amd ) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof exports === 'object') { + // Node/CommonJS style for Browserify + module.exports = factory(require('jquery')); + } else { + // Browser globals + factory(jQuery); + } +}(function($){ + + $.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, previousContentWidth, + wasAtTop = true, wasAtLeft = true, wasAtBottom = false, wasAtRight = false, + originalElement = elem.clone(false, false).empty(), + mwEvent = $.fn.mwheelIntent ? 'mwheelIntent.jsp' : 'mousewheel.jsp'; + + if (elem.css('box-sizing') === 'border-box') { + originalPadding = 0; + originalPaddingTotalWidth = 0; + } else { + originalPadding = elem.css('paddingTop') + ' ' + + elem.css('paddingRight') + ' ' + + elem.css('paddingBottom') + ' ' + + elem.css('paddingLeft'); + originalPaddingTotalWidth = (parseInt(elem.css('paddingLeft'), 10) || 0) + + (parseInt(elem.css('paddingRight'), 10) || 0); + } + + function initialise(s) + { + + var /*firstChild, lastChild, */isMaintainingPositon, lastContentX, lastContentY, + hasContainingSpaceChanged, originalScrollTop, originalScrollLeft, + maintainAtBottom = false, maintainAtRight = false; + + settings = s; + + if (pane === undefined) { + originalScrollTop = elem.scrollTop(); + originalScrollLeft = elem.scrollLeft(); + + 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 = $('
').css('padding', originalPadding).append(elem.children()); + container = $('
') + .css({ + 'width': paneWidth + 'px', + 'height': paneHeight + 'px' + } + ).append(pane).appendTo(elem); + + /* + // 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', ''); + + maintainAtBottom = settings.stickToBottom && isCloseToBottom(); + maintainAtRight = settings.stickToRight && isCloseToRight(); + + hasContainingSpaceChanged = elem.innerWidth() + originalPaddingTotalWidth != paneWidth || elem.outerHeight() != paneHeight; + + if (hasContainingSpaceChanged) { + paneWidth = elem.innerWidth() + originalPaddingTotalWidth; + paneHeight = elem.innerHeight(); + container.css({ + width: paneWidth + 'px', + height: paneHeight + 'px' + }); + } + + // If nothing changed since last check... + if (!hasContainingSpaceChanged && previousContentWidth == contentWidth && pane.outerHeight() == contentHeight) { + elem.width(paneWidth); + return; + } + previousContentWidth = contentWidth; + + pane.css('width', ''); + elem.width(paneWidth); + + container.find('>.jspVerticalBar,>.jspHorizontalBar').remove().end(); + } + + pane.css('overflow', 'auto'); + if (s.contentWidth) { + contentWidth = s.contentWidth; + } else { + contentWidth = pane[0].scrollWidth; + } + contentHeight = pane[0].scrollHeight; + pane.css('overflow', ''); + + 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, + left: 0, + width: container.width() - originalPaddingTotalWidth + }); + removeMousewheel(); + removeFocusHandler(); + removeKeyboardNav(); + removeClickOnTrack(); + } else { + elem.addClass('jspScrollable'); + + isMaintainingPositon = settings.maintainPosition && (verticalDragPosition || horizontalDragPosition); + if (isMaintainingPositon) { + lastContentX = contentPositionX(); + lastContentY = contentPositionY(); + } + + initialiseVerticalScroll(); + initialiseHorizontalScroll(); + resizeScrollbars(); + + if (isMaintainingPositon) { + scrollToX(maintainAtRight ? (contentWidth - paneWidth ) : lastContentX, false); + scrollToY(maintainAtBottom ? (contentHeight - paneHeight) : lastContentY, false); + } + + initFocusHandler(); + initMousewheel(); + initTouch(); + + if (settings.enableKeyboardNavigation) { + initKeyboardNav(); + } + if (settings.clickOnTrack) { + initClickOnTrack(); + } + + observeHash(); + if (settings.hijackInternalLinks) { + hijackInternalLinks(); + } + } + + if (settings.autoReinitialise && !reinitialiseInterval) { + reinitialiseInterval = setInterval( + function() + { + initialise(settings); + }, + settings.autoReinitialiseDelay + ); + } else if (!settings.autoReinitialise && reinitialiseInterval) { + clearInterval(reinitialiseInterval); + } + + originalScrollTop && elem.scrollTop(0) && scrollToY(originalScrollTop, false); + originalScrollLeft && elem.scrollLeft(0) && scrollToX(originalScrollLeft, false); + + elem.trigger('jsp-initialised', [isScrollableH || isScrollableV]); + } + + function initialiseVerticalScroll() + { + if (isScrollableV) { + + container.append( + $('
').append( + $('
'), + $('
').append( + $('
').append( + $('
'), + $('
') + ) + ), + $('
') + ) + ); + + verticalBar = container.find('>.jspVerticalBar'); + verticalTrack = verticalBar.find('>.jspTrack'); + verticalDrag = verticalTrack.find('>.jspDrag'); + + if (settings.showArrows) { + arrowUp = $('').bind( + 'mousedown.jsp', getArrowScroll(0, -1) + ).bind('click.jsp', nil); + arrowDown = $('').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', nil); + + 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(); + } + } + + 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) + try { + if (verticalBar.position().left === 0) { + pane.css('margin-left', scrollbarWidth + 'px'); + } + } catch (err) { + } + } + + function initialiseHorizontalScroll() + { + if (isScrollableH) { + + container.append( + $('
').append( + $('
'), + $('
').append( + $('
').append( + $('
'), + $('
') + ) + ), + $('
') + ) + ); + + horizontalBar = container.find('>.jspHorizontalBar'); + horizontalTrack = horizontalBar.find('>.jspTrack'); + horizontalDrag = horizontalTrack.find('>.jspDrag'); + + if (settings.showArrows) { + arrowLeft = $('').bind( + 'mousedown.jsp', getArrowScroll(-1, 0) + ).bind('click.jsp', nil); + arrowRight = $('').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', nil); + + 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(); + } + } + + 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( + $('
').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 = Math.ceil(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; + _positionDragX(horizontalDragPosition); // To update the state for the arrow buttons + } + if (isScrollableV) { + verticalDragHeight = Math.ceil(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; + _positionDragY(verticalDragPosition); // To update the state for the arrow buttons + } + } + + 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, + scrollTimeout, + isFirst = true, + doScroll = function() + { + if (dirX !== 0) { + jsp.scrollByX(dirX * settings.arrowButtonSpeed); + } + if (dirY !== 0) { + jsp.scrollByY(dirY * settings.arrowButtonSpeed); + } + scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.arrowRepeatFreq); + isFirst = false; + }; + + doScroll(); + + eve = ele ? 'mouseout.jsp' : 'mouseup.jsp'; + ele = ele || $('html'); + ele.bind( + eve, + function() + { + arrow.removeClass('jspActive'); + scrollTimeout && clearTimeout(scrollTimeout); + scrollTimeout = null; + ele.unbind(eve); + } + ); + } + + function initClickOnTrack() + { + removeClickOnTrack(); + if (isScrollableV) { + verticalTrack.bind( + 'mousedown.jsp', + function(e) + { + if (e.originalTarget === undefined || e.originalTarget == e.currentTarget) { + var clickedTrack = $(this), + offset = clickedTrack.offset(), + direction = e.pageY - offset.top - verticalDragPosition, + scrollTimeout, + isFirst = true, + doScroll = function() + { + var offset = clickedTrack.offset(), + pos = e.pageY - offset.top - verticalDragHeight / 2, + contentDragY = paneHeight * settings.scrollPagePercent, + dragY = dragMaxY * contentDragY / (contentHeight - paneHeight); + if (direction < 0) { + if (verticalDragPosition - dragY > pos) { + jsp.scrollByY(-contentDragY); + } else { + positionDragY(pos); + } + } else if (direction > 0) { + if (verticalDragPosition + dragY < pos) { + jsp.scrollByY(contentDragY); + } else { + positionDragY(pos); + } + } else { + cancelClick(); + return; + } + scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.trackClickRepeatFreq); + isFirst = false; + }, + cancelClick = function() + { + scrollTimeout && clearTimeout(scrollTimeout); + scrollTimeout = null; + $(document).unbind('mouseup.jsp', cancelClick); + }; + doScroll(); + $(document).bind('mouseup.jsp', cancelClick); + return false; + } + } + ); + } + + if (isScrollableH) { + horizontalTrack.bind( + 'mousedown.jsp', + function(e) + { + if (e.originalTarget === undefined || e.originalTarget == e.currentTarget) { + var clickedTrack = $(this), + offset = clickedTrack.offset(), + direction = e.pageX - offset.left - horizontalDragPosition, + scrollTimeout, + isFirst = true, + doScroll = function() + { + var offset = clickedTrack.offset(), + pos = e.pageX - offset.left - horizontalDragWidth / 2, + contentDragX = paneWidth * settings.scrollPagePercent, + dragX = dragMaxX * contentDragX / (contentWidth - paneWidth); + if (direction < 0) { + if (horizontalDragPosition - dragX > pos) { + jsp.scrollByX(-contentDragX); + } else { + positionDragX(pos); + } + } else if (direction > 0) { + if (horizontalDragPosition + dragX < pos) { + jsp.scrollByX(contentDragX); + } else { + positionDragX(pos); + } + } else { + cancelClick(); + return; + } + scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.trackClickRepeatFreq); + isFirst = false; + }, + cancelClick = function() + { + scrollTimeout && clearTimeout(scrollTimeout); + scrollTimeout = null; + $(document).unbind('mouseup.jsp', cancelClick); + }; + doScroll(); + $(document).bind('mouseup.jsp', cancelClick); + return false; + } + } + ); + } + } + + function removeClickOnTrack() + { + if (horizontalTrack) { + horizontalTrack.unbind('mousedown.jsp'); + } + if (verticalTrack) { + verticalTrack.unbind('mousedown.jsp'); + } + } + + function cancelDrag() + { + $('html').unbind('dragstart.jsp selectstart.jsp mousemove.jsp mouseup.jsp mouseleave.jsp'); + + if (verticalDrag) { + verticalDrag.removeClass('jspActive'); + } + if (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 || 0; + + 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]).trigger('scroll'); + } + + 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 ||0; + + var isAtLeft = horizontalDragPosition === 0, + isAtRight = horizontalDragPosition == dragMaxX, + 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]).trigger('scroll'); + } + + 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, eleWidth, eleTop = 0, eleLeft = 0, viewportTop, viewportLeft, maxVisibleEleTop, maxVisibleEleLeft, destY, destX; + + // 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(); + eleWidth= e.outerWidth(); + + container.scrollTop(0); + container.scrollLeft(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; + eleLeft += e.position().left; + 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.horizontalGutter; + } else if (eleTop + eleHeight > maxVisibleEleTop) { // element is below viewport + destY = eleTop - paneHeight + eleHeight + settings.horizontalGutter; + } + if (!isNaN(destY)) { + scrollToY(destY, animate); + } + + viewportLeft = contentPositionX(); + maxVisibleEleLeft = viewportLeft + paneWidth; + if (eleLeft < viewportLeft || stickToTop) { // element is to the left of viewport + destX = eleLeft - settings.horizontalGutter; + } else if (eleLeft + eleWidth > maxVisibleEleLeft) { // element is to the right viewport + destX = eleLeft - paneWidth + eleWidth + settings.horizontalGutter; + } + if (!isNaN(destX)) { + scrollToX(destX, animate); + } + + } + + function contentPositionX() + { + return -pane.position().left; + } + + function contentPositionY() + { + return -pane.position().top; + } + + function isCloseToBottom() + { + var scrollableHeight = contentHeight - paneHeight; + return (scrollableHeight > 20) && (scrollableHeight - contentPositionY() < 10); + } + + function isCloseToRight() + { + var scrollableWidth = contentWidth - paneWidth; + return (scrollableWidth > 20) && (scrollableWidth - contentPositionX() < 10); + } + + function initMousewheel() + { + container.unbind(mwEvent).bind( + mwEvent, + function (event, delta, deltaX, deltaY) { + + if (!horizontalDragPosition) horizontalDragPosition = 0; + if (!verticalDragPosition) verticalDragPosition = 0; + + var dX = horizontalDragPosition, dY = verticalDragPosition, factor = event.deltaFactor || settings.mouseWheelSpeed; + jsp.scrollBy(deltaX * factor, -deltaY * factor, 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.find(':input,a').unbind('focus.jsp').bind( + 'focus.jsp', + function(e) + { + scrollToElement(e.target, false); + } + ); + } + + function removeFocusHandler() + { + pane.find(':input,a').unbind('focus.jsp'); + } + + function initKeyboardNav() + { + var keyDown, elementHasScrolled, validParents = []; + isScrollableH && validParents.push(horizontalBar[0]); + isScrollableV && validParents.push(verticalBar[0]); + + // IE also focuses elements that don't have tabindex set. + pane.focus( + function() + { + elem.focus(); + } + ); + + elem.attr('tabindex', 0) + .unbind('keydown.jsp keypress.jsp') + .bind( + 'keydown.jsp', + function(e) + { + if (e.target !== this && !(validParents.length && $(e.target).closest(validParents).length)){ + return; + } + var dX = horizontalDragPosition, dY = verticalDragPosition; + switch(e.keyCode) { + case 40: // down + case 38: // up + case 34: // page down + case 32: // space + case 33: // page up + case 39: // right + case 37: // left + keyDown = e.keyCode; + keyDownHandler(); + break; + case 35: // end + scrollToY(contentHeight - paneHeight); + keyDown = null; + break; + case 36: // home + scrollToY(0); + keyDown = null; + break; + } + + elementHasScrolled = e.keyCode == keyDown && dX != horizontalDragPosition || dY != verticalDragPosition; + return !elementHasScrolled; + } + ).bind( + 'keypress.jsp', // For FF/ OSX so that we can cancel the repeat key presses if the JSP scrolls... + function(e) + { + if (e.keyCode == keyDown) { + keyDownHandler(); + } + return !elementHasScrolled; + } + ); + + 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 keyDownHandler() + { + var dX = horizontalDragPosition, dY = verticalDragPosition; + switch(keyDown) { + case 40: // down + jsp.scrollByY(settings.keyboardSpeed, false); + break; + case 38: // up + jsp.scrollByY(-settings.keyboardSpeed, false); + break; + case 34: // page down + case 32: // space + jsp.scrollByY(paneHeight * settings.scrollPagePercent, false); + break; + case 33: // page up + jsp.scrollByY(-paneHeight * settings.scrollPagePercent, false); + break; + case 39: // right + jsp.scrollByX(settings.keyboardSpeed, false); + break; + case 37: // left + jsp.scrollByX(-settings.keyboardSpeed, false); + break; + } + + elementHasScrolled = dX != horizontalDragPosition || dY != verticalDragPosition; + return elementHasScrolled; + } + } + + function removeKeyboardNav() + { + elem.attr('tabindex', '-1') + .removeAttr('tabindex') + .unbind('keydown.jsp keypress.jsp'); + } + + function observeHash() + { + if (location.hash && location.hash.length > 1) { + var e, + retryInt, + hash = escape(location.hash.substr(1)) // hash must be escaped to prevent XSS + ; + try { + e = $('#' + hash + ', a[name="' + hash + '"]'); + } catch (err) { + return; + } + + if (e.length && pane.find(hash)) { + // 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(e, true); + $(document).scrollTop(container.position().top); + clearInterval(retryInt); + } + }, + 50 + ); + } else { + scrollToElement(e, true); + $(document).scrollTop(container.position().top); + } + } + } + } + + function hijackInternalLinks() + { + // only register the link handler once + if ($(document.body).data('jspHijack')) { + return; + } + + // remember that the handler was bound + $(document.body).data('jspHijack', true); + + // use live handler to also capture newly created links + $(document.body).delegate('a[href*=#]', 'click', function(event) { + // does the link point to the same page? + // this also takes care of cases with a -Tag or Links not starting with the hash # + // e.g. when the current url already is index.html + var href = this.href.substr(0, this.href.indexOf('#')), + locationHref = location.href, + hash, + element, + container, + jsp, + scrollTop, + elementTop; + if (location.href.indexOf('#') !== -1) { + locationHref = location.href.substr(0, location.href.indexOf('#')); + } + if (href !== locationHref) { + // the link points to another page + return; + } + + // check if jScrollPane should handle this click event + hash = escape(this.href.substr(this.href.indexOf('#') + 1)); + + // find the element on the page + element; + try { + element = $('#' + hash + ', a[name="' + hash + '"]'); + } catch (e) { + // hash is not a valid jQuery identifier + return; + } + + if (!element.length) { + // this link does not point to an element on this page + return; + } + + container = element.closest('.jspScrollable'); + jsp = container.data('jsp'); + + // jsp might be another jsp instance than the one, that bound this event + // remember: this event is only bound once for all instances. + jsp.scrollToElement(element, true); + + if (container[0].scrollIntoView) { + // also scroll to the top of the container (if it is not visible) + scrollTop = $(window).scrollTop(); + elementTop = element.offset().top; + if (elementTop < scrollTop || elementTop > scrollTop + $(window).height()) { + container[0].scrollIntoView(); + } + } + + // jsp handled this event, prevent the browser default (scrolling :P) + event.preventDefault(); + }); + } + + // Init touch on iPad, iPhone, iPod, Android + function initTouch() + { + var startX, + startY, + touchStartX, + touchStartY, + moved, + moving = false; + + container.unbind('touchstart.jsp touchmove.jsp touchend.jsp click.jsp-touchclick').bind( + 'touchstart.jsp', + function(e) + { + var touch = e.originalEvent.touches[0]; + startX = contentPositionX(); + startY = contentPositionY(); + touchStartX = touch.pageX; + touchStartY = touch.pageY; + moved = false; + moving = true; + } + ).bind( + 'touchmove.jsp', + function(ev) + { + if(!moving) { + return; + } + + var touchPos = ev.originalEvent.touches[0], + dX = horizontalDragPosition, dY = verticalDragPosition; + + jsp.scrollTo(startX + touchStartX - touchPos.pageX, startY + touchStartY - touchPos.pageY); + + moved = moved || Math.abs(touchStartX - touchPos.pageX) > 5 || Math.abs(touchStartY - touchPos.pageY) > 5; + + // return true if there was no movement so rest of screen can scroll + return dX == horizontalDragPosition && dY == verticalDragPosition; + } + ).bind( + 'touchend.jsp', + function(e) + { + moving = false; + /*if(moved) { + return false; + }*/ + } + ).bind( + 'click.jsp-touchclick', + function(e) + { + if(moved) { + moved = false; + return false; + } + } + ); + } + + function destroy(){ + var currentY = contentPositionY(), + currentX = contentPositionX(); + elem.removeClass('jspScrollable').unbind('.jsp'); + elem.replaceWith(originalElement.append(pane.children())); + originalElement.scrollTop(currentY); + originalElement.scrollLeft(currentX); + + // clear reinitialize timer if active + if (reinitialiseInterval) { + clearInterval(reinitialiseInterval); + } + } + + // 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({}, settings, s); + 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 to the specified percentage of its maximum horizontal scroll position. animate + // is optional and if not passed then the value of animateScroll from the settings object this + // jScrollPane was initialised with is used. + scrollToPercentX: function(destPercentX, animate) + { + scrollToX(destPercentX * (contentWidth - paneWidth), animate); + }, + // Scrolls the pane to the specified percentage of its maximum vertical scroll position. animate + // is optional and if not passed then the value of animateScroll from the settings object this + // jScrollPane was initialised with is used. + scrollToPercentY: function(destPercentY, animate) + { + scrollToY(destPercentY * (contentHeight - paneHeight), 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() + Math[deltaX<0 ? 'floor' : 'ceil'](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() + Math[deltaY<0 ? 'floor' : 'ceil'](deltaY), + percentScrolled = destY / (contentHeight - paneHeight); + positionDragY(percentScrolled * dragMaxY, animate); + }, + // Positions the horizontal drag at the specified x position (and updates the viewport to reflect + // this). animate is optional and if not passed then the value of animateScroll from the settings + // object this jScrollPane was initialised with is used. + positionDragX: function(x, animate) + { + positionDragX(x, animate); + }, + // Positions the vertical drag at the specified y position (and updates the viewport to reflect + // this). animate is optional and if not passed then the value of animateScroll from the settings + // object this jScrollPane was initialised with is used. + positionDragY: function(y, animate) + { + positionDragY(y, 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, + 'easing' : 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 the width of the content within the scroll pane. + getContentWidth: function() + { + return contentWidth; + }, + // Returns the height of the content within the scroll pane. + getContentHeight: function() + { + return contentHeight; + }, + // Returns the horizontal position of the viewport within the pane content. + getPercentScrolledX: function() + { + return contentPositionX() / (contentWidth - paneWidth); + }, + // Returns the vertical position of the viewport within the pane content. + getPercentScrolledY: function() + { + return contentPositionY() / (contentHeight - paneHeight); + }, + // 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: $.noop, + // Removes the jScrollPane and returns the page to the state it was in before jScrollPane was + // initialised. + destroy: function() + { + destroy(); + } + } + ); + + initialise(s); + } + + // Pluginifying code... + settings = $.extend({}, $.fn.jScrollPane.defaults, settings); + + // Apply default speed + $.each(['arrowButtonSpeed', 'trackClickSpeed', 'keyboardSpeed'], function() { + settings[this] = settings[this] || settings.speed; + }); + + return this.each( + function() + { + var elem = $(this), jspApi = elem.data('jsp'); + if (jspApi) { + jspApi.reinitialise(settings); + } else { + $("script",elem).filter('[type="text/javascript"],:not([type])').remove(); + jspApi = new JScrollPane(elem, settings); + elem.data('jsp', jspApi); + } + } + ); + }; + + $.fn.jScrollPane.defaults = { + showArrows : false, + maintainPosition : true, + stickToBottom : false, + stickToRight : false, + clickOnTrack : true, + autoReinitialise : false, + autoReinitialiseDelay : 500, + verticalDragMinHeight : 0, + verticalDragMaxHeight : 99999, + horizontalDragMinWidth : 0, + horizontalDragMaxWidth : 99999, + contentWidth : undefined, + animateScroll : false, + animateDuration : 300, + animateEase : 'linear', + hijackInternalLinks : false, + verticalGutter : 4, + horizontalGutter : 4, + mouseWheelSpeed : 3, + arrowButtonSpeed : 0, + arrowRepeatFreq : 50, + arrowScrollOnHover : false, + trackClickSpeed : 0, + trackClickRepeatFreq : 70, + verticalArrowPositions : 'split', + horizontalArrowPositions : 'split', + enableKeyboardNavigation : true, + hideFocus : false, + keyboardSpeed : 0, + initialDelay : 300, // Delay before starting repeating + speed : 30, // Default speed when others falsey + scrollPagePercent : .8 // Percent of visible area scrolled when pageUp/Down or track area pressed + }; + +})); diff --git a/ajax/libs/jScrollPane/2.0.21/script/jquery.jscrollpane.min.js b/ajax/libs/jScrollPane/2.0.21/script/jquery.jscrollpane.min.js new file mode 100644 index 00000000000000..b7686336a9e436 --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.21/script/jquery.jscrollpane.min.js @@ -0,0 +1,8 @@ +/*! + * jScrollPane - v2.0.21 - 2015-02-24 + * http://jscrollpane.kelvinluck.com/ + * + * Copyright (c) 2014 Kelvin Luck + * Dual licensed under the MIT or GPL licenses. + */ +!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof exports?module.exports=a(require("jquery")):a(jQuery)}(function(a){a.fn.jScrollPane=function(b){function c(b,c){function d(c){var f,h,j,k,l,o,p=!1,q=!1;if(N=c,void 0===O)l=b.scrollTop(),o=b.scrollLeft(),b.css({overflow:"hidden",padding:0}),P=b.innerWidth()+rb,Q=b.innerHeight(),b.width(P),O=a('
').css("padding",qb).append(b.children()),R=a('
').css({width:P+"px",height:Q+"px"}).append(O).appendTo(b);else{if(b.css("width",""),p=N.stickToBottom&&A(),q=N.stickToRight&&B(),k=b.innerWidth()+rb!=P||b.outerHeight()!=Q,k&&(P=b.innerWidth()+rb,Q=b.innerHeight(),R.css({width:P+"px",height:Q+"px"})),!k&&sb==S&&O.outerHeight()==T)return void b.width(P);sb=S,O.css("width",""),b.width(P),R.find(">.jspVerticalBar,>.jspHorizontalBar").remove().end()}O.css("overflow","auto"),S=c.contentWidth?c.contentWidth:O[0].scrollWidth,T=O[0].scrollHeight,O.css("overflow",""),U=S/P,V=T/Q,W=V>1,X=U>1,X||W?(b.addClass("jspScrollable"),f=N.maintainPosition&&($||bb),f&&(h=y(),j=z()),e(),g(),i(),f&&(w(q?S-P:h,!1),v(p?T-Q:j,!1)),F(),C(),L(),N.enableKeyboardNavigation&&H(),N.clickOnTrack&&m(),J(),N.hijackInternalLinks&&K()):(b.removeClass("jspScrollable"),O.css({top:0,left:0,width:R.width()-rb}),D(),G(),I(),n()),N.autoReinitialise&&!pb?pb=setInterval(function(){d(N)},N.autoReinitialiseDelay):!N.autoReinitialise&&pb&&clearInterval(pb),l&&b.scrollTop(0)&&v(l,!1),o&&b.scrollLeft(0)&&w(o,!1),b.trigger("jsp-initialised",[X||W])}function e(){W&&(R.append(a('
').append(a('
'),a('
').append(a('
').append(a('
'),a('
'))),a('
'))),cb=R.find(">.jspVerticalBar"),db=cb.find(">.jspTrack"),Y=db.find(">.jspDrag"),N.showArrows&&(hb=a('').bind("mousedown.jsp",k(0,-1)).bind("click.jsp",E),ib=a('').bind("mousedown.jsp",k(0,1)).bind("click.jsp",E),N.arrowScrollOnHover&&(hb.bind("mouseover.jsp",k(0,-1,hb)),ib.bind("mouseover.jsp",k(0,1,ib))),j(db,N.verticalArrowPositions,hb,ib)),fb=Q,R.find(">.jspVerticalBar>.jspCap:visible,>.jspVerticalBar>.jspArrow").each(function(){fb-=a(this).outerHeight()}),Y.hover(function(){Y.addClass("jspHover")},function(){Y.removeClass("jspHover")}).bind("mousedown.jsp",function(b){a("html").bind("dragstart.jsp selectstart.jsp",E),Y.addClass("jspActive");var c=b.pageY-Y.position().top;return a("html").bind("mousemove.jsp",function(a){p(a.pageY-c,!1)}).bind("mouseup.jsp mouseleave.jsp",o),!1}),f())}function f(){db.height(fb+"px"),$=0,eb=N.verticalGutter+db.outerWidth(),O.width(P-eb-rb);try{0===cb.position().left&&O.css("margin-left",eb+"px")}catch(a){}}function g(){X&&(R.append(a('
').append(a('
'),a('
').append(a('
').append(a('
'),a('
'))),a('
'))),jb=R.find(">.jspHorizontalBar"),kb=jb.find(">.jspTrack"),_=kb.find(">.jspDrag"),N.showArrows&&(nb=a('').bind("mousedown.jsp",k(-1,0)).bind("click.jsp",E),ob=a('').bind("mousedown.jsp",k(1,0)).bind("click.jsp",E),N.arrowScrollOnHover&&(nb.bind("mouseover.jsp",k(-1,0,nb)),ob.bind("mouseover.jsp",k(1,0,ob))),j(kb,N.horizontalArrowPositions,nb,ob)),_.hover(function(){_.addClass("jspHover")},function(){_.removeClass("jspHover")}).bind("mousedown.jsp",function(b){a("html").bind("dragstart.jsp selectstart.jsp",E),_.addClass("jspActive");var c=b.pageX-_.position().left;return a("html").bind("mousemove.jsp",function(a){r(a.pageX-c,!1)}).bind("mouseup.jsp mouseleave.jsp",o),!1}),lb=R.innerWidth(),h())}function h(){R.find(">.jspHorizontalBar>.jspCap:visible,>.jspHorizontalBar>.jspArrow").each(function(){lb-=a(this).outerWidth()}),kb.width(lb+"px"),bb=0}function i(){if(X&&W){var b=kb.outerHeight(),c=db.outerWidth();fb-=b,a(jb).find(">.jspCap:visible,>.jspArrow").each(function(){lb+=a(this).outerWidth()}),lb-=c,Q-=c,P-=b,kb.parent().append(a('
').css("width",b+"px")),f(),h()}X&&O.width(R.outerWidth()-rb+"px"),T=O.outerHeight(),V=T/Q,X&&(mb=Math.ceil(1/U*lb),mb>N.horizontalDragMaxWidth?mb=N.horizontalDragMaxWidth:mbN.verticalDragMaxHeight?gb=N.verticalDragMaxHeight:gbf)$-k>e?tb.scrollByY(-j):p(e);else{if(!(f>0))return void i();e>$+k?tb.scrollByY(j):p(e)}c=setTimeout(h,g?N.initialDelay:N.trackClickRepeatFreq),g=!1},i=function(){c&&clearTimeout(c),c=null,a(document).unbind("mouseup.jsp",i)};return h(),a(document).bind("mouseup.jsp",i),!1}}),X&&kb.bind("mousedown.jsp",function(b){if(void 0===b.originalTarget||b.originalTarget==b.currentTarget){var c,d=a(this),e=d.offset(),f=b.pageX-e.left-bb,g=!0,h=function(){var a=d.offset(),e=b.pageX-a.left-mb/2,j=P*N.scrollPagePercent,k=ab*j/(S-P);if(0>f)bb-k>e?tb.scrollByX(-j):r(e);else{if(!(f>0))return void i();e>bb+k?tb.scrollByX(j):r(e)}c=setTimeout(h,g?N.initialDelay:N.trackClickRepeatFreq),g=!1},i=function(){c&&clearTimeout(c),c=null,a(document).unbind("mouseup.jsp",i)};return h(),a(document).bind("mouseup.jsp",i),!1}})}function n(){kb&&kb.unbind("mousedown.jsp"),db&&db.unbind("mousedown.jsp")}function o(){a("html").unbind("dragstart.jsp selectstart.jsp mousemove.jsp mouseup.jsp mouseleave.jsp"),Y&&Y.removeClass("jspActive"),_&&_.removeClass("jspActive")}function p(a,b){W&&(0>a?a=0:a>Z&&(a=Z),void 0===b&&(b=N.animateScroll),b?tb.animate(Y,"top",a,q):(Y.css("top",a),q(a)))}function q(a){void 0===a&&(a=Y.position().top),R.scrollTop(0),$=a||0;var c=0===$,d=$==Z,e=a/Z,f=-e*(T-Q);(ub!=c||wb!=d)&&(ub=c,wb=d,b.trigger("jsp-arrow-change",[ub,wb,vb,xb])),t(c,d),O.css("top",f),b.trigger("jsp-scroll-y",[-f,c,d]).trigger("scroll")}function r(a,b){X&&(0>a?a=0:a>ab&&(a=ab),void 0===b&&(b=N.animateScroll),b?tb.animate(_,"left",a,s):(_.css("left",a),s(a)))}function s(a){void 0===a&&(a=_.position().left),R.scrollTop(0),bb=a||0;var c=0===bb,d=bb==ab,e=a/ab,f=-e*(S-P);(vb!=c||xb!=d)&&(vb=c,xb=d,b.trigger("jsp-arrow-change",[ub,wb,vb,xb])),u(c,d),O.css("left",f),b.trigger("jsp-scroll-x",[-f,c,d]).trigger("scroll")}function t(a,b){N.showArrows&&(hb[a?"addClass":"removeClass"]("jspDisabled"),ib[b?"addClass":"removeClass"]("jspDisabled"))}function u(a,b){N.showArrows&&(nb[a?"addClass":"removeClass"]("jspDisabled"),ob[b?"addClass":"removeClass"]("jspDisabled"))}function v(a,b){var c=a/(T-Q);p(c*Z,b)}function w(a,b){var c=a/(S-P);r(c*ab,b)}function x(b,c,d){var e,f,g,h,i,j,k,l,m,n=0,o=0;try{e=a(b)}catch(p){return}for(f=e.outerHeight(),g=e.outerWidth(),R.scrollTop(0),R.scrollLeft(0);!e.is(".jspPane");)if(n+=e.position().top,o+=e.position().left,e=e.offsetParent(),/^body|html$/i.test(e[0].nodeName))return;h=z(),j=h+Q,h>n||c?l=n-N.horizontalGutter:n+f>j&&(l=n-Q+f+N.horizontalGutter),isNaN(l)||v(l,d),i=y(),k=i+P,i>o||c?m=o-N.horizontalGutter:o+g>k&&(m=o-P+g+N.horizontalGutter),isNaN(m)||w(m,d)}function y(){return-O.position().left}function z(){return-O.position().top}function A(){var a=T-Q;return a>20&&a-z()<10}function B(){var a=S-P;return a>20&&a-y()<10}function C(){R.unbind(zb).bind(zb,function(a,b,c,d){bb||(bb=0),$||($=0);var e=bb,f=$,g=a.deltaFactor||N.mouseWheelSpeed;return tb.scrollBy(c*g,-d*g,!1),e==bb&&f==$})}function D(){R.unbind(zb)}function E(){return!1}function F(){O.find(":input,a").unbind("focus.jsp").bind("focus.jsp",function(a){x(a.target,!1)})}function G(){O.find(":input,a").unbind("focus.jsp")}function H(){function c(){var a=bb,b=$;switch(d){case 40:tb.scrollByY(N.keyboardSpeed,!1);break;case 38:tb.scrollByY(-N.keyboardSpeed,!1);break;case 34:case 32:tb.scrollByY(Q*N.scrollPagePercent,!1);break;case 33:tb.scrollByY(-Q*N.scrollPagePercent,!1);break;case 39:tb.scrollByX(N.keyboardSpeed,!1);break;case 37:tb.scrollByX(-N.keyboardSpeed,!1)}return e=a!=bb||b!=$}var d,e,f=[];X&&f.push(jb[0]),W&&f.push(cb[0]),O.focus(function(){b.focus()}),b.attr("tabindex",0).unbind("keydown.jsp keypress.jsp").bind("keydown.jsp",function(b){if(b.target===this||f.length&&a(b.target).closest(f).length){var g=bb,h=$;switch(b.keyCode){case 40:case 38:case 34:case 32:case 33:case 39:case 37:d=b.keyCode,c();break;case 35:v(T-Q),d=null;break;case 36:v(0),d=null}return e=b.keyCode==d&&g!=bb||h!=$,!e}}).bind("keypress.jsp",function(a){return a.keyCode==d&&c(),!e}),N.hideFocus?(b.css("outline","none"),"hideFocus"in R[0]&&b.attr("hideFocus",!0)):(b.css("outline",""),"hideFocus"in R[0]&&b.attr("hideFocus",!1))}function I(){b.attr("tabindex","-1").removeAttr("tabindex").unbind("keydown.jsp keypress.jsp")}function J(){if(location.hash&&location.hash.length>1){var b,c,d=escape(location.hash.substr(1));try{b=a("#"+d+', a[name="'+d+'"]')}catch(e){return}b.length&&O.find(d)&&(0===R.scrollTop()?c=setInterval(function(){R.scrollTop()>0&&(x(b,!0),a(document).scrollTop(R.position().top),clearInterval(c))},50):(x(b,!0),a(document).scrollTop(R.position().top)))}}function K(){a(document.body).data("jspHijack")||(a(document.body).data("jspHijack",!0),a(document.body).delegate("a[href*=#]","click",function(b){var c,d,e,f,g,h,i=this.href.substr(0,this.href.indexOf("#")),j=location.href;if(-1!==location.href.indexOf("#")&&(j=location.href.substr(0,location.href.indexOf("#"))),i===j){c=escape(this.href.substr(this.href.indexOf("#")+1));try{d=a("#"+c+', a[name="'+c+'"]')}catch(k){return}d.length&&(e=d.closest(".jspScrollable"),f=e.data("jsp"),f.scrollToElement(d,!0),e[0].scrollIntoView&&(g=a(window).scrollTop(),h=d.offset().top,(g>h||h>g+a(window).height())&&e[0].scrollIntoView()),b.preventDefault())}}))}function L(){var a,b,c,d,e,f=!1;R.unbind("touchstart.jsp touchmove.jsp touchend.jsp click.jsp-touchclick").bind("touchstart.jsp",function(g){var h=g.originalEvent.touches[0];a=y(),b=z(),c=h.pageX,d=h.pageY,e=!1,f=!0}).bind("touchmove.jsp",function(g){if(f){var h=g.originalEvent.touches[0],i=bb,j=$;return tb.scrollTo(a+c-h.pageX,b+d-h.pageY),e=e||Math.abs(c-h.pageX)>5||Math.abs(d-h.pageY)>5,i==bb&&j==$}}).bind("touchend.jsp",function(){f=!1}).bind("click.jsp-touchclick",function(){return e?(e=!1,!1):void 0})}function M(){var a=z(),c=y();b.removeClass("jspScrollable").unbind(".jsp"),b.replaceWith(yb.append(O.children())),yb.scrollTop(a),yb.scrollLeft(c),pb&&clearInterval(pb)}var N,O,P,Q,R,S,T,U,V,W,X,Y,Z,$,_,ab,bb,cb,db,eb,fb,gb,hb,ib,jb,kb,lb,mb,nb,ob,pb,qb,rb,sb,tb=this,ub=!0,vb=!0,wb=!1,xb=!1,yb=b.clone(!1,!1).empty(),zb=a.fn.mwheelIntent?"mwheelIntent.jsp":"mousewheel.jsp";"border-box"===b.css("box-sizing")?(qb=0,rb=0):(qb=b.css("paddingTop")+" "+b.css("paddingRight")+" "+b.css("paddingBottom")+" "+b.css("paddingLeft"),rb=(parseInt(b.css("paddingLeft"),10)||0)+(parseInt(b.css("paddingRight"),10)||0)),a.extend(tb,{reinitialise:function(b){b=a.extend({},N,b),d(b)},scrollToElement:function(a,b,c){x(a,b,c)},scrollTo:function(a,b,c){w(a,c),v(b,c)},scrollToX:function(a,b){w(a,b)},scrollToY:function(a,b){v(a,b)},scrollToPercentX:function(a,b){w(a*(S-P),b)},scrollToPercentY:function(a,b){v(a*(T-Q),b)},scrollBy:function(a,b,c){tb.scrollByX(a,c),tb.scrollByY(b,c)},scrollByX:function(a,b){var c=y()+Math[0>a?"floor":"ceil"](a),d=c/(S-P);r(d*ab,b)},scrollByY:function(a,b){var c=z()+Math[0>a?"floor":"ceil"](a),d=c/(T-Q);p(d*Z,b)},positionDragX:function(a,b){r(a,b)},positionDragY:function(a,b){p(a,b)},animate:function(a,b,c,d){var e={};e[b]=c,a.animate(e,{duration:N.animateDuration,easing:N.animateEase,queue:!1,step:d})},getContentPositionX:function(){return y()},getContentPositionY:function(){return z()},getContentWidth:function(){return S},getContentHeight:function(){return T},getPercentScrolledX:function(){return y()/(S-P)},getPercentScrolledY:function(){return z()/(T-Q)},getIsScrollableH:function(){return X},getIsScrollableV:function(){return W},getContentPane:function(){return O},scrollToBottom:function(a){p(Z,a)},hijackInternalLinks:a.noop,destroy:function(){M()}}),d(c)}return b=a.extend({},a.fn.jScrollPane.defaults,b),a.each(["arrowButtonSpeed","trackClickSpeed","keyboardSpeed"],function(){b[this]=b[this]||b.speed}),this.each(function(){var d=a(this),e=d.data("jsp");e?e.reinitialise(b):(a("script",d).filter('[type="text/javascript"],:not([type])').remove(),e=new c(d,b),d.data("jsp",e))})},a.fn.jScrollPane.defaults={showArrows:!1,maintainPosition:!0,stickToBottom:!1,stickToRight:!1,clickOnTrack:!0,autoReinitialise:!1,autoReinitialiseDelay:500,verticalDragMinHeight:0,verticalDragMaxHeight:99999,horizontalDragMinWidth:0,horizontalDragMaxWidth:99999,contentWidth:void 0,animateScroll:!1,animateDuration:300,animateEase:"linear",hijackInternalLinks:!1,verticalGutter:4,horizontalGutter:4,mouseWheelSpeed:3,arrowButtonSpeed:0,arrowRepeatFreq:50,arrowScrollOnHover:!1,trackClickSpeed:0,trackClickRepeatFreq:70,verticalArrowPositions:"split",horizontalArrowPositions:"split",enableKeyboardNavigation:!0,hideFocus:!1,keyboardSpeed:0,initialDelay:300,speed:30,scrollPagePercent:.8}}); \ No newline at end of file diff --git a/ajax/libs/jScrollPane/2.0.21/style/jquery.jscrollpane.css b/ajax/libs/jScrollPane/2.0.21/style/jquery.jscrollpane.css new file mode 100644 index 00000000000000..57ccca25316d53 --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.21/style/jquery.jscrollpane.css @@ -0,0 +1,115 @@ +/* + * CSS Styles that are needed by jScrollPane for it to operate correctly. + * + * Include this stylesheet in your site or copy and paste the styles below into your stylesheet - jScrollPane + * may not operate correctly without them. + */ + +.jspContainer +{ + overflow: hidden; + position: relative; +} + +.jspPane +{ + position: absolute; +} + +.jspVerticalBar +{ + position: absolute; + top: 0; + right: 0; + width: 16px; + height: 100%; + background: red; +} + +.jspHorizontalBar +{ + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 16px; + background: red; +} + +.jspCap +{ + display: none; +} + +.jspHorizontalBar .jspCap +{ + float: left; +} + +.jspTrack +{ + background: #dde; + position: relative; +} + +.jspDrag +{ + background: #bbd; + position: relative; + top: 0; + left: 0; + cursor: pointer; +} + +.jspHorizontalBar .jspTrack, +.jspHorizontalBar .jspDrag +{ + float: left; + height: 100%; +} + +.jspArrow +{ + background: #50506d; + text-indent: -20000px; + display: block; + cursor: pointer; + padding: 0; + margin: 0; +} + +.jspArrow.jspDisabled +{ + cursor: default; + background: #80808d; +} + +.jspVerticalBar .jspArrow +{ + height: 16px; +} + +.jspHorizontalBar .jspArrow +{ + width: 16px; + float: left; + height: 100%; +} + +.jspVerticalBar .jspArrow:focus +{ + outline: none; +} + +.jspCorner +{ + background: #eeeef4; + float: left; + height: 100%; +} + +/* Yuk! CSS Hack for IE6 3 pixel bug :( */ +* html .jspCorner +{ + margin: 0 -3px 0 0; +} \ No newline at end of file diff --git a/ajax/libs/jScrollPane/2.0.21/style/jquery.jscrollpane.min.css b/ajax/libs/jScrollPane/2.0.21/style/jquery.jscrollpane.min.css new file mode 100644 index 00000000000000..9a0eed96f15c3a --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.21/style/jquery.jscrollpane.min.css @@ -0,0 +1 @@ +.jspContainer{overflow:hidden;position:relative}.jspPane{position:absolute}.jspVerticalBar{position:absolute;top:0;right:0;width:16px;height:100%;background:red}.jspHorizontalBar{position:absolute;bottom:0;left:0;width:100%;height:16px;background:red}.jspCap{display:none}.jspHorizontalBar .jspCap{float:left}.jspTrack{background:#dde;position:relative}.jspDrag{background:#bbd;position:relative;top:0;left:0;cursor:pointer}.jspHorizontalBar .jspTrack,.jspHorizontalBar .jspDrag{float:left;height:100%}.jspArrow{background:#50506d;text-indent:-20000px;display:block;cursor:pointer;padding:0;margin:0}.jspArrow.jspDisabled{cursor:default;background:#80808d}.jspVerticalBar .jspArrow{height:16px}.jspHorizontalBar .jspArrow{width:16px;float:left;height:100%}.jspVerticalBar .jspArrow:focus{outline:0}.jspCorner{background:#eeeef4;float:left;height:100%}* html .jspCorner{margin:0 -3px 0 0} \ No newline at end of file diff --git a/ajax/libs/jScrollPane/2.0.22/script/jquery.jscrollpane.js b/ajax/libs/jScrollPane/2.0.22/script/jquery.jscrollpane.js new file mode 100644 index 00000000000000..d499883d4d060c --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.22/script/jquery.jscrollpane.js @@ -0,0 +1,1470 @@ +/*! + * jScrollPane - v2.0.22 - 2015-04-25 + * http://jscrollpane.kelvinluck.com/ + * + * Copyright (c) 2014 Kelvin Luck + * Dual licensed under the MIT or GPL licenses. + */ + +// Script: jScrollPane - cross browser customisable scrollbars +// +// *Version: 2.0.22, Last updated: 2015-04-25* +// +// 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) 2014 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 - tested in 1.4.2+ - reported to work in 1.3.x +// Browsers Tested - Firefox 3.6.8, Safari 5, Opera 10.6, Chrome 5.0, IE 6, 7, 8 +// +// About: Release History +// +// 2.0.22 - (2015-04-25) Resolve a memory leak due to an event handler that isn't cleaned up in destroy (thanks @timjnh) +// 2.0.21 - (2015-02-24) Simplify UMD pattern: fixes browserify when loading jQuery outside of bundle +// 2.0.20 - (2014-10-23) Adds AMD support (thanks @carlosrberto) and support for overflow-x/overflow-y (thanks @darimpulso) +// 2.0.19 - (2013-11-16) Changes for more reliable scroll amount with latest mousewheel plugin (thanks @brandonaaron) +// 2.0.18 - (2013-10-23) Fix for issue with gutters and scrollToElement (thanks @Dubiy) +// 2.0.17 - (2013-08-17) Working correctly when box-sizing is set to border-box (thanks @pieht) +// 2.0.16 - (2013-07-30) Resetting left position when scroll is removed. Fixes #189 +// 2.0.15 - (2013-07-29) Fixed issue with scrollToElement where the destX and destY are undefined. +// 2.0.14 - (2013-05-01) Updated to most recent mouse wheel plugin (see #106) and related changes for sensible scroll speed +// 2.0.13 - (2013-05-01) Switched to semver compatible version name +// 2.0.0beta12 - (2012-09-27) fix for jQuery 1.8+ +// 2.0.0beta11 - (2012-05-14) +// 2.0.0beta10 - (2011-04-17) cleaner required size calculation, improved keyboard support, stickToBottom/Left, other small fixes +// 2.0.0beta9 - (2011-01-31) new API methods, bug fixes and correct keyboard support for FF/OSX +// 2.0.0beta8 - (2011-01-29) touchscreen support, improved keyboard support +// 2.0.0beta7 - (2011-01-23) scroll speed consistent (thanks Aivo Paas) +// 2.0.0beta6 - (2010-12-07) scrollToElement horizontal support +// 2.0.0beta5 - (2010-10-18) jQuery 1.4.3 support, various bug fixes +// 2.0.0beta4 - (2010-09-17) clickOnTrack support, bug fixes +// 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 (factory) { + if ( typeof define === 'function' && define.amd ) { + // AMD. Register as an anonymous module. + define(['jquery'], factory); + } else if (typeof exports === 'object') { + // Node/CommonJS style for Browserify + module.exports = factory(require('jquery')); + } else { + // Browser globals + factory(jQuery); + } +}(function($){ + + $.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, previousContentWidth, + wasAtTop = true, wasAtLeft = true, wasAtBottom = false, wasAtRight = false, + originalElement = elem.clone(false, false).empty(), + mwEvent = $.fn.mwheelIntent ? 'mwheelIntent.jsp' : 'mousewheel.jsp'; + + if (elem.css('box-sizing') === 'border-box') { + originalPadding = 0; + originalPaddingTotalWidth = 0; + } else { + originalPadding = elem.css('paddingTop') + ' ' + + elem.css('paddingRight') + ' ' + + elem.css('paddingBottom') + ' ' + + elem.css('paddingLeft'); + originalPaddingTotalWidth = (parseInt(elem.css('paddingLeft'), 10) || 0) + + (parseInt(elem.css('paddingRight'), 10) || 0); + } + + function initialise(s) + { + + var /*firstChild, lastChild, */isMaintainingPositon, lastContentX, lastContentY, + hasContainingSpaceChanged, originalScrollTop, originalScrollLeft, + maintainAtBottom = false, maintainAtRight = false; + + settings = s; + + if (pane === undefined) { + originalScrollTop = elem.scrollTop(); + originalScrollLeft = elem.scrollLeft(); + + 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 = $('
').css('padding', originalPadding).append(elem.children()); + container = $('
') + .css({ + 'width': paneWidth + 'px', + 'height': paneHeight + 'px' + } + ).append(pane).appendTo(elem); + + /* + // 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', ''); + + maintainAtBottom = settings.stickToBottom && isCloseToBottom(); + maintainAtRight = settings.stickToRight && isCloseToRight(); + + hasContainingSpaceChanged = elem.innerWidth() + originalPaddingTotalWidth != paneWidth || elem.outerHeight() != paneHeight; + + if (hasContainingSpaceChanged) { + paneWidth = elem.innerWidth() + originalPaddingTotalWidth; + paneHeight = elem.innerHeight(); + container.css({ + width: paneWidth + 'px', + height: paneHeight + 'px' + }); + } + + // If nothing changed since last check... + if (!hasContainingSpaceChanged && previousContentWidth == contentWidth && pane.outerHeight() == contentHeight) { + elem.width(paneWidth); + return; + } + previousContentWidth = contentWidth; + + pane.css('width', ''); + elem.width(paneWidth); + + container.find('>.jspVerticalBar,>.jspHorizontalBar').remove().end(); + } + + pane.css('overflow', 'auto'); + if (s.contentWidth) { + contentWidth = s.contentWidth; + } else { + contentWidth = pane[0].scrollWidth; + } + contentHeight = pane[0].scrollHeight; + pane.css('overflow', ''); + + 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, + left: 0, + width: container.width() - originalPaddingTotalWidth + }); + removeMousewheel(); + removeFocusHandler(); + removeKeyboardNav(); + removeClickOnTrack(); + } else { + elem.addClass('jspScrollable'); + + isMaintainingPositon = settings.maintainPosition && (verticalDragPosition || horizontalDragPosition); + if (isMaintainingPositon) { + lastContentX = contentPositionX(); + lastContentY = contentPositionY(); + } + + initialiseVerticalScroll(); + initialiseHorizontalScroll(); + resizeScrollbars(); + + if (isMaintainingPositon) { + scrollToX(maintainAtRight ? (contentWidth - paneWidth ) : lastContentX, false); + scrollToY(maintainAtBottom ? (contentHeight - paneHeight) : lastContentY, false); + } + + initFocusHandler(); + initMousewheel(); + initTouch(); + + if (settings.enableKeyboardNavigation) { + initKeyboardNav(); + } + if (settings.clickOnTrack) { + initClickOnTrack(); + } + + observeHash(); + if (settings.hijackInternalLinks) { + hijackInternalLinks(); + } + } + + if (settings.autoReinitialise && !reinitialiseInterval) { + reinitialiseInterval = setInterval( + function() + { + initialise(settings); + }, + settings.autoReinitialiseDelay + ); + } else if (!settings.autoReinitialise && reinitialiseInterval) { + clearInterval(reinitialiseInterval); + } + + originalScrollTop && elem.scrollTop(0) && scrollToY(originalScrollTop, false); + originalScrollLeft && elem.scrollLeft(0) && scrollToX(originalScrollLeft, false); + + elem.trigger('jsp-initialised', [isScrollableH || isScrollableV]); + } + + function initialiseVerticalScroll() + { + if (isScrollableV) { + + container.append( + $('
').append( + $('
'), + $('
').append( + $('
').append( + $('
'), + $('
') + ) + ), + $('
') + ) + ); + + verticalBar = container.find('>.jspVerticalBar'); + verticalTrack = verticalBar.find('>.jspTrack'); + verticalDrag = verticalTrack.find('>.jspDrag'); + + if (settings.showArrows) { + arrowUp = $('').bind( + 'mousedown.jsp', getArrowScroll(0, -1) + ).bind('click.jsp', nil); + arrowDown = $('').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', nil); + + 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(); + } + } + + 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) + try { + if (verticalBar.position().left === 0) { + pane.css('margin-left', scrollbarWidth + 'px'); + } + } catch (err) { + } + } + + function initialiseHorizontalScroll() + { + if (isScrollableH) { + + container.append( + $('
').append( + $('
'), + $('
').append( + $('
').append( + $('
'), + $('
') + ) + ), + $('
') + ) + ); + + horizontalBar = container.find('>.jspHorizontalBar'); + horizontalTrack = horizontalBar.find('>.jspTrack'); + horizontalDrag = horizontalTrack.find('>.jspDrag'); + + if (settings.showArrows) { + arrowLeft = $('').bind( + 'mousedown.jsp', getArrowScroll(-1, 0) + ).bind('click.jsp', nil); + arrowRight = $('').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', nil); + + 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(); + } + } + + 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( + $('
').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 = Math.ceil(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; + _positionDragX(horizontalDragPosition); // To update the state for the arrow buttons + } + if (isScrollableV) { + verticalDragHeight = Math.ceil(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; + _positionDragY(verticalDragPosition); // To update the state for the arrow buttons + } + } + + 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, + scrollTimeout, + isFirst = true, + doScroll = function() + { + if (dirX !== 0) { + jsp.scrollByX(dirX * settings.arrowButtonSpeed); + } + if (dirY !== 0) { + jsp.scrollByY(dirY * settings.arrowButtonSpeed); + } + scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.arrowRepeatFreq); + isFirst = false; + }; + + doScroll(); + + eve = ele ? 'mouseout.jsp' : 'mouseup.jsp'; + ele = ele || $('html'); + ele.bind( + eve, + function() + { + arrow.removeClass('jspActive'); + scrollTimeout && clearTimeout(scrollTimeout); + scrollTimeout = null; + ele.unbind(eve); + } + ); + } + + function initClickOnTrack() + { + removeClickOnTrack(); + if (isScrollableV) { + verticalTrack.bind( + 'mousedown.jsp', + function(e) + { + if (e.originalTarget === undefined || e.originalTarget == e.currentTarget) { + var clickedTrack = $(this), + offset = clickedTrack.offset(), + direction = e.pageY - offset.top - verticalDragPosition, + scrollTimeout, + isFirst = true, + doScroll = function() + { + var offset = clickedTrack.offset(), + pos = e.pageY - offset.top - verticalDragHeight / 2, + contentDragY = paneHeight * settings.scrollPagePercent, + dragY = dragMaxY * contentDragY / (contentHeight - paneHeight); + if (direction < 0) { + if (verticalDragPosition - dragY > pos) { + jsp.scrollByY(-contentDragY); + } else { + positionDragY(pos); + } + } else if (direction > 0) { + if (verticalDragPosition + dragY < pos) { + jsp.scrollByY(contentDragY); + } else { + positionDragY(pos); + } + } else { + cancelClick(); + return; + } + scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.trackClickRepeatFreq); + isFirst = false; + }, + cancelClick = function() + { + scrollTimeout && clearTimeout(scrollTimeout); + scrollTimeout = null; + $(document).unbind('mouseup.jsp', cancelClick); + }; + doScroll(); + $(document).bind('mouseup.jsp', cancelClick); + return false; + } + } + ); + } + + if (isScrollableH) { + horizontalTrack.bind( + 'mousedown.jsp', + function(e) + { + if (e.originalTarget === undefined || e.originalTarget == e.currentTarget) { + var clickedTrack = $(this), + offset = clickedTrack.offset(), + direction = e.pageX - offset.left - horizontalDragPosition, + scrollTimeout, + isFirst = true, + doScroll = function() + { + var offset = clickedTrack.offset(), + pos = e.pageX - offset.left - horizontalDragWidth / 2, + contentDragX = paneWidth * settings.scrollPagePercent, + dragX = dragMaxX * contentDragX / (contentWidth - paneWidth); + if (direction < 0) { + if (horizontalDragPosition - dragX > pos) { + jsp.scrollByX(-contentDragX); + } else { + positionDragX(pos); + } + } else if (direction > 0) { + if (horizontalDragPosition + dragX < pos) { + jsp.scrollByX(contentDragX); + } else { + positionDragX(pos); + } + } else { + cancelClick(); + return; + } + scrollTimeout = setTimeout(doScroll, isFirst ? settings.initialDelay : settings.trackClickRepeatFreq); + isFirst = false; + }, + cancelClick = function() + { + scrollTimeout && clearTimeout(scrollTimeout); + scrollTimeout = null; + $(document).unbind('mouseup.jsp', cancelClick); + }; + doScroll(); + $(document).bind('mouseup.jsp', cancelClick); + return false; + } + } + ); + } + } + + function removeClickOnTrack() + { + if (horizontalTrack) { + horizontalTrack.unbind('mousedown.jsp'); + } + if (verticalTrack) { + verticalTrack.unbind('mousedown.jsp'); + } + } + + function cancelDrag() + { + $('html').unbind('dragstart.jsp selectstart.jsp mousemove.jsp mouseup.jsp mouseleave.jsp'); + + if (verticalDrag) { + verticalDrag.removeClass('jspActive'); + } + if (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 || 0; + + 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]).trigger('scroll'); + } + + 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 ||0; + + var isAtLeft = horizontalDragPosition === 0, + isAtRight = horizontalDragPosition == dragMaxX, + 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]).trigger('scroll'); + } + + 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, eleWidth, eleTop = 0, eleLeft = 0, viewportTop, viewportLeft, maxVisibleEleTop, maxVisibleEleLeft, destY, destX; + + // 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(); + eleWidth= e.outerWidth(); + + container.scrollTop(0); + container.scrollLeft(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; + eleLeft += e.position().left; + 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.horizontalGutter; + } else if (eleTop + eleHeight > maxVisibleEleTop) { // element is below viewport + destY = eleTop - paneHeight + eleHeight + settings.horizontalGutter; + } + if (!isNaN(destY)) { + scrollToY(destY, animate); + } + + viewportLeft = contentPositionX(); + maxVisibleEleLeft = viewportLeft + paneWidth; + if (eleLeft < viewportLeft || stickToTop) { // element is to the left of viewport + destX = eleLeft - settings.horizontalGutter; + } else if (eleLeft + eleWidth > maxVisibleEleLeft) { // element is to the right viewport + destX = eleLeft - paneWidth + eleWidth + settings.horizontalGutter; + } + if (!isNaN(destX)) { + scrollToX(destX, animate); + } + + } + + function contentPositionX() + { + return -pane.position().left; + } + + function contentPositionY() + { + return -pane.position().top; + } + + function isCloseToBottom() + { + var scrollableHeight = contentHeight - paneHeight; + return (scrollableHeight > 20) && (scrollableHeight - contentPositionY() < 10); + } + + function isCloseToRight() + { + var scrollableWidth = contentWidth - paneWidth; + return (scrollableWidth > 20) && (scrollableWidth - contentPositionX() < 10); + } + + function initMousewheel() + { + container.unbind(mwEvent).bind( + mwEvent, + function (event, delta, deltaX, deltaY) { + + if (!horizontalDragPosition) horizontalDragPosition = 0; + if (!verticalDragPosition) verticalDragPosition = 0; + + var dX = horizontalDragPosition, dY = verticalDragPosition, factor = event.deltaFactor || settings.mouseWheelSpeed; + jsp.scrollBy(deltaX * factor, -deltaY * factor, 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.find(':input,a').unbind('focus.jsp').bind( + 'focus.jsp', + function(e) + { + scrollToElement(e.target, false); + } + ); + } + + function removeFocusHandler() + { + pane.find(':input,a').unbind('focus.jsp'); + } + + function initKeyboardNav() + { + var keyDown, elementHasScrolled, validParents = []; + isScrollableH && validParents.push(horizontalBar[0]); + isScrollableV && validParents.push(verticalBar[0]); + + // IE also focuses elements that don't have tabindex set. + pane.bind( + 'focus.jsp', + function() + { + elem.focus(); + } + ); + + elem.attr('tabindex', 0) + .unbind('keydown.jsp keypress.jsp') + .bind( + 'keydown.jsp', + function(e) + { + if (e.target !== this && !(validParents.length && $(e.target).closest(validParents).length)){ + return; + } + var dX = horizontalDragPosition, dY = verticalDragPosition; + switch(e.keyCode) { + case 40: // down + case 38: // up + case 34: // page down + case 32: // space + case 33: // page up + case 39: // right + case 37: // left + keyDown = e.keyCode; + keyDownHandler(); + break; + case 35: // end + scrollToY(contentHeight - paneHeight); + keyDown = null; + break; + case 36: // home + scrollToY(0); + keyDown = null; + break; + } + + elementHasScrolled = e.keyCode == keyDown && dX != horizontalDragPosition || dY != verticalDragPosition; + return !elementHasScrolled; + } + ).bind( + 'keypress.jsp', // For FF/ OSX so that we can cancel the repeat key presses if the JSP scrolls... + function(e) + { + if (e.keyCode == keyDown) { + keyDownHandler(); + } + return !elementHasScrolled; + } + ); + + 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 keyDownHandler() + { + var dX = horizontalDragPosition, dY = verticalDragPosition; + switch(keyDown) { + case 40: // down + jsp.scrollByY(settings.keyboardSpeed, false); + break; + case 38: // up + jsp.scrollByY(-settings.keyboardSpeed, false); + break; + case 34: // page down + case 32: // space + jsp.scrollByY(paneHeight * settings.scrollPagePercent, false); + break; + case 33: // page up + jsp.scrollByY(-paneHeight * settings.scrollPagePercent, false); + break; + case 39: // right + jsp.scrollByX(settings.keyboardSpeed, false); + break; + case 37: // left + jsp.scrollByX(-settings.keyboardSpeed, false); + break; + } + + elementHasScrolled = dX != horizontalDragPosition || dY != verticalDragPosition; + return elementHasScrolled; + } + } + + function removeKeyboardNav() + { + elem.attr('tabindex', '-1') + .removeAttr('tabindex') + .unbind('keydown.jsp keypress.jsp'); + + pane.unbind('.jsp'); + } + + function observeHash() + { + if (location.hash && location.hash.length > 1) { + var e, + retryInt, + hash = escape(location.hash.substr(1)) // hash must be escaped to prevent XSS + ; + try { + e = $('#' + hash + ', a[name="' + hash + '"]'); + } catch (err) { + return; + } + + if (e.length && pane.find(hash)) { + // 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(e, true); + $(document).scrollTop(container.position().top); + clearInterval(retryInt); + } + }, + 50 + ); + } else { + scrollToElement(e, true); + $(document).scrollTop(container.position().top); + } + } + } + } + + function hijackInternalLinks() + { + // only register the link handler once + if ($(document.body).data('jspHijack')) { + return; + } + + // remember that the handler was bound + $(document.body).data('jspHijack', true); + + // use live handler to also capture newly created links + $(document.body).delegate('a[href*=#]', 'click', function(event) { + // does the link point to the same page? + // this also takes care of cases with a -Tag or Links not starting with the hash # + // e.g. when the current url already is index.html + var href = this.href.substr(0, this.href.indexOf('#')), + locationHref = location.href, + hash, + element, + container, + jsp, + scrollTop, + elementTop; + if (location.href.indexOf('#') !== -1) { + locationHref = location.href.substr(0, location.href.indexOf('#')); + } + if (href !== locationHref) { + // the link points to another page + return; + } + + // check if jScrollPane should handle this click event + hash = escape(this.href.substr(this.href.indexOf('#') + 1)); + + // find the element on the page + element; + try { + element = $('#' + hash + ', a[name="' + hash + '"]'); + } catch (e) { + // hash is not a valid jQuery identifier + return; + } + + if (!element.length) { + // this link does not point to an element on this page + return; + } + + container = element.closest('.jspScrollable'); + jsp = container.data('jsp'); + + // jsp might be another jsp instance than the one, that bound this event + // remember: this event is only bound once for all instances. + jsp.scrollToElement(element, true); + + if (container[0].scrollIntoView) { + // also scroll to the top of the container (if it is not visible) + scrollTop = $(window).scrollTop(); + elementTop = element.offset().top; + if (elementTop < scrollTop || elementTop > scrollTop + $(window).height()) { + container[0].scrollIntoView(); + } + } + + // jsp handled this event, prevent the browser default (scrolling :P) + event.preventDefault(); + }); + } + + // Init touch on iPad, iPhone, iPod, Android + function initTouch() + { + var startX, + startY, + touchStartX, + touchStartY, + moved, + moving = false; + + container.unbind('touchstart.jsp touchmove.jsp touchend.jsp click.jsp-touchclick').bind( + 'touchstart.jsp', + function(e) + { + var touch = e.originalEvent.touches[0]; + startX = contentPositionX(); + startY = contentPositionY(); + touchStartX = touch.pageX; + touchStartY = touch.pageY; + moved = false; + moving = true; + } + ).bind( + 'touchmove.jsp', + function(ev) + { + if(!moving) { + return; + } + + var touchPos = ev.originalEvent.touches[0], + dX = horizontalDragPosition, dY = verticalDragPosition; + + jsp.scrollTo(startX + touchStartX - touchPos.pageX, startY + touchStartY - touchPos.pageY); + + moved = moved || Math.abs(touchStartX - touchPos.pageX) > 5 || Math.abs(touchStartY - touchPos.pageY) > 5; + + // return true if there was no movement so rest of screen can scroll + return dX == horizontalDragPosition && dY == verticalDragPosition; + } + ).bind( + 'touchend.jsp', + function(e) + { + moving = false; + /*if(moved) { + return false; + }*/ + } + ).bind( + 'click.jsp-touchclick', + function(e) + { + if(moved) { + moved = false; + return false; + } + } + ); + } + + function destroy(){ + var currentY = contentPositionY(), + currentX = contentPositionX(); + elem.removeClass('jspScrollable').unbind('.jsp'); + pane.unbind('.jsp'); + elem.replaceWith(originalElement.append(pane.children())); + originalElement.scrollTop(currentY); + originalElement.scrollLeft(currentX); + + // clear reinitialize timer if active + if (reinitialiseInterval) { + clearInterval(reinitialiseInterval); + } + } + + // 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({}, settings, s); + 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 to the specified percentage of its maximum horizontal scroll position. animate + // is optional and if not passed then the value of animateScroll from the settings object this + // jScrollPane was initialised with is used. + scrollToPercentX: function(destPercentX, animate) + { + scrollToX(destPercentX * (contentWidth - paneWidth), animate); + }, + // Scrolls the pane to the specified percentage of its maximum vertical scroll position. animate + // is optional and if not passed then the value of animateScroll from the settings object this + // jScrollPane was initialised with is used. + scrollToPercentY: function(destPercentY, animate) + { + scrollToY(destPercentY * (contentHeight - paneHeight), 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() + Math[deltaX<0 ? 'floor' : 'ceil'](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() + Math[deltaY<0 ? 'floor' : 'ceil'](deltaY), + percentScrolled = destY / (contentHeight - paneHeight); + positionDragY(percentScrolled * dragMaxY, animate); + }, + // Positions the horizontal drag at the specified x position (and updates the viewport to reflect + // this). animate is optional and if not passed then the value of animateScroll from the settings + // object this jScrollPane was initialised with is used. + positionDragX: function(x, animate) + { + positionDragX(x, animate); + }, + // Positions the vertical drag at the specified y position (and updates the viewport to reflect + // this). animate is optional and if not passed then the value of animateScroll from the settings + // object this jScrollPane was initialised with is used. + positionDragY: function(y, animate) + { + positionDragY(y, 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, + 'easing' : 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 the width of the content within the scroll pane. + getContentWidth: function() + { + return contentWidth; + }, + // Returns the height of the content within the scroll pane. + getContentHeight: function() + { + return contentHeight; + }, + // Returns the horizontal position of the viewport within the pane content. + getPercentScrolledX: function() + { + return contentPositionX() / (contentWidth - paneWidth); + }, + // Returns the vertical position of the viewport within the pane content. + getPercentScrolledY: function() + { + return contentPositionY() / (contentHeight - paneHeight); + }, + // 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: $.noop, + // Removes the jScrollPane and returns the page to the state it was in before jScrollPane was + // initialised. + destroy: function() + { + destroy(); + } + } + ); + + initialise(s); + } + + // Pluginifying code... + settings = $.extend({}, $.fn.jScrollPane.defaults, settings); + + // Apply default speed + $.each(['arrowButtonSpeed', 'trackClickSpeed', 'keyboardSpeed'], function() { + settings[this] = settings[this] || settings.speed; + }); + + return this.each( + function() + { + var elem = $(this), jspApi = elem.data('jsp'); + if (jspApi) { + jspApi.reinitialise(settings); + } else { + $("script",elem).filter('[type="text/javascript"],:not([type])').remove(); + jspApi = new JScrollPane(elem, settings); + elem.data('jsp', jspApi); + } + } + ); + }; + + $.fn.jScrollPane.defaults = { + showArrows : false, + maintainPosition : true, + stickToBottom : false, + stickToRight : false, + clickOnTrack : true, + autoReinitialise : false, + autoReinitialiseDelay : 500, + verticalDragMinHeight : 0, + verticalDragMaxHeight : 99999, + horizontalDragMinWidth : 0, + horizontalDragMaxWidth : 99999, + contentWidth : undefined, + animateScroll : false, + animateDuration : 300, + animateEase : 'linear', + hijackInternalLinks : false, + verticalGutter : 4, + horizontalGutter : 4, + mouseWheelSpeed : 3, + arrowButtonSpeed : 0, + arrowRepeatFreq : 50, + arrowScrollOnHover : false, + trackClickSpeed : 0, + trackClickRepeatFreq : 70, + verticalArrowPositions : 'split', + horizontalArrowPositions : 'split', + enableKeyboardNavigation : true, + hideFocus : false, + keyboardSpeed : 0, + initialDelay : 300, // Delay before starting repeating + speed : 30, // Default speed when others falsey + scrollPagePercent : .8 // Percent of visible area scrolled when pageUp/Down or track area pressed + }; + +})); diff --git a/ajax/libs/jScrollPane/2.0.22/script/jquery.jscrollpane.min.js b/ajax/libs/jScrollPane/2.0.22/script/jquery.jscrollpane.min.js new file mode 100644 index 00000000000000..57d2945fcaab4b --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.22/script/jquery.jscrollpane.min.js @@ -0,0 +1,8 @@ +/*! + * jScrollPane - v2.0.22 - 2015-04-25 + * http://jscrollpane.kelvinluck.com/ + * + * Copyright (c) 2014 Kelvin Luck + * Dual licensed under the MIT or GPL licenses. + */ +!function(a){"function"==typeof define&&define.amd?define(["jquery"],a):"object"==typeof exports?module.exports=a(require("jquery")):a(jQuery)}(function(a){a.fn.jScrollPane=function(b){function c(b,c){function d(c){var f,h,j,k,l,o,p=!1,q=!1;if(N=c,void 0===O)l=b.scrollTop(),o=b.scrollLeft(),b.css({overflow:"hidden",padding:0}),P=b.innerWidth()+ra,Q=b.innerHeight(),b.width(P),O=a('
').css("padding",qa).append(b.children()),R=a('
').css({width:P+"px",height:Q+"px"}).append(O).appendTo(b);else{if(b.css("width",""),p=N.stickToBottom&&A(),q=N.stickToRight&&B(),k=b.innerWidth()+ra!=P||b.outerHeight()!=Q,k&&(P=b.innerWidth()+ra,Q=b.innerHeight(),R.css({width:P+"px",height:Q+"px"})),!k&&sa==S&&O.outerHeight()==T)return void b.width(P);sa=S,O.css("width",""),b.width(P),R.find(">.jspVerticalBar,>.jspHorizontalBar").remove().end()}O.css("overflow","auto"),S=c.contentWidth?c.contentWidth:O[0].scrollWidth,T=O[0].scrollHeight,O.css("overflow",""),U=S/P,V=T/Q,W=V>1,X=U>1,X||W?(b.addClass("jspScrollable"),f=N.maintainPosition&&($||ba),f&&(h=y(),j=z()),e(),g(),i(),f&&(w(q?S-P:h,!1),v(p?T-Q:j,!1)),F(),C(),L(),N.enableKeyboardNavigation&&H(),N.clickOnTrack&&m(),J(),N.hijackInternalLinks&&K()):(b.removeClass("jspScrollable"),O.css({top:0,left:0,width:R.width()-ra}),D(),G(),I(),n()),N.autoReinitialise&&!pa?pa=setInterval(function(){d(N)},N.autoReinitialiseDelay):!N.autoReinitialise&&pa&&clearInterval(pa),l&&b.scrollTop(0)&&v(l,!1),o&&b.scrollLeft(0)&&w(o,!1),b.trigger("jsp-initialised",[X||W])}function e(){W&&(R.append(a('
').append(a('
'),a('
').append(a('
').append(a('
'),a('
'))),a('
'))),ca=R.find(">.jspVerticalBar"),da=ca.find(">.jspTrack"),Y=da.find(">.jspDrag"),N.showArrows&&(ha=a('').bind("mousedown.jsp",k(0,-1)).bind("click.jsp",E),ia=a('').bind("mousedown.jsp",k(0,1)).bind("click.jsp",E),N.arrowScrollOnHover&&(ha.bind("mouseover.jsp",k(0,-1,ha)),ia.bind("mouseover.jsp",k(0,1,ia))),j(da,N.verticalArrowPositions,ha,ia)),fa=Q,R.find(">.jspVerticalBar>.jspCap:visible,>.jspVerticalBar>.jspArrow").each(function(){fa-=a(this).outerHeight()}),Y.hover(function(){Y.addClass("jspHover")},function(){Y.removeClass("jspHover")}).bind("mousedown.jsp",function(b){a("html").bind("dragstart.jsp selectstart.jsp",E),Y.addClass("jspActive");var c=b.pageY-Y.position().top;return a("html").bind("mousemove.jsp",function(a){p(a.pageY-c,!1)}).bind("mouseup.jsp mouseleave.jsp",o),!1}),f())}function f(){da.height(fa+"px"),$=0,ea=N.verticalGutter+da.outerWidth(),O.width(P-ea-ra);try{0===ca.position().left&&O.css("margin-left",ea+"px")}catch(a){}}function g(){X&&(R.append(a('
').append(a('
'),a('
').append(a('
').append(a('
'),a('
'))),a('
'))),ja=R.find(">.jspHorizontalBar"),ka=ja.find(">.jspTrack"),_=ka.find(">.jspDrag"),N.showArrows&&(na=a('').bind("mousedown.jsp",k(-1,0)).bind("click.jsp",E),oa=a('').bind("mousedown.jsp",k(1,0)).bind("click.jsp",E),N.arrowScrollOnHover&&(na.bind("mouseover.jsp",k(-1,0,na)),oa.bind("mouseover.jsp",k(1,0,oa))),j(ka,N.horizontalArrowPositions,na,oa)),_.hover(function(){_.addClass("jspHover")},function(){_.removeClass("jspHover")}).bind("mousedown.jsp",function(b){a("html").bind("dragstart.jsp selectstart.jsp",E),_.addClass("jspActive");var c=b.pageX-_.position().left;return a("html").bind("mousemove.jsp",function(a){r(a.pageX-c,!1)}).bind("mouseup.jsp mouseleave.jsp",o),!1}),la=R.innerWidth(),h())}function h(){R.find(">.jspHorizontalBar>.jspCap:visible,>.jspHorizontalBar>.jspArrow").each(function(){la-=a(this).outerWidth()}),ka.width(la+"px"),ba=0}function i(){if(X&&W){var b=ka.outerHeight(),c=da.outerWidth();fa-=b,a(ja).find(">.jspCap:visible,>.jspArrow").each(function(){la+=a(this).outerWidth()}),la-=c,Q-=c,P-=b,ka.parent().append(a('
').css("width",b+"px")),f(),h()}X&&O.width(R.outerWidth()-ra+"px"),T=O.outerHeight(),V=T/Q,X&&(ma=Math.ceil(1/U*la),ma>N.horizontalDragMaxWidth?ma=N.horizontalDragMaxWidth:maN.verticalDragMaxHeight?ga=N.verticalDragMaxHeight:gaf)$-k>e?ta.scrollByY(-j):p(e);else{if(!(f>0))return void i();e>$+k?ta.scrollByY(j):p(e)}c=setTimeout(h,g?N.initialDelay:N.trackClickRepeatFreq),g=!1},i=function(){c&&clearTimeout(c),c=null,a(document).unbind("mouseup.jsp",i)};return h(),a(document).bind("mouseup.jsp",i),!1}}),X&&ka.bind("mousedown.jsp",function(b){if(void 0===b.originalTarget||b.originalTarget==b.currentTarget){var c,d=a(this),e=d.offset(),f=b.pageX-e.left-ba,g=!0,h=function(){var a=d.offset(),e=b.pageX-a.left-ma/2,j=P*N.scrollPagePercent,k=aa*j/(S-P);if(0>f)ba-k>e?ta.scrollByX(-j):r(e);else{if(!(f>0))return void i();e>ba+k?ta.scrollByX(j):r(e)}c=setTimeout(h,g?N.initialDelay:N.trackClickRepeatFreq),g=!1},i=function(){c&&clearTimeout(c),c=null,a(document).unbind("mouseup.jsp",i)};return h(),a(document).bind("mouseup.jsp",i),!1}})}function n(){ka&&ka.unbind("mousedown.jsp"),da&&da.unbind("mousedown.jsp")}function o(){a("html").unbind("dragstart.jsp selectstart.jsp mousemove.jsp mouseup.jsp mouseleave.jsp"),Y&&Y.removeClass("jspActive"),_&&_.removeClass("jspActive")}function p(a,b){W&&(0>a?a=0:a>Z&&(a=Z),void 0===b&&(b=N.animateScroll),b?ta.animate(Y,"top",a,q):(Y.css("top",a),q(a)))}function q(a){void 0===a&&(a=Y.position().top),R.scrollTop(0),$=a||0;var c=0===$,d=$==Z,e=a/Z,f=-e*(T-Q);(ua!=c||wa!=d)&&(ua=c,wa=d,b.trigger("jsp-arrow-change",[ua,wa,va,xa])),t(c,d),O.css("top",f),b.trigger("jsp-scroll-y",[-f,c,d]).trigger("scroll")}function r(a,b){X&&(0>a?a=0:a>aa&&(a=aa),void 0===b&&(b=N.animateScroll),b?ta.animate(_,"left",a,s):(_.css("left",a),s(a)))}function s(a){void 0===a&&(a=_.position().left),R.scrollTop(0),ba=a||0;var c=0===ba,d=ba==aa,e=a/aa,f=-e*(S-P);(va!=c||xa!=d)&&(va=c,xa=d,b.trigger("jsp-arrow-change",[ua,wa,va,xa])),u(c,d),O.css("left",f),b.trigger("jsp-scroll-x",[-f,c,d]).trigger("scroll")}function t(a,b){N.showArrows&&(ha[a?"addClass":"removeClass"]("jspDisabled"),ia[b?"addClass":"removeClass"]("jspDisabled"))}function u(a,b){N.showArrows&&(na[a?"addClass":"removeClass"]("jspDisabled"),oa[b?"addClass":"removeClass"]("jspDisabled"))}function v(a,b){var c=a/(T-Q);p(c*Z,b)}function w(a,b){var c=a/(S-P);r(c*aa,b)}function x(b,c,d){var e,f,g,h,i,j,k,l,m,n=0,o=0;try{e=a(b)}catch(p){return}for(f=e.outerHeight(),g=e.outerWidth(),R.scrollTop(0),R.scrollLeft(0);!e.is(".jspPane");)if(n+=e.position().top,o+=e.position().left,e=e.offsetParent(),/^body|html$/i.test(e[0].nodeName))return;h=z(),j=h+Q,h>n||c?l=n-N.horizontalGutter:n+f>j&&(l=n-Q+f+N.horizontalGutter),isNaN(l)||v(l,d),i=y(),k=i+P,i>o||c?m=o-N.horizontalGutter:o+g>k&&(m=o-P+g+N.horizontalGutter),isNaN(m)||w(m,d)}function y(){return-O.position().left}function z(){return-O.position().top}function A(){var a=T-Q;return a>20&&a-z()<10}function B(){var a=S-P;return a>20&&a-y()<10}function C(){R.unbind(za).bind(za,function(a,b,c,d){ba||(ba=0),$||($=0);var e=ba,f=$,g=a.deltaFactor||N.mouseWheelSpeed;return ta.scrollBy(c*g,-d*g,!1),e==ba&&f==$})}function D(){R.unbind(za)}function E(){return!1}function F(){O.find(":input,a").unbind("focus.jsp").bind("focus.jsp",function(a){x(a.target,!1)})}function G(){O.find(":input,a").unbind("focus.jsp")}function H(){function c(){var a=ba,b=$;switch(d){case 40:ta.scrollByY(N.keyboardSpeed,!1);break;case 38:ta.scrollByY(-N.keyboardSpeed,!1);break;case 34:case 32:ta.scrollByY(Q*N.scrollPagePercent,!1);break;case 33:ta.scrollByY(-Q*N.scrollPagePercent,!1);break;case 39:ta.scrollByX(N.keyboardSpeed,!1);break;case 37:ta.scrollByX(-N.keyboardSpeed,!1)}return e=a!=ba||b!=$}var d,e,f=[];X&&f.push(ja[0]),W&&f.push(ca[0]),O.bind("focus.jsp",function(){b.focus()}),b.attr("tabindex",0).unbind("keydown.jsp keypress.jsp").bind("keydown.jsp",function(b){if(b.target===this||f.length&&a(b.target).closest(f).length){var g=ba,h=$;switch(b.keyCode){case 40:case 38:case 34:case 32:case 33:case 39:case 37:d=b.keyCode,c();break;case 35:v(T-Q),d=null;break;case 36:v(0),d=null}return e=b.keyCode==d&&g!=ba||h!=$,!e}}).bind("keypress.jsp",function(a){return a.keyCode==d&&c(),!e}),N.hideFocus?(b.css("outline","none"),"hideFocus"in R[0]&&b.attr("hideFocus",!0)):(b.css("outline",""),"hideFocus"in R[0]&&b.attr("hideFocus",!1))}function I(){b.attr("tabindex","-1").removeAttr("tabindex").unbind("keydown.jsp keypress.jsp"),O.unbind(".jsp")}function J(){if(location.hash&&location.hash.length>1){var b,c,d=escape(location.hash.substr(1));try{b=a("#"+d+', a[name="'+d+'"]')}catch(e){return}b.length&&O.find(d)&&(0===R.scrollTop()?c=setInterval(function(){R.scrollTop()>0&&(x(b,!0),a(document).scrollTop(R.position().top),clearInterval(c))},50):(x(b,!0),a(document).scrollTop(R.position().top)))}}function K(){a(document.body).data("jspHijack")||(a(document.body).data("jspHijack",!0),a(document.body).delegate("a[href*=#]","click",function(b){var c,d,e,f,g,h,i=this.href.substr(0,this.href.indexOf("#")),j=location.href;if(-1!==location.href.indexOf("#")&&(j=location.href.substr(0,location.href.indexOf("#"))),i===j){c=escape(this.href.substr(this.href.indexOf("#")+1));try{d=a("#"+c+', a[name="'+c+'"]')}catch(k){return}d.length&&(e=d.closest(".jspScrollable"),f=e.data("jsp"),f.scrollToElement(d,!0),e[0].scrollIntoView&&(g=a(window).scrollTop(),h=d.offset().top,(g>h||h>g+a(window).height())&&e[0].scrollIntoView()),b.preventDefault())}}))}function L(){var a,b,c,d,e,f=!1;R.unbind("touchstart.jsp touchmove.jsp touchend.jsp click.jsp-touchclick").bind("touchstart.jsp",function(g){var h=g.originalEvent.touches[0];a=y(),b=z(),c=h.pageX,d=h.pageY,e=!1,f=!0}).bind("touchmove.jsp",function(g){if(f){var h=g.originalEvent.touches[0],i=ba,j=$;return ta.scrollTo(a+c-h.pageX,b+d-h.pageY),e=e||Math.abs(c-h.pageX)>5||Math.abs(d-h.pageY)>5,i==ba&&j==$}}).bind("touchend.jsp",function(a){f=!1}).bind("click.jsp-touchclick",function(a){return e?(e=!1,!1):void 0})}function M(){var a=z(),c=y();b.removeClass("jspScrollable").unbind(".jsp"),O.unbind(".jsp"),b.replaceWith(ya.append(O.children())),ya.scrollTop(a),ya.scrollLeft(c),pa&&clearInterval(pa)}var N,O,P,Q,R,S,T,U,V,W,X,Y,Z,$,_,aa,ba,ca,da,ea,fa,ga,ha,ia,ja,ka,la,ma,na,oa,pa,qa,ra,sa,ta=this,ua=!0,va=!0,wa=!1,xa=!1,ya=b.clone(!1,!1).empty(),za=a.fn.mwheelIntent?"mwheelIntent.jsp":"mousewheel.jsp";"border-box"===b.css("box-sizing")?(qa=0,ra=0):(qa=b.css("paddingTop")+" "+b.css("paddingRight")+" "+b.css("paddingBottom")+" "+b.css("paddingLeft"),ra=(parseInt(b.css("paddingLeft"),10)||0)+(parseInt(b.css("paddingRight"),10)||0)),a.extend(ta,{reinitialise:function(b){b=a.extend({},N,b),d(b)},scrollToElement:function(a,b,c){x(a,b,c)},scrollTo:function(a,b,c){w(a,c),v(b,c)},scrollToX:function(a,b){w(a,b)},scrollToY:function(a,b){v(a,b)},scrollToPercentX:function(a,b){w(a*(S-P),b)},scrollToPercentY:function(a,b){v(a*(T-Q),b)},scrollBy:function(a,b,c){ta.scrollByX(a,c),ta.scrollByY(b,c)},scrollByX:function(a,b){var c=y()+Math[0>a?"floor":"ceil"](a),d=c/(S-P);r(d*aa,b)},scrollByY:function(a,b){var c=z()+Math[0>a?"floor":"ceil"](a),d=c/(T-Q);p(d*Z,b)},positionDragX:function(a,b){r(a,b)},positionDragY:function(a,b){p(a,b)},animate:function(a,b,c,d){var e={};e[b]=c,a.animate(e,{duration:N.animateDuration,easing:N.animateEase,queue:!1,step:d})},getContentPositionX:function(){return y()},getContentPositionY:function(){return z()},getContentWidth:function(){return S},getContentHeight:function(){return T},getPercentScrolledX:function(){return y()/(S-P)},getPercentScrolledY:function(){return z()/(T-Q)},getIsScrollableH:function(){return X},getIsScrollableV:function(){return W},getContentPane:function(){return O},scrollToBottom:function(a){p(Z,a)},hijackInternalLinks:a.noop,destroy:function(){M()}}),d(c)}return b=a.extend({},a.fn.jScrollPane.defaults,b),a.each(["arrowButtonSpeed","trackClickSpeed","keyboardSpeed"],function(){b[this]=b[this]||b.speed}),this.each(function(){var d=a(this),e=d.data("jsp");e?e.reinitialise(b):(a("script",d).filter('[type="text/javascript"],:not([type])').remove(),e=new c(d,b),d.data("jsp",e))})},a.fn.jScrollPane.defaults={showArrows:!1,maintainPosition:!0,stickToBottom:!1,stickToRight:!1,clickOnTrack:!0,autoReinitialise:!1,autoReinitialiseDelay:500,verticalDragMinHeight:0,verticalDragMaxHeight:99999,horizontalDragMinWidth:0,horizontalDragMaxWidth:99999,contentWidth:void 0,animateScroll:!1,animateDuration:300,animateEase:"linear",hijackInternalLinks:!1,verticalGutter:4,horizontalGutter:4,mouseWheelSpeed:3,arrowButtonSpeed:0,arrowRepeatFreq:50,arrowScrollOnHover:!1,trackClickSpeed:0,trackClickRepeatFreq:70,verticalArrowPositions:"split",horizontalArrowPositions:"split",enableKeyboardNavigation:!0,hideFocus:!1,keyboardSpeed:0,initialDelay:300,speed:30,scrollPagePercent:.8}}); \ No newline at end of file diff --git a/ajax/libs/jScrollPane/2.0.22/style/jquery.jscrollpane.css b/ajax/libs/jScrollPane/2.0.22/style/jquery.jscrollpane.css new file mode 100644 index 00000000000000..57ccca25316d53 --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.22/style/jquery.jscrollpane.css @@ -0,0 +1,115 @@ +/* + * CSS Styles that are needed by jScrollPane for it to operate correctly. + * + * Include this stylesheet in your site or copy and paste the styles below into your stylesheet - jScrollPane + * may not operate correctly without them. + */ + +.jspContainer +{ + overflow: hidden; + position: relative; +} + +.jspPane +{ + position: absolute; +} + +.jspVerticalBar +{ + position: absolute; + top: 0; + right: 0; + width: 16px; + height: 100%; + background: red; +} + +.jspHorizontalBar +{ + position: absolute; + bottom: 0; + left: 0; + width: 100%; + height: 16px; + background: red; +} + +.jspCap +{ + display: none; +} + +.jspHorizontalBar .jspCap +{ + float: left; +} + +.jspTrack +{ + background: #dde; + position: relative; +} + +.jspDrag +{ + background: #bbd; + position: relative; + top: 0; + left: 0; + cursor: pointer; +} + +.jspHorizontalBar .jspTrack, +.jspHorizontalBar .jspDrag +{ + float: left; + height: 100%; +} + +.jspArrow +{ + background: #50506d; + text-indent: -20000px; + display: block; + cursor: pointer; + padding: 0; + margin: 0; +} + +.jspArrow.jspDisabled +{ + cursor: default; + background: #80808d; +} + +.jspVerticalBar .jspArrow +{ + height: 16px; +} + +.jspHorizontalBar .jspArrow +{ + width: 16px; + float: left; + height: 100%; +} + +.jspVerticalBar .jspArrow:focus +{ + outline: none; +} + +.jspCorner +{ + background: #eeeef4; + float: left; + height: 100%; +} + +/* Yuk! CSS Hack for IE6 3 pixel bug :( */ +* html .jspCorner +{ + margin: 0 -3px 0 0; +} \ No newline at end of file diff --git a/ajax/libs/jScrollPane/2.0.22/style/jquery.jscrollpane.min.css b/ajax/libs/jScrollPane/2.0.22/style/jquery.jscrollpane.min.css new file mode 100644 index 00000000000000..9a0eed96f15c3a --- /dev/null +++ b/ajax/libs/jScrollPane/2.0.22/style/jquery.jscrollpane.min.css @@ -0,0 +1 @@ +.jspContainer{overflow:hidden;position:relative}.jspPane{position:absolute}.jspVerticalBar{position:absolute;top:0;right:0;width:16px;height:100%;background:red}.jspHorizontalBar{position:absolute;bottom:0;left:0;width:100%;height:16px;background:red}.jspCap{display:none}.jspHorizontalBar .jspCap{float:left}.jspTrack{background:#dde;position:relative}.jspDrag{background:#bbd;position:relative;top:0;left:0;cursor:pointer}.jspHorizontalBar .jspTrack,.jspHorizontalBar .jspDrag{float:left;height:100%}.jspArrow{background:#50506d;text-indent:-20000px;display:block;cursor:pointer;padding:0;margin:0}.jspArrow.jspDisabled{cursor:default;background:#80808d}.jspVerticalBar .jspArrow{height:16px}.jspHorizontalBar .jspArrow{width:16px;float:left;height:100%}.jspVerticalBar .jspArrow:focus{outline:0}.jspCorner{background:#eeeef4;float:left;height:100%}* html .jspCorner{margin:0 -3px 0 0} \ No newline at end of file diff --git a/ajax/libs/jScrollPane/package.json b/ajax/libs/jScrollPane/package.json index 3fe8bd5677233c..3cc49e72d5365e 100644 --- a/ajax/libs/jScrollPane/package.json +++ b/ajax/libs/jScrollPane/package.json @@ -1,7 +1,7 @@ { "name": "jScrollPane", - "version": "2.0.14", - "filename": "jquery.jscrollpane.min.js", + "version": "2.0.22", + "filename": "script/jquery.jscrollpane.min.js", "description": "jScrollPane - cross browser styleable scrollbars with jQuery and CSS", "homepage": "http://jscrollpane.kelvinluck.com", "repositories": [