Yodlee MoneyCenter Tweaks

Slight modifications to Yodlee MoneyCenter

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// vim: et ts=4 sw=4 ai tw=80

// ==UserScript==
// @name           Yodlee MoneyCenter Tweaks
// @namespace      http://www.arthaey.com
// @description    Slight modifications to Yodlee MoneyCenter
// @include        https://moneycenter.yodlee.com/moneycenter/*
//
// @author         Arthaey Angosii
// @version        0.1
//
// Backed up from http://userscripts.org/scripts/review/21580
// Last updated on 2008-01-27
// ==/UserScript==
//
// CHANGELOG:
//  v0.1 - initial release
//

window.addEventListener("load", function() {

    const Options = new Object();

    // Removes the auto-login drop-down menu and all "go to site" links.
    Options.hideAutoLogin = true;

    // Adds day of week to transactions' dates (one of UMTWRFS).
    Options.dayOfWeek = true;

    // Colors transaction table rows in alterating colors.
    Options.stripeTransactions = true;
    Options.stripeColor = "#f6f7f8";

    /* SKINNING METHODS ******************************************************/

    function run() {
        var debugInfo = "Skinning Yodlee MoneyCenter, with these options:";
        for (var option in Options) {
            debugInfo += "\n - " + option + ": " + Options[option];
        }
        debug(debugInfo);

        if (Options.hideAutoLogin)      { hideAutoLogin(); }
        if (Options.dayOfWeek)          { dayOfWeek(); }
        if (Options.stripeTransactions) { stripeTransactions(); }
    }

    function hideAutoLogin() {
        // hide the drop-down menu at the top of the dashboard page
        var autoLogin = $$(".autologin");
        // We're only expecting the one auto-login div. If that's not what
        // we found, then don't try to hide the drop-down menu.
        if (autoLogin.length == 1) {
            autoLogin[0].style.display = "none";
        }

        // hide the "got to site" links
        runAtIntervalsUntil(function() {
            var links = document.getElementsByTagName("a");
            var link, sibling;

            for (var i = 0; i < links.length; i++) {
                link = links[i];
                sibling = link.nextSibling;

                if (link.textContent.match(/go to site|auto-login/)) {
                    link.style.display = "none";
                    // remove "|" if that text follows the link
                    if (sibling.nodeType == 3 /* TEXT */ &&
                        sibling.textContent.match(/^\s*\|\s*$/))
                    {
                        sibling.parentNode.removeChild(sibling);
                    }
                }
            }
        }, 5, 30);
    }

    function dayOfWeek() {
        forEachTransactionTable(function(table) {
            var weekday = ["U", "M", "T", "W", "R", "F", "S"];
            var cell, match, date;

            for (var i = 0; i < table.rows.length; i++) {
                for (var j = 0; j < table.rows[i].cells.length; j++ ) {
                    cell = table.rows[i].cells[j];
                    if (match = cell.textContent.match(/(\d{2})\/(\d{2})\/(\d{4})/)) {
                        date = new Date(match[3], parseInt(match[1]) - 1, match[2]);
                        cell.innerHTML = weekday[date.getDay()] +
                            "&nbsp;" + cell.textContent;
                    }
                }
            }
        });
    }

    function stripeTransactions() {
        GM_addStyle("tr.zebraStripe { background-color: " +
            Options.stripeColor + "; }");
        // highlight takes precedence over striping
        GM_addStyle("tr.zebraStripe.highlight { background-color: #ffffe5; }");

        forEachTransactionTable(function(table) {
            for (var r = 0; r < table.rows.length; r += 2) {
                table.rows[r].className += " zebraStripe";
            }
        });
    }

    /* SKINNING UTILITY METHODS **********************************************/

    var _transactionTables = null;

    /* The transaction tables can take a while to load, and they do so
     * asynchronously. So if you want to do something to each transaction table
     * on a page, use this function and pass in the function that will process
     * one table.
     *
     * If no transaction tables show up in 30 seconds, this function will give
     * up and stop calling your function. It will return true if it called your
     * function, false if it did not.
     */
    function forEachTransactionTable(processFunc) {
        _transactionTables = null;
        var hasRun = false;

        runAtIntervalsUntil(_checkForTransactionTables, 5, 30);

        runAtIntervalsUntil(function() {
            if (hasRun || _transactionTables == null) { return; }
            for (var i = 0; i < _transactionTables.length; i++) {
                processFunc(_transactionTables[i]);
            }
            hasRun = true;
        }, 6, 45);

        return hasRun;
    }

    function _checkForTransactionTables() {
        if (_transactionTables) { return _transactionTables; }

        var results = [];
        var tables = document.getElementsByTagName("table");
        var table;

        for (var i = 0; i < tables.length; i++) {
            table = tables[i];
            if (table.id.match(/^Txn/)) {
                results.push(table);
            }
        }

        if (results.length > 0) {
            _transactionTables = results;
            debug("Found " + results.length + " transaction tables.");
        }

        return results;
    }

    /* GENERIC UTILITY METHODS ***********************************************/

    var DEBUG = false;

    function debug(msg) {
        if (DEBUG) console.log(msg);
    }

    function runAtIntervalsUntil(func, intervalSeconds, untilSeconds) {
        var intervalObj = window.setInterval(func, intervalSeconds);
        window.setTimeout(function(intervalObj) {
            window.clearInterval(intervalObj);
        }, untilSeconds);
    }

    /* From http://wiki.greasespot.net/Code_snippets */
    function $$(xpath,root) {
        xpath = xpath.replace(/((^|\|)\s*)([^/|\s]+)/g,'$2.//$3').
                replace(/\.([\w-]+)(?!([^\]]*]))/g,'[@class="$1" or @class$=" $1" or @class^="$1 " or @class~=" $1 "]').
                replace(/#([\w-]+)/g,'[@id="$1"]').
                replace(/\/\[/g,'/*[');
        var str = '(@\\w+|"[^"]*"|\'[^\']*\')';
        xpath = xpath.replace(new RegExp(str+'\\s*~=\\s*'+str,'g'),'contains($1,$2)').
                replace(new RegExp(str+'\\s*\\^=\\s*'+str,'g'),'starts-with($1,$2)').
                replace(new RegExp(str+'\\s*\\$=\\s*'+str,'g'),'substring($1,string-length($1)-string-length($2)+1)=$2');

        var got = document.evaluate(xpath, root || document, null, null, null);
        var result = [];
        var next;

        while (next = got.iterateNext()) {
            result.push(next);
        }

        return result;
    }

    // http://wiki.greasespot.net/Code_snippets#Make_script_accessible_to_Firebug
    function makeAvailableToFirebug() {
        return makeAvailableToFirebug.caller.toString().
            replace(/([\s\S]*?return;){2}([\s\S]*)}/,'$2')
    }
    document.body.appendChild(document.createElement('script')).innerHTML =
        makeAvailableToFirebug();


    /* RUN THE SCRIPT ********************************************************/

    run();

}, true);