SB Ledger Summary

SB ledger summary for quick view rather than just ledger view

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

You will need to install an extension such as Tampermonkey to install this script.

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         SB Ledger Summary
// @namespace    http://tampermonkey.net/
// @version      0.1.2
// @description  SB ledger summary for quick view rather than just ledger view
// @author       Anonymous coder
// @run-at       document-start
// @match        http://www.swagbucks.com/account/summary
// @grant        none
// ==/UserScript==
/* Changelog
 *
 * 20190101 - Fixed substitution of ' for " for JSON parsing to work on descriptions with ' in the string
 * 20170825 - Added localStorage item to keep track if the checkbox is enabled and if so, re-click it on page refresh
 * 20170822 - Initial release
 */

// Create a few global variables for use later
var summary_data = [];
var sb_Categories = [
    "Searching",
    "Referrals",
    "Shop",
    "Trade-In",
    "Rewards Store",
    "Swag Codes",
    "Other",
    "Swagstakes",
    "Answer",
    "Discover",
    "Play",
    "Bonus SB",
    "Watch",
    "Tasks",
    "Mobile Watch",
    "Social Games",
    "nCrave",
    "Swagbucks Visa Card",
    "Swagbucks Local",
    "Uncategorized"
];
var my_sheet;

// Parse the data loaded
function parse_ledger(ledger_data) {

    var last_day;   
    // Slice out the beginning data which includes the lifetime SB
    // We don't care about this since it's already displayed on the website anyway
    if (ledger_data.substr(0, 2) == "1|") {
        var idxL = ledger_data.indexOf("@");
        lifeSB = ledger_data.slice(2, idxL);
        // Change all ' to " so we can just use the standard JSON parse function rather than re-invent the wheel
        var temp_data = ledger_data.substr(idxL + 3).replace(/,'/g, ',"').replace(/',/g, '",').replace(/']/g, '"]').replace(/\\/g,'');
        var parsed_data = JSON.parse(temp_data);
        // Sort the data by the category number
        if (parsed_data.length > 0) {
            last_day = parsed_data[0][1];
            parsed_data.sort(function(a,b) {
                if (a[0] == b[0]) {
                    return (a[5] === b[5] ? 0 : (a[5] < b[5] ? -1 : 1));
                } else
                    return a[0] - b[0];
            });
        }
        // Iterate through the parsed data and break it into the activity types defined by Swagbucks
        for (i = 0 ; i < parsed_data.length ; i++) {
            if (last_day == parsed_data[i][1]) {
                var switch_val = 0;
                switch(parsed_data[i][0]) {
                        // Searching
                    case 1: //"Searching the Web",
                        switch_val = 0;
                        break;
                        // Referrals
                    case 2: //"Referral SB from",
                        switch_val = 1;
                        break;
                        // Shop
                    case 3: //"Shop",
                        switch_val = 2;
                        break;
                        // Trade-Im
                    case 4: //"Trade-In",
                        switch_val = 3;
                        break;
                        // Rewards Store
                    case 5: //"Rewards Store Refund",
                    case 6: //"Rewards Store Purchase",
                        switch_val = 4;
                        break;
                        // Swag Codes
                    case 7: //"Swag Code",
                        switch_val = 5;
                        break;
                        // Other
                    case 0: //"Registration",
                    case 9: //"Other",
                    case 21: //"Accelerator Bonus",
                    case 98: //"Correction",
                    case 99: //"Adjustment"
                        switch_val = 6;
                        break;
                        // Swagstakes
                    case 11: //"Swagstakes Entry",
                        switch_val = 7;
                        break;
                        // Answer
                    case 12: //"Answer",
                        switch_val = 8;
                        break;
                        // Discover
                    case 13: //"Discover",
                    case 20: //"Swagbucks Rewards",
                    case 24: //"Mobile Offers",
                        switch_val = 9;
                        break;
                        // Play
                    case 14: //"Play",
                        switch_val = 10;
                        break;
                        //Bonus SB
                    case 15: //"Bonus SB",
                        switch_val = 11;
                        break;
                        // Watch
                    case 16: //"Watch",
                        switch_val = 12;
                        break;
                        // Tasks
                    case 17: //"Tasks",
                        switch_val = 13;
                        break;
                        // Mobile Watch
                    case 18: //"Mobile Watch",
                        switch_val = 14;
                        break;
                        // Social Games
                    case 19: //"Social Games",
                        switch_val = 15;
                        break;
                        // nCrave
                    case 22: //"nCrave",
                        switch_val = 16;
                        break;
                        // Swagbucks Visa Card
                    case 23: //"Swagbucks Visa Card",
                        switch_val = 17;
                        break;
                        // Swagbucks Local
                    case 25: //"Swagbucks Local",
                        switch_val = 18;
                        break;
                        // Not categorized according to Swagbucks website
                    case 8: //"Submission",
                    case 10: //"Flipswap",
                    default:
                        switch_val = 19;
                }
                // Searching and Play categories have blank name fields, so we need to supply it manually rather than the parsed data
                var entry_name;
                if (parsed_data[i][5] === "" && parsed_data[i][0] == 1)
                    entry_name = "Searching";
                else if (parsed_data[i][5] === "" && parsed_data[i][0] == 14)
                    entry_name = "Play";
                else
                    entry_name = parsed_data[i][5];
                // Add parsed data to our array for rendering later
                if (summary_data[switch_val] === undefined) { // Initial data, array element doesn't exist
                    summary_data[switch_val] = {};
                    summary_data[switch_val][entry_name] = [parsed_data[i][3] , 1 ];
                    summary_data[switch_val].LedgerTotal = [parsed_data[i][3] , 1 ];
                }
                else { // Array element exists, but object doesn't, so initialize
                    if (summary_data[switch_val][entry_name] === undefined) {
                        summary_data[switch_val][entry_name] = [parsed_data[i][3] , 1 ];
                        summary_data[switch_val].LedgerTotal[0] += parsed_data[i][3];
                        summary_data[switch_val].LedgerTotal[1] += 1;
                    }
                    else { // Array and object exists, so increment values
                        summary_data[switch_val][entry_name][0] += parsed_data[i][3];
                        summary_data[switch_val][entry_name][1] += 1;
                        summary_data[switch_val].LedgerTotal[0] += parsed_data[i][3];
                        summary_data[switch_val].LedgerTotal[1] += 1;                 
                    }
                }
            }
        }
    }
}

