Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

scrollIntoViewIfNeeded() for IE7

If course it seems scrollIntoViewIfNeeded is a feature tendered only by WebKit. However I'm working on something that needs to be compatible with IE back to 7, and I need to detect whether something is visible, and if not, then call scrollIntoView() on it.

It's also important to note that I'm not dealing with whole windows, I could be dealing with a smaller DIV in which an element may be scrolled out of the viewable box.

For example, the element with id "pleaseFindMe" should be scrolled into view only if overflowed out of the viewable area of the div.

    <div style='border:1px solid black;width:40%; overflow:scroll;'>
        <span id='e2' style='white-space: nowrap;' >Lorem ipsum aliqua proident veniam et quis consectetur esse dolore non Ut nulla dolor eu culpa. Lorem ipsum sint cupidatat non et adipisicing esse elit officia. proident, sunt in culpa qui officia deserunt mollit anim <span id='pleaseFindMe'>id est</span> laborum. </span>
    </div>  
like image 293
andyortlieb Avatar asked Jul 12 '12 22:07

andyortlieb


2 Answers

Old question, but it seems still relevant on browsers today (IE, Fx). So I wrote some polyfill for scrollIntoViewIfNeeded().

if (!Element.prototype.scrollIntoViewIfNeeded) {
    Element.prototype.scrollIntoViewIfNeeded = function (centerIfNeeded) {
        "use strict";

        function makeRange(start, length) {
            return {"start": start, "length": length, "end": start + length};
        }

        function coverRange(inner, outer) {
            if (false === centerIfNeeded ||
                (outer.start < inner.end && inner.start < outer.end))
            {
                return Math.min(
                    inner.start, Math.max(outer.start, inner.end - outer.length)
                );
            }
            return (inner.start + inner.end - outer.length) / 2;
        }

        function makePoint(x, y) {
            return {
                "x": x, "y": y,
                "translate": function translate(dX, dY) {
                    return makePoint(x + dX, y + dY);
                }
            };
        }

        function absolute(elem, pt) {
            while (elem) {
                pt = pt.translate(elem.offsetLeft, elem.offsetTop);
                elem = elem.offsetParent;
            }
            return pt;
        }

        var target = absolute(this, makePoint(0, 0)),
            extent = makePoint(this.offsetWidth, this.offsetHeight),
            elem = this.parentNode,
            origin;

        while (elem instanceof HTMLElement) {
            // Apply desired scroll amount.
            origin = absolute(elem, makePoint(elem.clientLeft, elem.clientTop));
            elem.scrollLeft = coverRange(
                makeRange(target.x - origin.x, extent.x),
                makeRange(elem.scrollLeft, elem.clientWidth)
            );
            elem.scrollTop = coverRange(
                makeRange(target.y - origin.y, extent.y),
                makeRange(elem.scrollTop, elem.clientHeight)
            );

            // Determine actual scroll amount by reading back scroll properties.
            target = target.translate(-elem.scrollLeft, -elem.scrollTop);
            elem = elem.parentNode;
        }
    };
}

http://jsfiddle.net/obnpd7ra/

The code is designed to work well in the presence of nested scrollable areas and relatively positioned elements.

like image 97
joki Avatar answered Nov 14 '22 15:11

joki


IE has supported the beautiful element method getBoundingClientRect since IE4. Although it has some minor flaws in IE<8, it can definitely be used for your purpose.

So here's the trick:

var findMe = document.getElementById("pleaseFindMe"),
    contRect = container.getBoundingClientRect(),
    findMeRect = findMe.getBoundingClientRect();
if (findMeRect.top < contRect.top || findMeRect.bottom > contRect.bottom
       || findMeRect.right > contRect.right || findMeRect.left < contRect.left)
    findMe.scrollIntoView();
like image 9
MaxArt Avatar answered Nov 14 '22 16:11

MaxArt