Created
September 18, 2012 17:45
-
-
Save alisey/3744577 to your computer and use it in GitHub Desktop.
Scroll selection into view
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
// Scroll to selection focus, but only if it's out of view. Align selection | |
// focus with the top or bottom edge of its scroll-container. Return true | |
// on success. | |
// * there might be several nested scroll-containers, including window | |
// * must not try to scroll overflow:hidden and overflow:visible elements | |
// * no scrolling should happen if selection focus is visible | |
// * selection is not necessarily collapsed | |
// * range.getBoundingClientRect doesn't work for collapsed ranges | |
// * Opera reports incorrect startOffset and endOffset for collapsed ranges | |
// outside of text nodes (e.g. between 2 <br> elements), range.insertNode | |
// doesn't work correctly in that case too. | |
// * horizontal scroll is ignored | |
function scrollSelectionIntoView() { | |
var sel, range, marker, container, rect, top, bottom, | |
containerTop, containerBottom, scroll; | |
// IE8, IE9 | |
if (document.selection) { | |
// scrolls only if needed | |
document.selection.createRange().scrollIntoView(); | |
return true; | |
} | |
sel = window.getSelection(); | |
if (!sel.focusNode) { | |
return false; | |
} | |
// collapse to focus point | |
range = document.createRange(); | |
range.setStart(sel.focusNode, sel.focusOffset); | |
if ($.browser.opera && range.startContainer.nodeType == 1) { | |
return false; | |
} | |
// zero-width space | |
marker = $('<span style="visibility: hidden">\u200B</span>')[0]; | |
range.insertNode(marker); | |
container = marker; | |
if (marker.scrollIntoViewIfNeeded) { | |
marker.scrollIntoViewIfNeeded(true); // WebKit | |
} else while (container != window) { | |
container = container.parentNode || window; | |
if (container === window) { | |
containerTop = 0; | |
containerBottom = $(container).height(); | |
} else if ( | |
container.scrollHeight > container.clientHeight && | |
/scroll|auto/.test($(container).css('overflow')) | |
) { | |
rect = container.getBoundingClientRect(); | |
containerTop = rect.top; | |
containerBottom = rect.bottom; | |
} else { | |
continue; | |
} | |
rect = marker.getBoundingClientRect(); | |
top = rect.top; | |
bottom = rect.bottom; | |
scroll = $(container).scrollTop(); | |
if (top < containerTop) { | |
$(container).scrollTop(scroll + top - containerTop - 20); | |
} else if (bottom > containerBottom) { | |
$(container).scrollTop(scroll + bottom - containerBottom + 20); | |
} | |
} | |
container = marker.parentNode; | |
container.removeChild(marker); | |
container.normalize(); | |
return true; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment