xkcd Tweaks

Some tweaks to xkcd.com and what-if.xkcd.com

目前为 2016-08-11 提交的版本。查看 最新版本

// ==UserScript==
// @name          xkcd Tweaks
// @description   Some tweaks to xkcd.com and what-if.xkcd.com
// @include       /^(https?:)?(\/\/)?(www\.)?(what-?if\.)?xkcd\.com/
// @author        Mital Ashok
// @icon          data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAABX0lEQVRYhcWVMZIEIQhFOYrhHM8baGjoEbyRYYcehY2cchXwt7O9Q1VXzQDKAxSJiPjLH/G3xARwzi20zrnnAaTAT4GIAGjvJAkhLH4hBBxgzl5ZIFbBqpxWsQXAyk4CQYJbEH8GcNo2EQAVC2CU1to9gE8rIJW6t2gLoDlKC8dAyPWEAOZslAWLDYWGAE5ONBFxa00N3s8BBGCBbO6z2f/bAPPmiM/H11AjtzL03sMA3nsM4M5YfQRgLJn2WxK09CZAz75nOm4y206rpgJIAeYsJJ9T6AVAGzKW7hR6AZDKNZZV0xsb/9IZoPIB211DLbgGPdpEgFlmoN2JZmautS7QtVbVfzsHXq/XorNevJQSExGXUriUwkTEKaX7AJ3+ui5Rv9mQY4wcYzybA1YgFGD+r7UBGkSorWecc37rcs5mG0SAu1nO+nHej+/EvwGgehFgvD47AHQdYMOe0qe+Hzm8hknb8QYpAAAAAElFTkSuQmCC
// @namespace     https://greasyfork.org/en/users/59570-mital-ashok
// @license       http://creativecommons.org/licenses/by-sa/4.0/
// @version       1.0.1
// @grant         none
// @noframes
// ==/UserScript==


