MTurk Goals

Add goals and progess bars to the mTurk Dashboard and Status pages.

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         MTurk Goals
// @namespace    http://greasyfork.org/
// @version      0.7
// @description  Add goals and progess bars to the mTurk Dashboard and Status pages.
// @author       Jacob Valenta
// @include      https://www.mturk.com/mturk/dashboard
// @include      https://www.mturk.com/mturk/status
// @grant        none
// ==/UserScript==

var getJsonFromUrl = function(url){
    // Get GET parameters from a url as JSON
    // http://stackoverflow.com/a/8486146
    var regex = /[?&]([^=#]+)=([^&#]*)/g,
        url = url,
        params = {},
        match;
    while(match = regex.exec(url)) {
        params[match[1]] = match[2];
    }
    return params;
};

var setGoal = function(newGoal){
    localStorage.setItem("mturk-goal", parseFloat(newGoal).toFixed(2).toString());
};

var getGoal = function(){
    if (localStorage.getItem("mturk-goal") === null) {
        setGoal(10.00);
        return 10.00;
    }else{
        return parseFloat(localStorage.getItem("mturk-goal"));
    }
};

var percentColors = [
    { pct: 0.0, color: { r: 0xc0, g: 0x50, b: 0x50 } },
    { pct: 0.5, color: { r: 0xc0, g: 0xc0, b: 0x50 } },
    { pct: 1.0, color: { r: 0x50, g: 0xc0, b: 0x50 } } ];

var getColorForPercentage = function(pct) {
    for (var i = 1; i < percentColors.length - 1; i++) {
        if (pct < percentColors[i].pct) {
            break;
        }
    }
    var lower = percentColors[i - 1];
    var upper = percentColors[i];
    var range = upper.pct - lower.pct;
    var rangePct = (pct - lower.pct) / range;
    var pctLower = 1 - rangePct;
    var pctUpper = rangePct;
    var color = {
        r: Math.floor(lower.color.r * pctLower + upper.color.r * pctUpper),
        g: Math.floor(lower.color.g * pctLower + upper.color.g * pctUpper),
        b: Math.floor(lower.color.b * pctLower + upper.color.b * pctUpper)
    };
    return 'rgb(' + [color.r, color.g, color.b].join(',') + ')';
};

var getPendingHitsForDate = function(date, pages, callback, prog_container, earned) {
    // Hastily written. I will work on refactoring this.

    // I gave up on javascript's Dates and UTC vs PDT and PST
    // Screw that, just parse the date out of amazon's url...
	var currentPage = 1;

    while (currentPage <= pages){
		var request = new XMLHttpRequest();

        request.onreadystatechange = function() {
            var requestedDate = this._date;

            if (request.readyState == 4 && request.status == 200) {
                var response = request.responseXML;
                var pending = 0.00;

                var hits = response.getElementById("dailyActivityTable").querySelectorAll("tr");
                for (var i = 1; i <= hits.length - 1; ++i) {
                    row = hits[i];

                    var value_column = row.querySelectorAll("td")[2];

                    if (value_column != undefined){
                        var amount = Math.round(100 * parseFloat(value_column.querySelector("span").innerText.replace('$', ''))) / 100;
                        pending += amount;
                    }

                }
                callback(pending, prog_container, earned);
            }
        };

		request.open("GET", "https://www.mturk.com/mturk/statusdetail?encodedDate=" + date + "&sortType=Pending&pageNumber=" + currentPage, true);
        request._date = date;
        request.responseType = "document";
		request.send();

        currentPage += 1;
	}
};

(function() {
    'use strict';

    var page, width, metrics, goal;
    if (location.pathname == "/mturk/dashboard"){
        page = "dashboard";
        width = "200";
    }
    else if (location.pathname == "/mturk/status"){
        page = "status";
        width = "100";
    }

    goal = getGoal();

    if (page == "dashboard"){
        metrics = document.querySelectorAll(".metrics-table")[3].querySelectorAll("tr");

        // Add a change goal button to the bottom of the Dashboard
        var change_goal = document.createElement("td");
        change_goal.innerHTML = 'Goal: <input id="goal" style="width:50px;" value="'+goal.toFixed(2)+'" />&nbsp;<input id="goal-button" type="button" value="Set" style="border: 2px outset buttonface; background-color: buttonface" />';
        var last_td = metrics[metrics.length - 1].querySelectorAll("td")[0];
        last_td.setAttribute("colspan", "9");

        metrics[metrics.length -1].insertBefore(change_goal, last_td);

        // Add click callback
        document.getElementById("goal-button").addEventListener("click", function(){
            // Set goal from input and refresh page
            setGoal(document.getElementById("goal").value);
            location.reload();
        });
    }
    else if (page == "status"){
        metrics = document.querySelectorAll('table')[6].querySelectorAll("tr");
    }

    for (var i = 1; i < metrics.length - 1; ++i) {
        var row = metrics[i];
        var earned = parseFloat(row.querySelectorAll("td:last-child")[0].innerText.replace('$', ''));

        var fraction = (earned / goal);

        var prog = fraction * width;

        var progress_container = document.createElement('div');
        var progress = document.createElement('div');
        var progress_label = document.createElement('div');

        // TODO: Add actual CSS and classes to DOM.
        progress_container.setAttribute("style", "display: inline-block; float: right; width: " + width + "px; height: 6px; background-color: #eee; border: 1px solid #888; margin-top: 3px; border-radius: 1px");
        progress.setAttribute("style", "width: " + prog + "px; max-width: "+width+"px; height: 6px; background-color: "+ getColorForPercentage(fraction) + ";");      

        progress_label.setAttribute("style", "float: right; display: inline-block;");
        progress_label.innerHTML = (Math.round((fraction * 100) * 10) / 10).toFixed(1).toString() + "%&nbsp;&nbsp;";

        progress_container.appendChild(progress);

        row.querySelectorAll("td")[0].appendChild(progress_label).appendChild(progress_container);

        // Get pending hits and add another progress bar
        var dateString = getJsonFromUrl(row.querySelector('td a').getAttribute("href"));
        var pendingHits = parseInt(row.querySelectorAll("td")[4].innerText);
        var pages = Math.ceil(pendingHits / 25);
        if (pendingHits > 0){
            getPendingHitsForDate(dateString.encodedDate, pages, function(amount, container, accepted){
                var pending_earned = accepted + amount;
                var pending_fraction = (pending_earned / goal);
                var pending_prog = pending_fraction * width;

                var pending_progress = document.createElement('div');
                pending_progress.setAttribute("style", "margin-top: -6px; max-width:"+width+"px; height: 6px; opacity: 0.5");
                pending_progress.style.width = pending_prog;
                pending_progress.style["background-color"] = getColorForPercentage(pending_fraction);

               container.appendChild(pending_progress);
            }, progress_container, earned);
        }
    }
})();