// We need this function in order to override the XMLHttpRequest Swagbucks sends so we can see a copy of the account activity without calling it ourselves
(function(open) {
    XMLHttpRequest.prototype.open = function() {
        this.addEventListener("readystatechange", function() {
            if(this.readyState == 4 && this.status == 200 && this.responseURL.includes("cmd=sb-acct-ledger")) {
                parse_ledger(this.responseText);
            }
        }, false);
        open.apply(this, arguments);
    };
})(XMLHttpRequest.prototype.open);

// Render the ledger data as a summary table
function render_ledger_data() {
    // Add checkbox to display summary or not
    var summary_checkbox_section = document.createElement("section");
    summary_checkbox_section.setAttribute("id", "sbsummary");
    var summary_checkbox_label = document.createElement("label");
    summary_checkbox_label.setAttribute("class", "periodLabel");
    var summary_checkbox = document.createElement("input");
    summary_checkbox.setAttribute("id", "sbsummarycheck");
    summary_checkbox.setAttribute("type", "checkbox");
    summary_checkbox.addEventListener('click', function () {
        if (document.getElementById("sbsummarycheck").checked) {
            localStorage.setItem('Enabled', 'true');
            document.getElementById("tableContainerL").style.display = "none"; 
            document.getElementById("sbsummary_section").style.display = "block"; 
        } else {
            localStorage.setItem('Enabled', 'false');
            document.getElementById("tableContainerL").style.display = "block"; 
            document.getElementById("sbsummary_section").style.display = "none"; 
        }
    }, false);
    summary_checkbox_label.appendChild(summary_checkbox);
    summary_checkbox_label.appendChild(document.createTextNode("SB Summary"));
    summary_checkbox_section.appendChild(summary_checkbox_label);
    document.getElementById("tableParameters").appendChild(summary_checkbox_section);
    // Create the summary table
    var summary_table = document.createElement("table");
    summary_table.setAttribute("class", "sbsummarytable");
    var summary_table_header_row = document.createElement("tr");
    summary_table_header_row.setAttribute("class", "sbsummaryheader");
    var summary_table_header1 = document.createElement("th");
    summary_table_header1.setAttribute("class", "sbsummaryheader_cell");
    summary_table_header1.appendChild(document.createTextNode("Activity"));
    var summary_table_header2 = document.createElement("th");
    summary_table_header2.setAttribute("class", "sbsummaryheader_cell");
    summary_table_header2.appendChild(document.createTextNode("Total SB"));
    var summary_table_header3 = document.createElement("th");
    summary_table_header3.setAttribute("class", "sbsummaryheader_cell");
    summary_table_header3.appendChild(document.createTextNode("Entries"));
    summary_table_header_row.appendChild(summary_table_header1);
    summary_table_header_row.appendChild(summary_table_header2);
    summary_table_header_row.appendChild(summary_table_header3);
    summary_table.appendChild(summary_table_header_row);
    // Now that the header was created, let's populate the table rows, first with the activity summary rows
    var summary_table_data_row, summary_table_data_cell1, summary_table_data_cell2, summary_table_data_cell3;
    var summary_data_key;
    for (i = 0; i < summary_data.length; i++) {
        if (summary_data[i] !== undefined) {
            summary_table_data_row = document.createElement("tr");
            summary_table_data_row.setAttribute("class", "sbsummarydata");

            summary_table_data_cell1 = document.createElement("td");
            summary_table_data_cell1.setAttribute("class", "sbsummarydata_category " + i);
            summary_table_data_cell1.appendChild(document.createTextNode(sb_Categories[i]));
            summary_table_data_cell2 = document.createElement("td");
            if (summary_data[i].LedgerTotal[0] < 0) {
                summary_table_data_cell2.setAttribute("class", "sbsummarydata_amount red");
            } else {
                summary_table_data_cell2.setAttribute("class", "sbsummarydata_amount");
            }
            summary_table_data_cell2.appendChild(document.createTextNode(summary_data[i].LedgerTotal[0]));
            summary_table_data_cell3 = document.createElement("td");
            summary_table_data_cell3.setAttribute("class", "sbsummarydata_entries");
            summary_table_data_cell3.appendChild(document.createTextNode(summary_data[i].LedgerTotal[1]));
            summary_table_data_row.appendChild(summary_table_data_cell1);
            summary_table_data_row.appendChild(summary_table_data_cell2);
            summary_table_data_row.appendChild(summary_table_data_cell3);
            summary_table_data_row.addEventListener('click', function() {
                var changerule = my_sheet.cssRules;
                if (this.className.includes("active")) {
                    // Hide detailed rows
                    for (i = 0; i < changerule.length; i++) {
                        if (changerule[i].selectorText == ("._" + this.childNodes[0].className.split(" ")[1] + ".sbsummarydetaildata")) {
                            changerule[i].style.display = "none";
                            this.className = this.className.replace(" active", "");
                            break;
                        }
                    }
                } else {
                    // Show detailed rows
                    for (i = 0; i < changerule.length; i++) {
                        if (changerule[i].selectorText == ("._" + this.childNodes[0].className.split(" ")[1] + ".sbsummarydetaildata")) {
                            changerule[i].style.display = "table-row";
                            this.className = this.className.concat(" active");
                            break;
                        }
                    }
                }
            });
            // Now we add the table into the html file to be drawn
            summary_table.appendChild(summary_table_data_row);
            // Now we add the detailed rows below the activity
            if ( i == 14 ) { // This is a mobile watch activity, so let's display the regular data first
                for (summary_data_key in summary_data[i]) {
                    if (summary_data_key != "LedgerTotal" && !summary_data_key.includes("Bonus")) {
                        summary_table_data_row = document.createElement("tr");
                        summary_table_data_row.setAttribute("class", "sbsummarydetaildata _" + i);
                        summary_table_data_cell1 = document.createElement("td");
                        summary_table_data_cell1.setAttribute("class", "sbsummarydetaildata_category");
                        summary_table_data_cell1.appendChild(document.createTextNode(summary_data_key));
                        summary_table_data_cell2 = document.createElement("td");
                        if (summary_data[i][summary_data_key][0] < 0) {
                            summary_table_data_cell2.setAttribute("class", "sbsummarydetaildata_amount red");
                        } else {
                            summary_table_data_cell2.setAttribute("class", "sbsummarydetaildata_amount");
                        }
                        summary_table_data_cell2.appendChild(document.createTextNode(summary_data[i][summary_data_key][0]));
                        summary_table_data_cell3 = document.createElement("td");
                        summary_table_data_cell3.setAttribute("class", "sbsummarydetaildata_entries");
                        summary_table_data_cell3.appendChild(document.createTextNode(summary_data[i][summary_data_key][1]));
                        summary_table_data_row.appendChild(summary_table_data_cell1);
                        summary_table_data_row.appendChild(summary_table_data_cell2);
                        summary_table_data_row.appendChild(summary_table_data_cell3);
                        summary_table.appendChild(summary_table_data_row);
                    }
                }
                for (summary_data_key in summary_data[i]) { // Now if there were any bonus rounds, we will display them next
                    if (summary_data_key != "LedgerTotal" && summary_data_key.includes("Bonus")) {
                        summary_table_data_row = document.createElement("tr");
                        summary_table_data_row.setAttribute("class", "sbsummarydetaildata _" + i);
                        summary_table_data_cell1 = document.createElement("td");
                        summary_table_data_cell1.setAttribute("class", "sbsummarydetaildata_category");
                        summary_table_data_cell1.appendChild(document.createTextNode(summary_data_key));
                        summary_table_data_cell2 = document.createElement("td");
                        if (summary_data[i][summary_data_key][0] < 0) {
                            summary_table_data_cell2.setAttribute("class", "sbsummarydetaildata_amount red");
                        } else {
                            summary_table_data_cell2.setAttribute("class", "sbsummarydetaildata_amount");
                        }
                        summary_table_data_cell2.appendChild(document.createTextNode(summary_data[i][summary_data_key][0]));
                        summary_table_data_cell3 = document.createElement("td");
                        summary_table_data_cell3.setAttribute("class", "sbsummarydetaildata_entries");
                        summary_table_data_cell3.appendChild(document.createTextNode(summary_data[i][summary_data_key][1]));
                        summary_table_data_row.appendChild(summary_table_data_cell1);
                        summary_table_data_row.appendChild(summary_table_data_cell2);
                        summary_table_data_row.appendChild(summary_table_data_cell3);
                        summary_table.appendChild(summary_table_data_row);
                    }
                }
            } else { // Display detailed data (non-mobile watch entries)
                for (summary_data_key in summary_data[i]) {
                    if (summary_data_key != "LedgerTotal") {
                        summary_table_data_row = document.createElement("tr");
                        summary_table_data_row.setAttribute("class", "sbsummarydetaildata _" + i);
                        summary_table_data_cell1 = document.createElement("td");
                        summary_table_data_cell1.setAttribute("class", "sbsummarydetaildata_category");
                        summary_table_data_cell1.appendChild(document.createTextNode(summary_data_key));
                        summary_table_data_cell2 = document.createElement("td");
                        if (summary_data[i][summary_data_key][0] < 0) {
                            summary_table_data_cell2.setAttribute("class", "sbsummarydetaildata_amount red");
                        } else {
                            summary_table_data_cell2.setAttribute("class", "sbsummarydetaildata_amount");
                        }
                        summary_table_data_cell2.appendChild(document.createTextNode(summary_data[i][summary_data_key][0]));
                        summary_table_data_cell3 = document.createElement("td");
                        summary_table_data_cell3.setAttribute("class", "sbsummarydetaildata_entries");
                        summary_table_data_cell3.appendChild(document.createTextNode(summary_data[i][summary_data_key][1]));
                        summary_table_data_row.appendChild(summary_table_data_cell1);
                        summary_table_data_row.appendChild(summary_table_data_cell2);
                        summary_table_data_row.appendChild(summary_table_data_cell3);
                        summary_table.appendChild(summary_table_data_row);
                    }
                }
            }
        }
    }
    // Now that the table was generated, let's add the section right after Swagbuck's ledger table
    var summary_section = document.createElement("section");
    summary_section.setAttribute("id", "sbsummary_section");
    summary_section.style.display = "none";
    summary_section.appendChild(summary_table);
    document.getElementById("tableView").appendChild(summary_section);
    if (localStorage.getItem('Enabled') == 'true') {
        document.getElementById('sbsummarycheck').click();
    }
}

// Add some CSS style information so our table doesn't look too different
function render_css() {
    // Create a style
    var style = document.createElement("style");
    // WebKit hack :(
    style.appendChild(document.createTextNode(""));
    // Add the <style> element to the page
    document.head.appendChild(style);

    // Now we add our rules for everything we generated earlier
    // Overall table
    style.sheet.insertRule(".sbsummarytable { cursor: pointer; text-align: left; width: 100%; position: relative; border: solid #ccc; border-collapse: collapse; font-weight: normal; border-width: .1rem; padding: .7rem 0 .7rem 1rem }", style.sheet.length);
    // Table header row (<th>)
    style.sheet.insertRule(".sbsummaryheader { cursor: pointer; font-size: 1.5em; text-align: left; position: relative; border: solid #ccc; font-weight: normal; border-width: .1rem; padding: .7rem 0 .7rem 1rem }", style.sheet.length);
    style.sheet.insertRule(".sbsummaryheader_cell { top: 0; left: 0; width: 100%; position: relative; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; padding: 1rem 0 1rem 1rem; font-weight: bold }", style.sheet.length);    
    // Activity summary row
    style.sheet.insertRule(".sbsummarydata { cursor: pointer; font-size: 1.4em; text-align: left; position: relative; border: solid #ccc; font-weight: normal; border-width: .1rem; padding: .7rem 0 .7rem 1rem; font-weight: bold }", style.sheet.length);
    style.sheet.insertRule(".sbsummarydata_category { color: #69b8d6; width: 100%; position: relative; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; padding: 1rem 0 1rem 1rem; font-weight: bold }", style.sheet.length);
    style.sheet.insertRule(".sbsummarydata_amount { color: #69b8d6; text-align: right; padding: 1rem 0 1rem 1rem; font-weight: bold }", style.sheet.length);
    style.sheet.insertRule(".red.sbsummarydata_amount { color: #e98780 }", style.sheet.length);
    style.sheet.insertRule(".sbsummarydata_entries { top: 0; left: 0; width: 100%; position: relative; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; padding: 1rem 0 1rem 1rem; font-weight: bold}", style.sheet.length);
    // Detailed data row
    //    style.sheet.insertRule(".sbsummarydetaildata { cursor: pointer; font-size: 1.4em; text-align: left; position: relative; border: solid #ccc; font-weight: normal; border-width: .1rem; padding: .7rem 0 .7rem 1rem }", style.sheet.length);
    style.sheet.insertRule(".sbsummarydetaildata_category { top: 0; left: 0; width: 100%; position: relative; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; padding: 1rem 0 1rem 1rem }", style.sheet.length);
    style.sheet.insertRule(".sbsummarydetaildata_amount { color: #69b8d6; text-align: right; padding: 1rem 0 1rem 1rem; font-weight: bold }", style.sheet.length);
    style.sheet.insertRule(".red.sbsummarydetaildata_amount { color: #e98780 }", style.sheet.length);
    style.sheet.insertRule(".sbsummarydetaildata_entries { top: 0; left: 0; width: 100%; position: relative; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; padding: 1rem 0 1rem 1rem; }", style.sheet.length);
    // Generate individual styles for each activity type's detailed rows so they can be show or hidden when clicked
    for (i = 0; i < 20; i++) {
        style.sheet.insertRule("._" + i + ".sbsummarydetaildata { cursor: pointer; width: 100%; font-size: 1.4em; text-align: left; position: relative; border: solid #ccc; font-weight: normal; border-width: .1rem; padding: .1rem 0 .1rem 1rem; display: none }", style.sheet.length);
    }
    return style.sheet;
}

// Push the HTML code changes once the page is ready to go
document.onreadystatechange = function () {
    if (document.readyState === "complete") {
        // Push CSS rules for the table we create
        my_sheet = render_css();
        // Render ledger data
        render_ledger_data();
    }
};