(function() {
    var border = true,
        hr = true,
        titleText = true,
        snap = true,
        explainButton = true,
        transcript = true;


    var location = window.location.href.toLowerCase().replace(/^(?:https?:)?(?:\/\/)?(?:www\.)?/, 'https://')
                                                     .replace(/^(?:https:\/\/)whatif/, 'https://what-if')
                                                     .replace(/(?:^https(?=:\/\/xkcd\.com\/1663(\/|$)))/, 'http');
                                                     // Comic 1663 (Garden) does not work over https.
    if (location !== window.location.href) {
        window.location.replace(location);
        return;
    }
    
    function repeat(interval, func, onCompletion) {
        if (typeof onCompletion === 'undefined') {
            onCompletion = function() {};
        }
        if (func()) {
            onCompletion();
            return;
        }
        var intervalId = setInterval(function() {if (func()) { clearInterval(intervalId); onCompletion(); }}, interval);
    }

    function disable(nodeList) {
        return function disable() {
            Array.prototype.forEach.call(nodeList, function(currentValue) {
                currentValue.style.visibility = 'hidden';
                currentValue.removeAttribute('href');
                currentValue.style.cursor = 'default';
                currentValue.parentElement.style.MozUserSelect = 'none';
                currentValue.parentElement.style.webkitUserSelect = 'none';
                currentValue.parentElement.style.userSelect = 'none';
            });
            return Array.prototype.every.call(nodeList, function(currentValue) {
                return currentValue.style.visibility === 'hidden' &&
                       !currentValue.hasAttribute('href') &&
                       currentValue.style.cursor === 'default';
            });
        };
    }
    
    function activeIsEditable() {
        var node = document.activeElement;
        var name = node.nodeName.toLowerCase();
        return node.isContentEditable || node.nodeType == 1 && (name == "textarea" ||
          name == "input" && /^(?:text|email|number|search|tel|url|password|)$/i.test(node.type));
    }
    
    var isWhatIf = /^(https?:)?(\/\/)?(www\.)?what-if/i.test(window.location.href),
        blackList = {
            'xkcd': {
                1193: ['titleText'],
                1506: ['p', 'n', 'r', 'titleText'],
                1525: ['p', 'n', 'r', 'titleText'],
                1608: ['left', 'right', 'titleText']
            }, 'whatIf': {
                
            }
        },
        number, first, last, xhttp,
        left = 37, right = 39, n = 78, p = 80, r = 82;

    if (isWhatIf) {
        last = false;
        var setRandom = function(create) {
            if (!receivedResponse.received) {
                if (receivedResponse.onreceive !== false) {
                    receivedResponse.onreceive = !!create;
                }
                return;
            }
            if (typeof random === 'undefined') {
                random = Math.floor(Math.random() * (lastNumber - 1)) + 1;
            }
            if (random >= number) {
                random++;
            }
            if (create) {
                var addRandom = function(ulTag) {
                    var liTag = document.createElement('li'),
                        aTag = document.createElement('a');
                    aTag.href = '/' + random + '/';
                    aTag.appendChild(document.createTextNode('Random'));
                    liTag.appendChild(aTag);
                    if (last) {
                        ulTag.insertBefore(liTag, ulTag.lastChild);
                    } else {
                        ulTag.insertBefore(liTag, ulTag.lastChild.previousSibling);
                    }
                    if (first) {
                        liTag.style.marginLeft = '8.57552em';
                    }
                };
                navs = document.getElementsByClassName('main-nav');
                addRandom(navs[0].firstElementChild);
                addRandom(navs[1].firstElementChild);
            } else {
                window.location.pathname = '/' + random + '/';
            }
        },
        receivedResponse = {'received': false, 'onreceive': null},
        lastNumber, navs, addButtons, localLatest, time, expired, random;
        
        localLatest = localStorage.latestComic;
        time = new Date().getTime();
        if (typeof localLatest === 'undefined') {
            expired = true;
        } else {
            localLatest = localLatest.split(',');
            expired = localLatest[1] <= time;
        }
        if (expired) {
            xhttp = new XMLHttpRequest();
            xhttp.open('get', '/', true);
            xhttp.onreadystatechange = function() {
                if (xhttp.readyState == XMLHttpRequest.DONE) {
                    lastNumber = +xhttp.response.match(/<a href="\/\/what-if.xkcd.com\/(\d+)\/"><h1>/)[1];
                    receivedResponse.received = true;
                    localStorage.latestComic = lastNumber + ',' + (time + 6.048e+8);
                    if (receivedResponse.onreceive !== null) {
                        setRandom(receivedResponse.onreceive);
                    }
                }
            };
            xhttp.send();
        } else {
            lastNumber = localLatest[0];
            receivedResponse.received = true;
        }

        document.addEventListener('keydown', function(event) {
            var keyCode = event.keyCode;
            if ((keyCode === right || keyCode === n) && !last) {
                Array.prototype.forEach.call(document.getElementsByTagName('a'), function(currentValue) {
                    if (currentValue.firstChild !== null) {
                        if (currentValue.firstChild.textContent === 'Next') {
                            currentValue.click();
                        }
                    }
                });
            } else if ((keyCode === left || keyCode === p) && !first) {
                Array.prototype.forEach.call(document.getElementsByTagName('a'), function(currentValue) {
                    if (currentValue.firstChild !== null) {
                        if (currentValue.firstChild.textContent === 'Prev') {
                            currentValue.click();
                        }
                    }
                });
            } else if (keyCode === r) {
                setRandom();
            }
        });

        var headATag = document.getElementsByTagName('h1')[0].parentElement;
        number = +headATag.getAttribute('href').slice(19, -1);
        first = true;
        last = true;
        Array.prototype.forEach.call(document.getElementsByTagName('a'), function(currentValue) {
            if (currentValue.firstChild) {
                if (currentValue.firstChild.textContent === 'Prev') {
                    first = false;
                }
                if (currentValue.firstChild.textContent === 'Next') {
                    last = false;
                }
            }
        });

        if (/^(https?:)?(\/\/)?(www\.)?what-if.xkcd.com\/\d+/i.test(window.location.href)) {
            repeat(100, function() {
                headATag.removeAttribute('href');
                headATag.style.textDecoration = 'underline';
                return !headATag.hasAttribute('href') && headATag.style.textDecoration === 'underline';
            });
        }
        setRandom(true);

        addButtons = function(navTag) {
            var ulTag = navTag.firstElementChild,
                aTag;
            navTag.style.width = '23.5em';
            if (!first) {
                var firstTag = document.createElement('li');
                aTag = document.createElement('a');
                aTag.appendChild(document.createTextNode('First'));
                aTag.href = '/1/';
                firstTag.appendChild(aTag);
                firstTag.className = 'nav-prev';
                ulTag.insertBefore(firstTag, ulTag.firstChild);
            }
            if (!last) {
                var lastTag = document.createElement('li');
                aTag = document.createElement('a');
                aTag.appendChild(document.createTextNode('Last'));
                aTag.href = '/';
                lastTag.appendChild(aTag);
                lastTag.className = 'nav-next';
                ulTag.insertBefore(lastTag, ulTag.lastElementChild);
            }
            Array.prototype.forEach.call(ulTag.children, function(currentValue) {
                if (currentValue.firstChild.firstChild.textContent !== 'Last') {
                    currentValue.style.marginRight = '0.5em';
                }                    
            });
        };
        navs = document.getElementsByClassName('main-nav');
        addButtons(navs[0]);
        addButtons(navs[1]);
        

        Array.prototype.forEach.call(document.getElementsByTagName('img'), function(currentValue) {
            if (currentValue.hasAttribute('title')) {
                if (border) {
                    currentValue.style.border = '2px solid rgba(127, 127, 127, 0.22)';
                }
                if (titleText) {
                    currentValue.style.marginTop = currentValue.style.paddingTop;
                    currentValue.style.marginBottom = 0;
                    var oldPadding = currentValue.style.paddingBottom;
                    currentValue.style.paddingTop = 0;
                    currentValue.style.paddingBottom = 0;
                    var title = document.createElement('p');
                    title.appendChild(document.createTextNode(currentValue.title));
                    title.style.textAlign = 'center';
                    title.style.paddingLeft = '5em';
                    title.style.paddingRight = '5em';
                    title.style.paddingTop = 0;
                    title.style.paddingBottom = oldPadding;
                    title.style.fontSize = '85%';
                    currentValue.parentElement.insertBefore(title, currentValue.nextSibling);
                    currentValue.removeAttribute('title');
                }
            }
        });
        return;
    }



    var comic = document.getElementById('comic'),
        title = document.createElement('p'),
        previousButtons, nextButtons, intervalId, top, nav, link, oldNav;
    
    if (snap) {
        top = document.getElementById('middleContainer').offsetTop + 6;
        window.scrollTo(0, top);
        window.addEventListener('scroll', function() {
            var scrollPosition = document.documentElement.scrollTop || document.body.scrollTop;
            if (scrollPosition > top - 145 && top + 10 > scrollPosition) {
                if (intervalId === false && scrollPosition !== top) {
                    intervalId = setInterval(function() {
                        if (scrollPosition > top - 145 && top + 10 > scrollPosition) {
                            window.scrollTo(0, top);
                        }
                        clearInterval(intervalId);
                        intervalId = false;
                    }, 500);
                }
            } else {
                clearInterval(intervalId);
                intervalId = false;
            }
        });
    }

    first = last = false;
    repeat(100, function() {
        nextButtons = Array.prototype.slice.call(document.querySelectorAll('[accesskey="n"], [href="/"]'), 1);
        previousButtons = document.querySelectorAll('[accesskey="p"], [href="/1/"]');
        return nextButtons.length === 4 && previousButtons.length === 4;
    }, function() {
        if (previousButtons[1].getAttribute('href') === '#') {
            number = 1;
            first = true;
            repeat(100, disable(previousButtons));
        } else {
            number = +previousButtons[1].getAttribute('href').slice(1, -1) + 1;
            if (nextButtons[0].getAttribute('href') === '#') {
                last = true;
                repeat(100, disable(nextButtons));
            }
        }
    });

    if (number in blackList.xkcd) {
        blackList.xkcd[number].forEach(function(currentValue) {
            switch (currentValue) {
                case 'right':
                    right = null;
                    break;
                case 'n':
                    n = null;
                    break;
                case 'left':
                    left = null;
                    break;
                case 'p':
                    p = null;
                    break;
                case 'r':
                    r = null;
                    break;
                case 'titleText':
                    titleText = false;
            }
        });
    }

    repeat(1000, function() {
        if (comic.firstElementChild.tagName.toLowerCase() === 'script') {
            return false;
        }
        try {
            if (hr) {
                comic.parentElement.insertBefore(document.createElement('hr'), comic.nextSibling);
                comic.parentElement.insertBefore(document.createElement('hr'), comic);
            }
            if (titleText) {
                title.appendChild(document.createTextNode(comic.firstElementChild.title));
                title.style.fontVariant = 'normal';
                title.style.paddingLeft = '80px';
                title.style.paddingRight = '80px';
                title.style.fontSize = '20px';
                comic.parentElement.insertBefore(title, comic.nextSibling);
                comic.firstElementChild.removeAttribute('title');
            }
            return true;
        } catch (e) {
            return true;
        }
    });

    if (explainButton) {
        link = document.createElement('a');
        link.href = 'http://www.explainxkcd.com/' + number + '/';
        link.style.fontFamily = 'xkcd-Regular';
        link.style.fontVariant = 'normal';
        link.style.marginLeft = '5px';
        link.style.display = 'inline-block';
        link.style.fontSize = '20px';
        link.style.padding = '0px 5px 5px';
        link.appendChild(document.createTextNode('Explain!'));
        
        nav = document.createElement('ul');
        nav.className = 'comicNav';
        nav.style.marginBottom = 0;
        nav.appendChild(document.createElement('li'));
        nav.firstChild.appendChild(link);
        
        oldNav = document.getElementsByClassName('comicNav')[1];
        oldNav.parentElement.insertBefore(nav, oldNav.nextSibling);
    }
    
    document.addEventListener('keydown', function(event) {
        if (activeIsEditable()) {
            return;
        }
        var keyCode = event.keyCode;
        if ((keyCode === right || keyCode === n) && !last) {
            nextButtons[0].click();
        } else if ((keyCode === left || keyCode === p) && !first) {
            previousButtons[1].click();
        } else if (keyCode === r) {
            document.querySelector('[href="//c.xkcd.com/random/comic/"]').click();
        }
    });

    if (transcript) {
        transcript = document.getElementById('transcript');
        if (transcript !== null && transcript.firstChild !== null && transcript.firstChild !== '') {
            var node = document.createElement('p');
            node.innerHTML = transcript.innerHTML.replace(/\n*{{(title text|alt):.+\n*$/i, '').replace(/\n/g, '<br style="display: block; margin: 3px 0;">');
            node.style.fontVariant = 'normal';
            node.style.paddingLeft = '80px';
            node.style.paddingRight = '80px';
            node.style.fontSize = '14px';
            node.style.textAlign = 'left';

            var ul = document.getElementsByTagName('ul');
            ul = ul[ul.length - 1];
            var parent = ul.parentElement;
            ul = ul.nextSibling;

            if (hr) {
                parent.insertBefore(document.createElement('hr'), ul);
            }
            parent.insertBefore(node, ul);
            if (hr) {
                parent.insertBefore(document.createElement('hr'), ul);
            }
        }
    }
})();