249 lines
7 KiB
JavaScript
249 lines
7 KiB
JavaScript
(function($) {
|
|
var version = '1.4.13',
|
|
optionOverrides = {},
|
|
defaults = {
|
|
exclude: [],
|
|
excludeWithin:[],
|
|
offset: 0,
|
|
|
|
// one of 'top' or 'left'
|
|
direction: 'top',
|
|
|
|
// jQuery set of elements you wish to scroll (for $.smoothScroll).
|
|
// if null (default), $('html, body').firstScrollable() is used.
|
|
scrollElement: null,
|
|
|
|
// only use if you want to override default behavior
|
|
scrollTarget: null,
|
|
|
|
// fn(opts) function to be called before scrolling occurs.
|
|
// `this` is the element(s) being scrolled
|
|
beforeScroll: function() {},
|
|
|
|
// fn(opts) function to be called after scrolling occurs.
|
|
// `this` is the triggering element
|
|
afterScroll: function() {},
|
|
easing: 'swing',
|
|
speed: 400,
|
|
|
|
// coefficient for "auto" speed
|
|
autoCoefficent: 2,
|
|
|
|
// $.fn.smoothScroll only: whether to prevent the default click action
|
|
preventDefault: true
|
|
},
|
|
|
|
getScrollable = function(opts) {
|
|
var scrollable = [],
|
|
scrolled = false,
|
|
dir = opts.dir && opts.dir == 'left' ? 'scrollLeft' : 'scrollTop';
|
|
|
|
this.each(function() {
|
|
|
|
if (this == document || this == window) { return; }
|
|
var el = $(this);
|
|
if ( el[dir]() > 0 ) {
|
|
scrollable.push(this);
|
|
} else {
|
|
// if scroll(Top|Left) === 0, nudge the element 1px and see if it moves
|
|
el[dir](1);
|
|
scrolled = el[dir]() > 0;
|
|
if ( scrolled ) {
|
|
scrollable.push(this);
|
|
}
|
|
// then put it back, of course
|
|
el[dir](0);
|
|
}
|
|
});
|
|
|
|
// If no scrollable elements, fall back to <body>,
|
|
// if it's in the jQuery collection
|
|
// (doing this because Safari sets scrollTop async,
|
|
// so can't set it to 1 and immediately get the value.)
|
|
if (!scrollable.length) {
|
|
this.each(function(index) {
|
|
if (this.nodeName === 'BODY') {
|
|
scrollable = [this];
|
|
}
|
|
});
|
|
}
|
|
|
|
// Use the first scrollable element if we're calling firstScrollable()
|
|
if ( opts.el === 'first' && scrollable.length > 1 ) {
|
|
scrollable = [ scrollable[0] ];
|
|
}
|
|
|
|
return scrollable;
|
|
},
|
|
isTouch = 'ontouchend' in document;
|
|
|
|
$.fn.extend({
|
|
scrollable: function(dir) {
|
|
var scrl = getScrollable.call(this, {dir: dir});
|
|
return this.pushStack(scrl);
|
|
},
|
|
firstScrollable: function(dir) {
|
|
var scrl = getScrollable.call(this, {el: 'first', dir: dir});
|
|
return this.pushStack(scrl);
|
|
},
|
|
|
|
smoothScroll: function(options, extra) {
|
|
options = options || {};
|
|
|
|
if ( options === 'options' ) {
|
|
if ( !extra ) {
|
|
return this.first().data('ssOpts');
|
|
}
|
|
return this.each(function() {
|
|
var $this = $(this),
|
|
opts = $.extend($this.data('ssOpts') || {}, extra);
|
|
|
|
$(this).data('ssOpts', opts);
|
|
});
|
|
}
|
|
|
|
var opts = $.extend({}, $.fn.smoothScroll.defaults, options),
|
|
locationPath = $.smoothScroll.filterPath(location.pathname);
|
|
|
|
this
|
|
.unbind('click.smoothscroll')
|
|
.bind('click.smoothscroll', function(event) {
|
|
var link = this,
|
|
$link = $(this),
|
|
thisOpts = $.extend({}, opts, $link.data('ssOpts') || {}),
|
|
exclude = opts.exclude,
|
|
excludeWithin = thisOpts.excludeWithin,
|
|
elCounter = 0, ewlCounter = 0,
|
|
include = true,
|
|
clickOpts = {},
|
|
hostMatch = ((location.hostname === link.hostname) || !link.hostname),
|
|
pathMatch = thisOpts.scrollTarget || ( $.smoothScroll.filterPath(link.pathname) || locationPath ) === locationPath,
|
|
thisHash = escapeSelector(link.hash);
|
|
|
|
if ( !thisOpts.scrollTarget && (!hostMatch || !pathMatch || !thisHash) ) {
|
|
include = false;
|
|
} else {
|
|
while (include && elCounter < exclude.length) {
|
|
if ($link.is(escapeSelector(exclude[elCounter++]))) {
|
|
include = false;
|
|
}
|
|
}
|
|
while ( include && ewlCounter < excludeWithin.length ) {
|
|
if ($link.closest(excludeWithin[ewlCounter++]).length) {
|
|
include = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( include ) {
|
|
|
|
if ( thisOpts.preventDefault ) {
|
|
event.preventDefault();
|
|
}
|
|
|
|
$.extend( clickOpts, thisOpts, {
|
|
scrollTarget: thisOpts.scrollTarget || thisHash,
|
|
link: link
|
|
});
|
|
$.smoothScroll( clickOpts );
|
|
}
|
|
});
|
|
|
|
return this;
|
|
}
|
|
});
|
|
|
|
$.smoothScroll = function(options, px) {
|
|
if ( options === 'options' && typeof px === 'object' ) {
|
|
return $.extend(optionOverrides, px);
|
|
}
|
|
var opts, $scroller, scrollTargetOffset, speed,
|
|
scrollerOffset = 0,
|
|
offPos = 'offset',
|
|
scrollDir = 'scrollTop',
|
|
aniProps = {},
|
|
aniOpts = {},
|
|
scrollprops = [];
|
|
|
|
if (typeof options === 'number') {
|
|
opts = $.extend({link: null}, $.fn.smoothScroll.defaults, optionOverrides);
|
|
scrollTargetOffset = options;
|
|
} else {
|
|
opts = $.extend({link: null}, $.fn.smoothScroll.defaults, options || {}, optionOverrides);
|
|
if (opts.scrollElement) {
|
|
offPos = 'position';
|
|
if (opts.scrollElement.css('position') == 'static') {
|
|
opts.scrollElement.css('position', 'relative');
|
|
}
|
|
}
|
|
}
|
|
|
|
scrollDir = opts.direction == 'left' ? 'scrollLeft' : scrollDir;
|
|
|
|
if ( opts.scrollElement ) {
|
|
$scroller = opts.scrollElement;
|
|
if ( !(/^(?:HTML|BODY)$/).test($scroller[0].nodeName) ) {
|
|
scrollerOffset = $scroller[scrollDir]();
|
|
}
|
|
} else {
|
|
$scroller = $('html, body').firstScrollable(opts.direction);
|
|
}
|
|
|
|
// beforeScroll callback function must fire before calculating offset
|
|
opts.beforeScroll.call($scroller, opts);
|
|
|
|
scrollTargetOffset = (typeof options === 'number') ? options :
|
|
px ||
|
|
( $(opts.scrollTarget)[offPos]() &&
|
|
$(opts.scrollTarget)[offPos]()[opts.direction] ) ||
|
|
0;
|
|
|
|
aniProps[scrollDir] = scrollTargetOffset + scrollerOffset + opts.offset;
|
|
speed = opts.speed;
|
|
|
|
// automatically calculate the speed of the scroll based on distance / coefficient
|
|
if (speed === 'auto') {
|
|
|
|
// if aniProps[scrollDir] == 0 then we'll use scrollTop() value instead
|
|
speed = aniProps[scrollDir] || $scroller.scrollTop();
|
|
|
|
// divide the speed by the coefficient
|
|
speed = speed / opts.autoCoefficent;
|
|
}
|
|
|
|
aniOpts = {
|
|
duration: speed,
|
|
easing: opts.easing,
|
|
complete: function() {
|
|
opts.afterScroll.call(opts.link, opts);
|
|
}
|
|
};
|
|
|
|
if (opts.step) {
|
|
aniOpts.step = opts.step;
|
|
}
|
|
|
|
if ($scroller.length) {
|
|
$scroller.stop().animate(aniProps, aniOpts);
|
|
} else {
|
|
opts.afterScroll.call(opts.link, opts);
|
|
}
|
|
};
|
|
|
|
$.smoothScroll.version = version;
|
|
$.smoothScroll.filterPath = function(string) {
|
|
return string
|
|
.replace(/^\//,'')
|
|
.replace(/(?:index|default).[a-zA-Z]{3,4}$/,'')
|
|
.replace(/\/$/,'');
|
|
};
|
|
|
|
// default options
|
|
$.fn.smoothScroll.defaults = defaults;
|
|
|
|
function escapeSelector (str) {
|
|
return str.replace(/(:|\.)/g,'\\$1');
|
|
}
|
|
|
|
})(jQuery);
|