git.fiddlerwoaroof.com
Raw Blame History
(function () {
    var slice = Array.prototype.slice;
    function getBodyOffset(body) {
        var top = body.offsetTop;
        var left = body.offsetLeft;

        return {
            top: top,
            left: left
        };
    }
    function getOffset(elem) {
        var docElem;
        var body;
        var win;
        var clientTop;
        var clientLeft;
        var scrollTop;
        var scrollLeft;
        var box = {
            top: 0,
            left: 0
        };
        var doc = elem && elem.ownerDocument;

        if(!doc) {
            return;
        }
        if((body = doc.body) === elem) {
            return getBodyOffset(elem);
        }
        docElem = doc.documentElement;
        if(typeof elem.getBoundingClientRect !== "undefined") {
            box = elem.getBoundingClientRect();
        }
        win = window;
        clientTop = docElem.clientTop || body.clientTop || 0;
        clientLeft = docElem.clientLeft || body.clientLeft || 0;
        scrollTop = win.pageYOffset || docElem.scrollTop;
        scrollLeft = win.pageXOffset || docElem.scrollLeft;
        return {
            top: box.top + scrollTop - clientTop,
            left: box.left + scrollLeft - clientLeft
        };
    }
    function setStyle(elem, repl) {
        var style = elem.getAttribute('style').split(';');
        var newStyle = [];

        for(var i = 0; i < style.length; i++) {
            var both = style[i].split(':');
            var key = both[0];
            var value = both[1];

            if(key in repl) {
                newStyle.push(key + ':' + repl[key]);
            } else {
                newStyle.push(both);
            }
        }
        elem.setAttribute('style', newStyle.join(';'));
    }
    var cssPattern = /\s*(.*?)\s*{(.*?)}/g;
    var matchPosition = /\.*?position:.*?sticky.*?;/;
    var getTop = /\.*?top:(.*?);/;
    var toObserve = [];

    function parse(css) {
        var matches;
        var css = css.replace(/(\/\*([\s\S]*?)\*\/)|(\/\/(.*)$)/gm, '').replace(/\n|\r/g, '');

        while((matches = cssPattern.exec(css)) !== null) {
            var selector = matches[1];
            if(matchPosition.test(matches[2]) && selector !== "#modernizr") {
                var topMatch = getTop.exec(matches[2]);
                var topCSS = ((topMatch !== null) ? parseInt(topMatch[1]) : 0);

                var elems = slice.call(document.querySelectorAll(selector));
                elems.forEach(function (elem) {
                    var height = elem.offsetHeight;
                    var parent = elem.parentElement;
                    var parOff = getOffset(parent);
                    var parOffTop = ((parOff !== null && parOff.top !== null) ? parOff.top : 0);
                    var elmOff = getOffset(elem);
                    var elmOffTop = ((elmOff !== null && elmOff.top !== null) ? elmOff.top : 0);
                    var start = elmOffTop - topCSS;
                    var end = (parOffTop + parent.offsetHeight) - height - topCSS;
                    var newCSS = matches[2] + "position:fixed;width:" + elem.offsetWidth + "px;height:" + height + "px";

                    var dummy = document.createElement('div');
                    dummy.innerHTML = '<span style="position:static;display:block;height:' + height + 'px;"></span>';
                    toObserve.push({
                        element: elem,
                        parent: parent,
                        repl: dummy.firstElementChild,
                        start: start,
                        end: end,
                        oldCSS: matches[2],
                        newCSS: newCSS,
                        fixed: false
                    });
                });
            }
        }
    }
    window.addEventListener('scroll', function () {
        var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
        for(var i = 0; i < toObserve.length; i++) {
            var obj = toObserve[i];
            if(obj.fixed === false && scrollTop > obj.start && scrollTop < obj.end) {
                obj.element.setAttribute('style', obj.newCSS);
                obj.fixed = true;
                obj.element.classList.add('stuck');
            } else {
                if(obj.fixed === true) {
                    if(scrollTop < obj.start) {
                        obj.element.setAttribute('style', obj.oldCSS);
                        obj.fixed = false;
                        obj.element.classList.remove('stuck');
                    } else {
                        if(scrollTop > obj.end) {
                            var absolute = getOffset(obj.element);
                            absolute.position = "absolute";
                            obj.element.setAttribute('style', obj.newCSS);
                            setStyle(obj.element, absolute);
                            obj.fixed = false;
                            obj.element.classList.remove('stuck');
                        }
                    }
                }
            }
        }
    }, false);
    window.addEventListener('load', function () {
        var styles = slice.call(document.querySelectorAll('style'));
        styles.forEach(function (style) {
            var text = style.textContent || style.innerText;
            parse(text);
        });
        var links = slice.call(document.querySelectorAll('link'));
        links.forEach(function (link) {
            if(link.getAttribute('rel') !== 'stylesheet') {
                return;
            }
            var href = link.getAttribute('href');
            var req = new XMLHttpRequest();

            req.open('GET', href, true);
            req.onload = function (e) {
                parse(req.responseText);
            };
            req.send();
        });
    }, false);
})();