Created
February 24, 2016 02:12
-
-
Save 303182519/c0ff6d54c25b38ff90ed to your computer and use it in GitHub Desktop.
jScrollPane源码阅读
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/*! | |
* 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 dwfis.define === 'function') { | |
// AMD. Register as an anonymous module. | |
module.exports = factory(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; | |
//第一次肯定为undefined,设置整体的html结构 | |
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" />').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, | |
left: 0, | |
width: container.width() - originalPaddingTotalWidth | |
}); | |
removeMousewheel(); | |
removeFocusHandler(); | |
removeKeyboardNav(); | |
removeClickOnTrack(); | |
} else { | |
elem.addClass('jspScrollable'); | |
//当reinitialised,保持之前的位置 | |
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) { | |
verticalBar = $('<div class="jspVerticalBar" />'); | |
verticalTrack = $('<div class="jspTrack" />'); | |
verticalDrag = $('<div class="jspDrag" />'); | |
container.append( | |
verticalBar.append( | |
//$('<div class="jspCap jspCapTop" />'), | |
verticalTrack.append( | |
/*$('<div class="jspDrag" />').append( | |
$('<div class="jspDragTop" />'), | |
$('<div class="jspDragBottom" />') | |
)*/ | |
verticalDrag | |
) | |
//$('<div class="jspCap jspCapBottom" />') | |
) | |
); | |
//不需要上下按钮 | |
/*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(); | |
} | |
);*/ | |
//假如这里重新定义的话,会导致重复绑定,前面container.find('>.jspVerticalBar,>.jspHorizontalBar').remove().end(),jq内部可以把绑定事件也一起清理 | |
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 || 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) | |
{ | |
console.log($(e.target)) | |
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 <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 | |
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 | |
// 这里上面的$.extend已经做了 | |
/*$.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 | |
}; | |
})); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
good job