Skip to content

Instantly share code, notes, and snippets.

@nkcmr
Created February 4, 2015 21:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nkcmr/c2a468750588ef5c4d14 to your computer and use it in GitHub Desktop.
Save nkcmr/c2a468750588ef5c4d14 to your computer and use it in GitHub Desktop.
$.fn.scrollIntoView
define([], function() {
function stripWrapper(ele) {
return (ele instanceof jQuery || ele instanceof angular.element) ? ele[0] : ele;
}
function getRect(el) {
el = stripWrapper(el);
return _.pick(el.getBoundingClientRect(), 'top', 'left', 'bottom', 'right', 'width', 'height');
}
$.fn.doesScroll = function doesScroll() {
var _this = stripWrapper(this);
return ((_this.scrollTop != ((_this.scrollTop += 1) === null ||
_this.scrollTop) && (_this.scrollTop -= 1) !== null) ||
(_this.scrollTop != ((_this.scrollTop -= 1) === null ||
_this.scrollTop) && (_this.scrollTop += 1) !== null));
};
function findNearestScrollingParent(ele) {
var parents = $(ele).parents();
parents = [].slice.call(parents);
// find the nearest
return _.find(parents, function(p) {
return $(p).doesScroll();
});
}
function upmostScroller() {
/*
quirkiness:
in chrome the upmost scroller is the `body`. according to W3C, this is wrong.
the upmost scroller is supposed to be the `documentElement`
here, we resolve that quirkiness
*/
if ((/chrome/i).test(navigator.userAgent)) {
return document.body;
} else {
return document.documentElement;
}
}
$.fn.scrollIntoView = function scrollIntoView(opts) {
opts = opts || {};
var parent,
parentOffset,
view,
eleRect,
ele = this,
scrollX,
scrollY,
duration = (_.isNumber(opts.duration) ? opts.duration : 100),
padding = opts.padding || 10;
parent = findNearestScrollingParent(this);
// nothing in this hierarchy scrolls
if (!parent) {
return;
}
parentOffset = $(parent).offset();
eleRect = getRect(ele);
if (parent.tagName == 'BODY' || parent.tagName == 'HTML') {
view = {};
view.top = 0;
view.left = 0;
view.bottom = window.innerHeight;
view.right = window.innerWidth;
view.width = window.innerWidth;
view.height = window.innerHeight;
parent = upmostScroller();
scrollY = window.pageYOffset;
scrollX = window.pageXOffset;
} else {
view = {};
view.top = parentOffset.top;
view.left = parentOffset.left;
view.right = view.left + parent.clientWidth;
view.bottom = view.top + parent.clientHeight;
view.width = parent.clientWidth;
view.height = parent.clientHeight;
scrollY = parent.scrollTop;
scrollX = parent.scrollLeft;
eleRect.left = window.pageXOffset + eleRect.left;
eleRect.right = window.pageXOffset + eleRect.right;
eleRect.top = window.pageYOffset + eleRect.top;
eleRect.bottom = window.pageYOffset + eleRect.bottom;
}
if (eleRect.left < view.left) {
scrollX += eleRect.left - (view.left + padding);
} else if (eleRect.right > view.right) {
scrollX += eleRect.right - (view.right - padding);
}
if (eleRect.top < view.top) {
scrollY += eleRect.top - (view.top + padding);
} else if (eleRect.bottom > view.bottom) {
scrollY += eleRect.bottom - (view.bottom - padding);
}
if (duration === 0) {
parent.scrollTop = scrollY;
parent.scrollLeft = scrollX;
} else {
$(parent).animate({
scrollTop: scrollY,
scrollLeft: scrollX
}, duration);
}
};
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment