Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
adding the extra setting "onlyNotVisible"
This addition adds the extra settings "onlyNotVisible", it wraps the main scrollTo in a check for this setting, if provided it checks if the passed target element is within the viewport, if it is then it does not scroll as its already within view range otherwise it does scroll to it.

This extra setting is only to be used with a jquery object or a dom selector id for the target parameter.
  • Loading branch information
lilpug authored Dec 10, 2016
commit 80a7d09797710ccb3dec96726f8e3d75c7d2a19a
247 changes: 138 additions & 109 deletions jquery.scrollTo.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,27 @@
$.inArray(elem.nodeName.toLowerCase(), ['iframe','#document','html','body']) !== -1;
}

//This function checks if the specified target is within the viewport of the current window
function IsInViewPort(target)
{
if (target != null)
{
//Gets the js element from a jquery object
var el = $(target)[0];

//Gets its boundary
var rect = el.getBoundingClientRect();

//Checks if its within the viewport of the window
return (
rect.top >= 0 &&
rect.left >= 0 &&
rect.bottom <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.right <= (window.innerWidth || document.documentElement.clientWidth)
);
}
}

$.fn.scrollTo = function(target, duration, settings) {
if (typeof duration === 'object') {
settings = duration;
Expand All @@ -50,116 +71,124 @@
}

settings = $.extend({}, $scrollTo.defaults, settings);
// Speed is still recognized for backwards compatibility
duration = duration || settings.duration;
// Make sure the settings are given right
var queue = settings.queue && settings.axis.length > 1;
if (queue) {
// Let's keep the overall duration
duration /= 2;
}
settings.offset = both(settings.offset);
settings.over = both(settings.over);

return this.each(function() {
// Null target yields nothing, just like jQuery does
if (target === null) return;

var win = isWin(this),
elem = win ? this.contentWindow || window : this,
$elem = $(elem),
targ = target,
attr = {},
toff;

switch (typeof targ) {
// A number will pass the regex
case 'number':
case 'string':
if (/^([+-]=?)?\d+(\.\d+)?(px|%)?$/.test(targ)) {
targ = both(targ);
// We are done
break;
}
// Relative/Absolute selector
targ = win ? $(targ) : $(targ, elem);
/* falls through */
case 'object':
if (targ.length === 0) return;
// DOMElement / jQuery
if (targ.is || targ.style) {
// Get the real position of the target
toff = (targ = $(targ)).offset();
}
}

var offset = $.isFunction(settings.offset) && settings.offset(elem, targ) || settings.offset;

$.each(settings.axis.split(''), function(i, axis) {
var Pos = axis === 'x' ? 'Left' : 'Top',
pos = Pos.toLowerCase(),
key = 'scroll' + Pos,
prev = $elem[key](),
max = $scrollTo.max(elem, axis);

if (toff) {// jQuery / DOMElement
attr[key] = toff[pos] + (win ? 0 : prev - $elem.offset()[pos]);

// If it's a dom element, reduce the margin
if (settings.margin) {
attr[key] -= parseInt(targ.css('margin'+Pos), 10) || 0;
attr[key] -= parseInt(targ.css('border'+Pos+'Width'), 10) || 0;
}

attr[key] += offset[pos] || 0;

if (settings.over[pos]) {
// Scroll to a fraction of its width/height
attr[key] += targ[axis === 'x'?'width':'height']() * settings.over[pos];
}
} else {
var val = targ[pos];
// Handle percentage values
attr[key] = val.slice && val.slice(-1) === '%' ?
parseFloat(val) / 100 * max
: val;
}

// Number or 'number'
if (settings.limit && /^\d+$/.test(attr[key])) {
// Check the limits
attr[key] = attr[key] <= 0 ? 0 : Math.min(attr[key], max);
}

// Don't waste time animating, if there's no need.
if (!i && settings.axis.length > 1) {
if (prev === attr[key]) {
// No animation needed
attr = {};
} else if (queue) {
// Intermediate animation
animate(settings.onAfterFirst);
// Don't animate this axis again in the next iteration.
attr = {};
}
}
});

animate(settings.onAfter);

function animate(callback) {
var opts = $.extend({}, settings, {
// The queue setting conflicts with animate()
// Force it to always be true
queue: true,
duration: duration,
complete: callback && function() {
callback.call(elem, targ, settings);
}
});
$elem.animate(attr, opts);
}
});
if (
settings.onlyNotVisible == null ||
settings.onlyNotVisible == false ||
(settings.onlyNotVisible == true && !IsInViewPort(target))
)
{
// Speed is still recognized for backwards compatibility
duration = duration || settings.duration;
// Make sure the settings are given right
var queue = settings.queue && settings.axis.length > 1;
if (queue) {
// Let's keep the overall duration
duration /= 2;
}
settings.offset = both(settings.offset);
settings.over = both(settings.over);

return this.each(function () {
// Null target yields nothing, just like jQuery does
if (target === null) return;

var win = isWin(this),
elem = win ? this.contentWindow || window : this,
$elem = $(elem),
targ = target,
attr = {},
toff;

switch (typeof targ) {
// A number will pass the regex
case 'number':
case 'string':
if (/^([+-]=?)?\d+(\.\d+)?(px|%)?$/.test(targ)) {
targ = both(targ);
// We are done
break;
}
// Relative/Absolute selector
targ = win ? $(targ) : $(targ, elem);
/* falls through */
case 'object':
if (targ.length === 0) return;
// DOMElement / jQuery
if (targ.is || targ.style) {
// Get the real position of the target
toff = (targ = $(targ)).offset();
}
}

var offset = $.isFunction(settings.offset) && settings.offset(elem, targ) || settings.offset;

$.each(settings.axis.split(''), function (i, axis) {
var Pos = axis === 'x' ? 'Left' : 'Top',
pos = Pos.toLowerCase(),
key = 'scroll' + Pos,
prev = $elem[key](),
max = $scrollTo.max(elem, axis);

if (toff) {// jQuery / DOMElement
attr[key] = toff[pos] + (win ? 0 : prev - $elem.offset()[pos]);

// If it's a dom element, reduce the margin
if (settings.margin) {
attr[key] -= parseInt(targ.css('margin' + Pos), 10) || 0;
attr[key] -= parseInt(targ.css('border' + Pos + 'Width'), 10) || 0;
}

attr[key] += offset[pos] || 0;

if (settings.over[pos]) {
// Scroll to a fraction of its width/height
attr[key] += targ[axis === 'x' ? 'width' : 'height']() * settings.over[pos];
}
} else {
var val = targ[pos];
// Handle percentage values
attr[key] = val.slice && val.slice(-1) === '%' ?
parseFloat(val) / 100 * max
: val;
}

// Number or 'number'
if (settings.limit && /^\d+$/.test(attr[key])) {
// Check the limits
attr[key] = attr[key] <= 0 ? 0 : Math.min(attr[key], max);
}

// Don't waste time animating, if there's no need.
if (!i && settings.axis.length > 1) {
if (prev === attr[key]) {
// No animation needed
attr = {};
} else if (queue) {
// Intermediate animation
animate(settings.onAfterFirst);
// Don't animate this axis again in the next iteration.
attr = {};
}
}
});

animate(settings.onAfter);

function animate(callback) {
var opts = $.extend({}, settings, {
// The queue setting conflicts with animate()
// Force it to always be true
queue: true,
duration: duration,
complete: callback && function () {
callback.call(elem, targ, settings);
}
});
$elem.animate(attr, opts);
}
});
}
};

// Max scrolling position, works on quirks mode
Expand Down