xleotranx
3/2/2016 - 9:31 AM

Support centering an element when scrolling into view w3c issue: https://www.w3.org/Bugs/Public/show_bug.cgi?id=17152 Original code from

Support centering an element when scrolling into view

w3c issue: https://www.w3.org/Bugs/Public/show_bug.cgi?id=17152 Original code from http://jsbin.com/ilecok/16/

////////////////////////////////////////////////////////////////////////////////
// Author: Thaddee Tyl 2012.
// The following work is under CC0.

void function() {

// Hook the polyfill.
Element.prototype._scrollIntoView = function scrollIntoView(options) {
    if( !this.ownerDocument )return;
    
    var _window = this.ownerDocument.defaultView;
    
    // Traditional scrollIntoView.
    if( !arguments.length || typeof options != "object" ) {
        return this.scrollIntoView.apply(this, arguments);
    }
  
    // Fetch positional information.
    //
    // The following are always from the {top, bottom, left, right}
    // of the viewport, to the {top, …} of the box.
    // Think of them as geometrical vectors, it helps.
    // The axes are directed downwards and towards the right.
    
    var rect = this.getBoundingClientRect(),
        topToBottom = rect.bottom,
        bottomToTop = rect.top - _window.innerHeight,
        leftToRight = rect.right,
        rightToLeft = rect.left - _window.innerWidth,
        xAllowed = true,  // We allow one translation on the x axis,
        yAllowed = true;  // and one on the y axis.
    
    // Read options.
    //
    // We have the following options:
    // - float vertical = 0.5        (from 0 to 1).
    // - float horizontal = 0.0      (from 0 to 1).
    // - boolean notIfViewed = true
    
    if (options.vertical === undefined)  options.vertical = 0.5;
    if (options.horizontal === undefined)  options.horizontal = 0.5;
    if (options.evenIfViewed === undefined)  options.evenIfViewed = false;
    
    // Whatever `horizontal` and `vertical` are,
    // the behavior is the same if the box is (even partially) visible.
    
    if (topToBottom > 0 && topToBottom <= this.offsetHeight) {
        if (yAllowed) {
            _window.scrollBy(0, topToBottom - this.offsetHeight);
            yAllowed = false;
        }
    }
    else if (bottomToTop < 0 && bottomToTop >= -this.offsetHeight) {
        if (yAllowed) {
            _window.scrollBy(0, bottomToTop + this.offsetHeight);
            yAllowed = false;
        }
    }
    
    if (leftToRight > 0 && leftToRight <= this.offsetWidth) {
        if (xAllowed) {
            _window.scrollBy(leftToRight - this.offsetWidth, 0);
            xAllowed = false;
        }
    }
    else if (rightToLeft < 0 && rightToLeft >= -this.offsetWidth) {
        if (xAllowed) {
            _window.scrollBy(rightToLeft + this.offsetWidth, 0);
            xAllowed = false;
        }
    }
    
    // If we want it positioned in the viewport,
    // and the box is completely hidden,
    // then we position it explicitly.
    
    if( yAllowed
        && (options.evenIfViewed ? true : (topToBottom <= 0 || bottomToTop >= 0))
    ) {
        _window.scroll(
            _window.scrollX
            , _window.scrollY + rect.top - (_window.innerHeight - this.offsetHeight) * options.vertical
        );
    }
    
    if( xAllowed
        && (options.evenIfViewed ? true : (leftToRight <= 0 || rightToLeft <= 0))
    ) {
        _window.scroll(
            _window.scrollX + rect.left - (_window.innerWidth - this.offsetWidth) * options.horizontal
            , _window.scrollY
        );
    }  
    
    if (_window.parent !== _window) {
        // We are inside a scrollable element.
        
        var frame = _window.frameElement;
        scrollIntoView.call(frame, options);
    }
};

}.call(this);