Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenaka Moorthi <benaka.moorthi@gmail.com>2013-08-10 03:25:50 +0400
committerBenaka Moorthi <benaka.moorthi@gmail.com>2013-08-10 03:25:50 +0400
commita3bc6979a99444f29da1aa7973338e3dcd72d309 (patch)
tree2ac49526db2e40a9a3dfedd0b95cb68b07062265 /libs/jquery
parentcfb17ed2795101ea90d71d124d91b0cbad09858c (diff)
Refs #3089, add initial visitor profile popup that uses dynamic data from Live plugin API. No client-side behavior yet & placeholder images still present.
Diffstat (limited to 'libs/jquery')
-rw-r--r--libs/jquery/images/down_arrow.pngbin0 -> 2898 bytes
-rw-r--r--libs/jquery/images/scroller.pngbin0 -> 3329 bytes
-rw-r--r--libs/jquery/images/slide.pngbin0 -> 2831 bytes
-rw-r--r--libs/jquery/images/up_arrow.pngbin0 -> 2881 bytes
-rw-r--r--libs/jquery/jquery.jscrollpane.js1341
-rw-r--r--libs/jquery/jquery.mousewheel.js117
-rw-r--r--libs/jquery/mwheelIntent.js76
-rw-r--r--libs/jquery/stylesheets/jquery.jscrollpane.css119
-rw-r--r--libs/jquery/stylesheets/scroll.less140
9 files changed, 1793 insertions, 0 deletions
diff --git a/libs/jquery/images/down_arrow.png b/libs/jquery/images/down_arrow.png
new file mode 100644
index 0000000000..a364892c7d
--- /dev/null
+++ b/libs/jquery/images/down_arrow.png
Binary files differ
diff --git a/libs/jquery/images/scroller.png b/libs/jquery/images/scroller.png
new file mode 100644
index 0000000000..ddcab93426
--- /dev/null
+++ b/libs/jquery/images/scroller.png
Binary files differ
diff --git a/libs/jquery/images/slide.png b/libs/jquery/images/slide.png
new file mode 100644
index 0000000000..657b9a6de5
--- /dev/null
+++ b/libs/jquery/images/slide.png
Binary files differ
diff --git a/libs/jquery/images/up_arrow.png b/libs/jquery/images/up_arrow.png
new file mode 100644
index 0000000000..c7cb24c2b4
--- /dev/null
+++ b/libs/jquery/images/up_arrow.png
Binary files differ
diff --git a/libs/jquery/jquery.jscrollpane.js b/libs/jquery/jquery.jscrollpane.js
new file mode 100644
index 0000000000..48d8be8537
--- /dev/null
+++ b/libs/jquery/jquery.jscrollpane.js
@@ -0,0 +1,1341 @@
+/*!
+ * jScrollPane - v2.0.0beta12 - 2012-09-27
+ * 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.0beta12, Last updated: 2012-09-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.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.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();
+ paneHeight = elem.innerHeight();
+
+ elem.width(paneWidth);
+
+ pane = $('<div class="jspPane" />').css('padding', originalPadding).append(elem.children());
+ container = $('<div class="jspContainer" />')
+ .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(
+ $('<div class="jspVerticalBar" />').append(
+ $('<div class="jspCap jspCapTop" />'),
+ $('<div class="jspTrack" />').append(
+ $('<div class="jspDrag" />').append(
+ $('<div class="jspDragTop" />'),
+ $('<div class="jspDragBottom" />')
+ )
+ ),
+ $('<div class="jspCap jspCapBottom" />')
+ )
+ );
+
+ verticalBar = container.find('>.jspVerticalBar');
+ verticalTrack = verticalBar.find('>.jspTrack');
+ verticalDrag = verticalTrack.find('>.jspDrag');
+
+ if (settings.showArrows) {
+ arrowUp = $('<a class="jspArrow jspArrowUp" />').bind(
+ 'mousedown.jsp', getArrowScroll(0, -1)
+ ).bind('click.jsp', nil);
+ arrowDown = $('<a class="jspArrow jspArrowDown" />').bind(
+ 'mousedown.jsp', getArrowScroll(0, 1)
+ ).bind('click.jsp', nil);
+ if (settings.arrowScrollOnHover) {
+ arrowUp.bind('mouseover.jsp', getArrowScroll(0, -1, arrowUp));
+ arrowDown.bind('mouseover.jsp', getArrowScroll(0, 1, arrowDown));
+ }
+
+ appendArrows(verticalTrack, settings.verticalArrowPositions, arrowUp, arrowDown);
+ }
+
+ verticalTrackHeight = paneHeight;
+ container.find('>.jspVerticalBar>.jspCap:visible,>.jspVerticalBar>.jspArrow').each(
+ function () {
+ verticalTrackHeight -= $(this).outerHeight();
+ }
+ );
+
+
+ verticalDrag.hover(
+ function () {
+ verticalDrag.addClass('jspHover');
+ },
+ function () {
+ verticalDrag.removeClass('jspHover');
+ }
+ ).bind(
+ 'mousedown.jsp',
+ function (e) {
+ // Stop IE from allowing text selection
+ $('html').bind('dragstart.jsp selectstart.jsp', 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(
+ $('<div class="jspHorizontalBar" />').append(
+ $('<div class="jspCap jspCapLeft" />'),
+ $('<div class="jspTrack" />').append(
+ $('<div class="jspDrag" />').append(
+ $('<div class="jspDragLeft" />'),
+ $('<div class="jspDragRight" />')
+ )
+ ),
+ $('<div class="jspCap jspCapRight" />')
+ )
+ );
+
+ horizontalBar = container.find('>.jspHorizontalBar');
+ horizontalTrack = horizontalBar.find('>.jspTrack');
+ horizontalDrag = horizontalTrack.find('>.jspDrag');
+
+ if (settings.showArrows) {
+ arrowLeft = $('<a class="jspArrow jspArrowLeft" />').bind(
+ 'mousedown.jsp', getArrowScroll(-1, 0)
+ ).bind('click.jsp', nil);
+ arrowRight = $('<a class="jspArrow jspArrowRight" />').bind(
+ 'mousedown.jsp', getArrowScroll(1, 0)
+ ).bind('click.jsp', nil);
+ if (settings.arrowScrollOnHover) {
+ arrowLeft.bind('mouseover.jsp', getArrowScroll(-1, 0, arrowLeft));
+ arrowRight.bind('mouseover.jsp', getArrowScroll(1, 0, arrowRight));
+ }
+ appendArrows(horizontalTrack, settings.horizontalArrowPositions, arrowLeft, arrowRight);
+ }
+
+ horizontalDrag.hover(
+ function () {
+ horizontalDrag.addClass('jspHover');
+ },
+ function () {
+ horizontalDrag.removeClass('jspHover');
+ }
+ ).bind(
+ 'mousedown.jsp',
+ function (e) {
+ // Stop IE from allowing text selection
+ $('html').bind('dragstart.jsp selectstart.jsp', 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(
+ $('<div class="jspCorner" />').css('width', horizontalTrackHeight + 'px')
+ );
+ sizeVerticalScrollbar();
+ sizeHorizontalScrollbar();
+ }
+ // reflow content
+ if (isScrollableH) {
+ pane.width((container.outerWidth() - originalPaddingTotalWidth) + 'px');
+ }
+ contentHeight = pane.outerHeight();
+ percentInViewV = contentHeight / paneHeight;
+
+ if (isScrollableH) {
+ horizontalDragWidth = 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 <base>-Tag or Links not starting with the hash #
+ // e.g. <a href="index.html#test"> 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
+ 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/libs/jquery/jquery.mousewheel.js b/libs/jquery/jquery.mousewheel.js
new file mode 100644
index 0000000000..9d65c7162b
--- /dev/null
+++ b/libs/jquery/jquery.mousewheel.js
@@ -0,0 +1,117 @@
+/*! Copyright (c) 2013 Brandon Aaron (http://brandonaaron.net)
+ * Licensed under the MIT License (LICENSE.txt).
+ *
+ * Thanks to: http://adomas.org/javascript-mouse-wheel/ for some pointers.
+ * Thanks to: Mathias Bank(http://www.mathias-bank.de) for a scope bug fix.
+ * Thanks to: Seamus Leahy for adding deltaX and deltaY
+ *
+ * Version: 3.1.3
+ *
+ * Requires: 1.2.2+
+ */
+
+(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;
+ } else {
+ // Browser globals
+ factory(jQuery);
+ }
+}(function ($) {
+
+ var toFix = ['wheel', 'mousewheel', 'DOMMouseScroll', 'MozMousePixelScroll'];
+ var toBind = 'onwheel' in document || document.documentMode >= 9 ? ['wheel'] : ['mousewheel', 'DomMouseScroll', 'MozMousePixelScroll'];
+ var lowestDelta, lowestDeltaXY;
+
+ if ( $.event.fixHooks ) {
+ for ( var i = toFix.length; i; ) {
+ $.event.fixHooks[ toFix[--i] ] = $.event.mouseHooks;
+ }
+ }
+
+ $.event.special.mousewheel = {
+ setup: function() {
+ if ( this.addEventListener ) {
+ for ( var i = toBind.length; i; ) {
+ this.addEventListener( toBind[--i], handler, false );
+ }
+ } else {
+ this.onmousewheel = handler;
+ }
+ },
+
+ teardown: function() {
+ if ( this.removeEventListener ) {
+ for ( var i = toBind.length; i; ) {
+ this.removeEventListener( toBind[--i], handler, false );
+ }
+ } else {
+ this.onmousewheel = null;
+ }
+ }
+ };
+
+ $.fn.extend({
+ mousewheel: function(fn) {
+ return fn ? this.bind("mousewheel", fn) : this.trigger("mousewheel");
+ },
+
+ unmousewheel: function(fn) {
+ return this.unbind("mousewheel", fn);
+ }
+ });
+
+
+ function handler(event) {
+ var orgEvent = event || window.event,
+ args = [].slice.call(arguments, 1),
+ delta = 0,
+ deltaX = 0,
+ deltaY = 0,
+ absDelta = 0,
+ absDeltaXY = 0,
+ fn;
+ event = $.event.fix(orgEvent);
+ event.type = "mousewheel";
+
+ // Old school scrollwheel delta
+ if ( orgEvent.wheelDelta ) { delta = orgEvent.wheelDelta; }
+ if ( orgEvent.detail ) { delta = orgEvent.detail * -1; }
+
+ // New school wheel delta (wheel event)
+ if ( orgEvent.deltaY ) {
+ deltaY = orgEvent.deltaY * -1;
+ delta = deltaY;
+ }
+ if ( orgEvent.deltaX ) {
+ deltaX = orgEvent.deltaX;
+ delta = deltaX * -1;
+ }
+
+ // Webkit
+ if ( orgEvent.wheelDeltaY !== undefined ) { deltaY = orgEvent.wheelDeltaY; }
+ if ( orgEvent.wheelDeltaX !== undefined ) { deltaX = orgEvent.wheelDeltaX * -1; }
+
+ // Look for lowest delta to normalize the delta values
+ absDelta = Math.abs(delta);
+ if ( !lowestDelta || absDelta < lowestDelta ) { lowestDelta = absDelta; }
+ absDeltaXY = Math.max(Math.abs(deltaY), Math.abs(deltaX));
+ if ( !lowestDeltaXY || absDeltaXY < lowestDeltaXY ) { lowestDeltaXY = absDeltaXY; }
+
+ // Get a whole value for the deltas
+ fn = delta > 0 ? 'floor' : 'ceil';
+ delta = Math[fn](delta / lowestDelta);
+ deltaX = Math[fn](deltaX / lowestDeltaXY);
+ deltaY = Math[fn](deltaY / lowestDeltaXY);
+
+ // Add event and delta to the front of the arguments
+ args.unshift(event, delta, deltaX, deltaY);
+
+ return ($.event.dispatch || $.event.handle).apply(this, args);
+ }
+
+}));
diff --git a/libs/jquery/mwheelIntent.js b/libs/jquery/mwheelIntent.js
new file mode 100644
index 0000000000..72b7d135ca
--- /dev/null
+++ b/libs/jquery/mwheelIntent.js
@@ -0,0 +1,76 @@
+/**
+ * @author trixta
+ * @version 1.2
+ */
+(function($){
+
+ var mwheelI = {
+ pos: [-260, -260]
+ },
+ minDif = 3,
+ doc = document,
+ root = doc.documentElement,
+ body = doc.body,
+ longDelay, shortDelay
+ ;
+
+ function unsetPos(){
+ if(this === mwheelI.elem){
+ mwheelI.pos = [-260, -260];
+ mwheelI.elem = false;
+ minDif = 3;
+ }
+ }
+
+ $.event.special.mwheelIntent = {
+ setup: function(){
+ var jElm = $(this).bind('mousewheel', $.event.special.mwheelIntent.handler);
+ if( this !== doc && this !== root && this !== body ){
+ jElm.bind('mouseleave', unsetPos);
+ }
+ jElm = null;
+ return true;
+ },
+ teardown: function(){
+ $(this)
+ .unbind('mousewheel', $.event.special.mwheelIntent.handler)
+ .unbind('mouseleave', unsetPos)
+ ;
+ return true;
+ },
+ handler: function(e, d){
+ var pos = [e.clientX, e.clientY];
+ if( this === mwheelI.elem || Math.abs(mwheelI.pos[0] - pos[0]) > minDif || Math.abs(mwheelI.pos[1] - pos[1]) > minDif ){
+ mwheelI.elem = this;
+ mwheelI.pos = pos;
+ minDif = 250;
+
+ clearTimeout(shortDelay);
+ shortDelay = setTimeout(function(){
+ minDif = 10;
+ }, 200);
+ clearTimeout(longDelay);
+ longDelay = setTimeout(function(){
+ minDif = 3;
+ }, 1500);
+ e = $.extend({}, e, {type: 'mwheelIntent'});
+ return $.event.dispatch.apply(this, arguments);
+ }
+ }
+ };
+ $.fn.extend({
+ mwheelIntent: function(fn) {
+ return fn ? this.bind("mwheelIntent", fn) : this.trigger("mwheelIntent");
+ },
+
+ unmwheelIntent: function(fn) {
+ return this.unbind("mwheelIntent", fn);
+ }
+ });
+
+ $(function(){
+ body = doc.body;
+ //assume that document is always scrollable, doesn't hurt if not
+ $(doc).bind('mwheelIntent.mwheelIntentDefault', $.noop);
+ });
+})(jQuery);
diff --git a/libs/jquery/stylesheets/jquery.jscrollpane.css b/libs/jquery/stylesheets/jquery.jscrollpane.css
new file mode 100644
index 0000000000..0364216fe0
--- /dev/null
+++ b/libs/jquery/stylesheets/jquery.jscrollpane.css
@@ -0,0 +1,119 @@
+/*
+ * 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: 8px;
+ 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;
+}
+
+.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/libs/jquery/stylesheets/scroll.less b/libs/jquery/stylesheets/scroll.less
new file mode 100644
index 0000000000..508adb4c7a
--- /dev/null
+++ b/libs/jquery/stylesheets/scroll.less
@@ -0,0 +1,140 @@
+/*
+ * 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%;
+}
+
+.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: url("../images/slide.png") transparent no-repeat 7px;
+ position: relative;
+ background-size: 20% 100%;
+ /*height: 447px!important;*/
+}
+
+.jspDrag
+{
+ background: url("../images/scroller.png") transparent no-repeat;
+ background-size: 100% 100%;
+ width: 17px;
+ position: relative;
+ top: 0;
+ left: 0;
+ cursor: pointer;
+}
+
+.jspHorizontalBar .jspTrack,
+.jspHorizontalBar .jspDrag
+{
+ float: left;
+ height: 100%;
+}
+
+.jspArrow
+{
+
+ text-indent: -20000px;
+ display: block;
+ cursor: pointer;
+}
+.jspArrowDown{
+ background: url("../images/down_arrow.png") transparent no-repeat;
+}
+.jspArrowUp{
+ background: url("../images/up_arrow.png") transparent no-repeat;
+}
+
+.jspVerticalBar .jspArrow
+{
+ height: 14px;
+
+}
+
+.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;
+}
+
+/* Styles specific to this particular page */
+.scroll-pane-before,
+.scroll-pane-after,
+.scroll-pane-split,
+.scroll-pane-os
+{
+ width: 100%;
+ height: 200px;
+ overflow: auto;
+}
+.horizontal-only
+{
+ height: auto;
+ max-height: 200px;
+}