MTurk Dashboard Goals

Shows some goal information, progress, etc. on the dashboard

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name       MTurk Dashboard Goals
// @version    0.72b
// @description  Shows some goal information, progress, etc. on the dashboard
// @include      https://www.mturk.com/mturk/dashboard
// @grant       GM_getValue
// @grant       GM_setValue
// @grant       GM_deleteValue
// @grant       GM_xmlhttpRequest
// @copyright  2012+, Tjololo12
// @namespace https://greasyfork.org/users/710
// ==/UserScript==
//

//GM_deleteValue('GOALS_goal_table');

var retryAttempts = '10';
var retryTime = '250';
var goalTableJson = [];
if (GM_getValue('GOALS_goal_table')){
    var goalStuff = GM_getValue('GOALS_goal_table');
    goalTableJson = JSON.parse(goalStuff);
    if (Object.keys(goalTableJson).length == 0){
        GM_deleteValue('GOALS_goal_table');
        goalTableJson = [];
    }
}
var numEntries = (GM_getValue('GOALS_goal_table') ? Object.keys(goalTableJson).length : 0);

var balance = 0;
var refresh = false;
if (!GM_getValue('GOALS_balance')){
    balance = get_balance();
    refresh = true;
    GM_setValue('GOALS_balance', balance);
    GM_setValue('GOALS_timestamp', new Date());
}
else{
    if (GM_getValue('GOALS_timestamp')){
        console.log(datediff("minutes", GM_getValue('GOALS_timestamp'), "")+" timestamp: "+GM_getValue('GOALS_timestamp'));
        if (datediff("minutes", GM_getValue('GOALS_timestamp'), "") > 1){
            balance = get_balance();
            refresh = true;
            GM_setValue('GOALS_balance', balance);
            GM_setValue('GOALS_timestamp', new Date());
        }
        else
            balance = GM_getValue('GOALS_balance');
    }
    else{
        balance = get_balance();
        refresh = true;
        GM_setValue('GOALS_balance', balance);
        GM_setValue('GOALS_timestamp', new Date());
    }
}

var cells= document.getElementsByClassName('metrics-table-first-value');
var contains = false;
var approvedHits = 0;
for (var i = 0, len = cells.length; i < len; ++i) {
    if(cells[i].innerHTML.indexOf("Today's Projected Earnings") != -1) {
        console.log("Pending earnings found: "+cells[i].parentNode.getElementsByTagName('td')[1].innerHTML.replace(/[^0-9\.]/g, ''));
        GM_setValue('GOALS_today_pending', cells[i].parentNode.getElementsByTagName('td')[1].innerHTML.replace(/[^0-9\.]/g, ''));
        contains = true;
        } 
    if(cells[i].innerHTML.indexOf("Approved HITs") != -1) {
        console.log("Approved HITs found: "+cells[i].parentNode.getElementsByTagName('td')[1].innerHTML.replace(/[^0-9\.]/g, ''));
        approvedHits = parseFloat(cells[i].parentNode.getElementsByTagName('td')[1].innerHTML.replace(/[^0-9\.]/g, ''));
        } 
} 
console.log("Data "+(refresh ? "" : "not ")+"refreshed");

//Compatibility for converting old entries
if (!GM_getValue('GOALS_converted')){
    for (var key in goalTableJson){
        //if (!goalTableJson[key]['start'])
            goalTableJson[key]['start'] = approvedHits - balance;
        console.log(goalTableJson[key]['start']);
    }
    var goalString = JSON.stringify(goalTableJson);
    GM_setValue('GOALS_goal_table', goalString);
    goalTableJson = GM_getValue('GOALS_goal_table');
    console.log("Data converted");
}

var TEMPLATE = "{name} | {amount} | {days} | {percent}";
if (GM_getValue('GOALS_export_template'))
    TEMPLATE = GM_getValue('GOALS_export_template');
var EDIT = false;

function fetchData() {
    var timer;

    if (typeof numCon === 'undefined') {
        var numCon = 0;
    } else if (numCon > retryAttempts) {
        throw new Error("Could not get data.");
    }


    GM_xmlhttpRequest({
        method: "GET",
        url: "https://www.mturk.com/mturk/youraccount",
        onload: function (response) {
            // Get balance
            var reBal = /(\$\d+,?.?\d+,?.?\d+,?.?\d?\d?)/;
            var balance = response.responseText.match(reBal);
            if (balance['0']) {
                GM_setValue('GOAL_AMZ_Balance', balance['0'].substr(1));
                return balance['0'].substr(1);
            }
            else {
                GM_setValue('GOAL_AMZ_Balance', 0);
                return 0;
            }
        }
        });
    numCon++;
}

/* ----------------------------------------------------------------------------------- */

function get_balance() {
    var retval = fetchData();
    if (GM_getValue('GOAL_AMZ_Balance'))
    {
       return GM_getValue('GOAL_AMZ_Balance');   
    }
    else
         return retval;
}

function saveOrder_func(){
    var goalTable = document.getElementById('goal_table');
    var rows = goalTable.rows;
    var goalJson = (goalTableJson ? goalTableJson : []);
    var newJson = [];
    for (var i=0; i<rows.length; i++) {
        if (goalJson[rows[i].id.replace(/[^0-9\.]/g, '')])
            newJson.push(goalJson[rows[i].id.replace(/[^0-9\.]/g, '')]);
    }
    goalTableJson = newJson;
    var goalString = JSON.stringify(newJson);
    //console.log(goalString);
    GM_setValue('GOALS_goal_table', goalString);
    document.getElementById('hide_button').click();
}

function addRow_func(){
    //console.log("addRow");
    //var new_row = document.createElement('tr');
    var checkbox = document.createElement('td');
    var goal_name = document.createElement('td');
    var type_name = document.createElement('td');
    var goal_amount = document.createElement('td');
    var date = document.createElement('td');
    var order = document.createElement('td');
    goalTable = document.getElementById('goal_table');
    var element1 = document.createElement("input");
    var element2 = document.createElement("input");
    var element3 = document.createElement("input");
    var element4 = document.createElement("input");
    var element5 = document.createElement("select");
    var element6 = document.createElement("select");
    var tempNum = numEntries;
    
    var nameId = "newName_"+tempNum;
    var amountId = "newAmount_"+tempNum;
    var dateId = "newDate_"+tempNum;
    var checkId = "radio_"+tempNum;
    var typeId = "type_"+tempNum;
    var typeCellId = "newType_"+tempNum;
    var orderId = "order_"+tempNum;
    var orderCellId = "newOrder_"+tempNum;
    goal_name.setAttribute('id', nameId);
    goal_amount.setAttribute('id', amountId);
    date.setAttribute('id', dateId);
    type_name.setAttribute('id', typeCellId);
    order.setAttribute('id', orderCellId);
    
    element1.type = "radio";
    element1.disabled = true;
    element1.setAttribute('id', checkId);
    checkbox.appendChild(element1);
    
    element2.type = "text";
    element2.value = "What is it?";
    element2.setAttribute('onFocus','if (this.value == \'What is it?\') this.value=\'\'');
    element2.id = "name_"+tempNum;
    goal_name.appendChild(element2);
    
    element3.type = "text";
    element3.value = "$x,xxx.xx";
    element3.setAttribute('onFocus', 'if (this.value == \'$x,xxx.xx\') this.value=\'\'');
    element3.id = "amount_"+tempNum;
    goal_amount.appendChild(element3);
    
    element4.type = "text";
    element4.value = "mm/dd/yyyy";
    element4.setAttribute('onFocus', 'if (this.value == \'mm/dd/yyyy\') this.value=\'\'');
    element4.id = "date_"+tempNum;
    date.appendChild(element4);
    
    element5.setAttribute('id', typeId);
    
    var option = document.createElement('option');
    option.value = 'normal';
    option.appendChild(document.createTextNode('Normal'));
    element5.appendChild(option);
          
    option = document.createElement('option');
    option.value = 'day';
    option.appendChild(document.createTextNode('Daily Goal'));
    element5.appendChild(option);
    type_name.appendChild(element5);
    
    for (var i = 0; i < numEntries + 1; i++){
        option = document.createElement('option');
        option.value = i;
        option.appendChild(document.createTextNode(i+1));
        if (i == numEntries)
            option.setAttribute("selected", "selected");
        element6.appendChild(option);
    }
    order.appendChild(element6);
    
    element6.setAttribute('id', orderId);
    
    if (!GM_getValue('GOALS_goal_table') && document.getElementById('noContentRow'))
        goalTable.deleteRow(1);
    
    var new_row = goalTable.insertRow(++numEntries);
    //goalTable.appendChild(new_row)
    new_row.setAttribute("NoDrag", 1);
    new_row.appendChild(goal_name);
    new_row.appendChild(type_name);
    new_row.appendChild(goal_amount);
    new_row.appendChild(date);
    new_row.appendChild(checkbox);
    new_row.appendChild(order);
}

function validate_date(input)
{
  var date = input.value;  

  if (!date || date == "mm/dd/yyyy")
      return true;
  if (date.match(/^[01]\d\/[0123]\d\/20\d\d$/) != null)
  {
    var d = date.split('\/');
    date = d[2] + '-' + d[0] + '-' + d[1];
    input.value = date;
  }

  if (date.match(/^$|^20\d\d\-[01]\d\-[0123]\d$/) != null)
  {
    input.style.backgroundColor = 'white';
    return true;
  }
  input.style.backgroundColor = 'pink';
  return false;
}

function validate_amount(input)
{
    var amount = input.value;
    
    if (amount.match(/^\$?(\d+,?)+(\.\d\d)?$/)){
        return true;
    }
    else
        return false;
}

function validate_type(input)
{
    var type = input.value;
    
    if (type == "day")
    {
        var cells= document.getElementsByClassName('metrics-table-first-value');
        var contains = false;
        for (var i = 0, len = cells.length; i < len; ++i) {
            if(cells[i].innerHTML.indexOf("Today's Projected Earnings") != -1) {
                console.log("Pending earnings found: "+cells[i].parentNode.getElementsByTagName('td')[1].innerHTML.replace(/[^0-9\.]/g, ''));
                GM_setValue('GOALS_today_pending', cells[i].parentNode.getElementsByTagName('td')[1].replace(/[^0-9\.]/g, ''));
                contains = true;
            }    
        } 
        if (!contains)
            alert("Daily goals require the installation of the \"Today's Projected Earnings\" script from userscripts.org.");
        return contains;
    }
    else
        return true;    
}

function save_values(){
//    try{
        var jsonObj = [];
        for (var i = (GM_getValue('GOALS_goal_table') ? Object.keys(goalTableJson).length : 0); i <= numEntries-1; i++)
        {
            var nameCellId = "newName_"+i;
            var amountCellId = "newAmount_"+i;
            var dateCellId = "newDate_"+i;
            var typeCellId = "newType_"+i;
            var orderCellId = "newOrder_"+i;
            
            var nameId = "name_"+i;
            var amountId = "amount_"+i;
            var dateId = "date_"+i;
            var checkId = "radio_"+i;
            var typeId = "type_"+i;
            var orderId = "order_"+i;
            
            var name = document.getElementById(nameId);
            var amount = document.getElementById(amountId);
            var date = document.getElementById(dateId);
            var type = document.getElementById(typeId);
            var order = document.getElementById(orderId);
            
            var nameVal = name.value;
            var amountVal = amount.value.replace("$","");
            amountVal = amountVal.replace(",","");
            var tempAmountVal = amount.value;
            var dateVal = date.value;
            var typeVal = type.options[type.selectedIndex].value;
            var orderVal = order.options[order.selectedIndex].value;
            
            if (typeVal == 'day')
            {
                var tempDate = new Date();
                var months = parseInt(tempDate.getMonth());
                var days = parseInt(tempDate.getDate());
                var years = parseInt(tempDate.getFullYear());
                months += 1;
                days += 1;
                if (months.length == 1)
                    months = "0"+months;
                if (days.length == 1)
                    days = "0"+days;
                var dateString = months + "/" + days + "/" + years;                
                console.log(dateString);
                dateVal = dateString;
            }
            
            if (!validate_date(date)){
                alert("Invalid date format! Please use mm/dd/yyyy or yyyy-mm-dd");
                return false;
            }
            if (!validate_amount(amount)){
                alert("Invalid amount format! Please use $x,xxx.xx or x,xxx.xx or xxxx.xx");
                return false;
            }
            if (!validate_type(typeVal)){
                return false;
            }
            
            var nameCell = document.getElementById(nameCellId);
            var amountCell = document.getElementById(amountCellId);
            var dateCell = document.getElementById(dateCellId);
            var typeCell = document.getElementById(typeCellId);
            var orderCell = document.getElementById(orderCellId);
            
            var startVal = approvedHits;
            
            jsonObj[i] = {'name':nameVal, 'amount':amountVal, 'date':(dateVal == "mm/dd/yyyy" ? null : dateVal), 'type':(typeVal == 'normal' ? null : typeVal), 'start':startVal};
            
            nameCell.removeChild(name);
            nameCell.textContent = nameVal;
        
            amountCell.removeChild(amount);
            amountCell.textContent = ""+parseFloat(tempAmountVal).formatMoney(2);
        
            dateCell.removeChild(date);
            dateCell.textContent = (dateVal != "mm/dd/yyyy" ? dateVal : "");
            
            typeCell.removeChild(type);
            typeCell.textContent = (typeVal == 'normal' ? "Normal" : typeVal);
            
            orderCell.removeChild(order);
            orderCell.textContent = orderVal;
            
            document.getElementById(checkId).disabled = false;
        }
        var goalJson = (goalTableJson ? goalTableJson : []);
        for (var key in jsonObj)
            goalJson.splice(parseInt(orderVal)-1, 0, jsonObj[key]);
        goalTableJson = goalJson;
        var goalString = JSON.stringify(goalJson);
        //console.log(goalString);
        GM_setValue('GOALS_goal_table', goalString);
        toggleGoalDiv();
        toggleGoalDiv();
        return true;
//    }
//    catch (err){
//        console.log(err);
//        return false;
//    }
}

function updateDate(key)
{
    var tempDate = new Date();
    var months = parseInt(tempDate.getMonth());
    var days = parseInt(tempDate.getDate());
    var years = parseInt(tempDate.getFullYear());
    var numDays = new Date(years, months, 0).getDate();
    months = (months + 1 > 12 ? 1 : (days + 1 > numDays ? months + 2 : months + 1));
    days = (days + 1 > numDays ? 1 : days + 1);
    if (months.length == 1)
        months = "0"+months;
    if (days.length == 1)
        days = "0"+days;
    var dateString = months + "/" + days + "/" + years;                
    console.log(dateString);
    var goalDate = goalTableJson[key]['date'];
    if (goalDate != dateString){
        goalTableJson[key]['date'] = dateString;
        var goalString = JSON.stringify(goalTableJson);
        GM_setValue('GOALS_goal_table', goalString);
    }
}

Number.prototype.formatMoney = function(c, d, t){
var n = this, 
    c = isNaN(c = Math.abs(c)) ? 2 : c, 
    d = d == undefined ? "." : d, 
    t = t == undefined ? "," : t, 
    s = n < 0 ? "-$" : "$", 
    i = parseFloat(n = Math.abs(+n || 0).toFixed(c)) + "", 
    j = (j = i.split('.')[0].length) > 3 ? j % 3 : 0;
    return s + (j ? i.substr(0, j) + t : "") + i.substr(j).replace(/(\d{3})(?=\d)/g, "$1" + t) + (c && i%1 == 0 ? d + Math.abs(n - i).toFixed(c).slice(2) : "");
 };

function datediff(interval,date1,laterDate) {
    var second=1000, minute=second*60, hour=minute*60, day=hour*24, week=day*7;
    date1 = new Date(date1);
    var date2 = (laterDate ? new Date(date2) : new Date());
    var timediff = date2 - date1;
    if (isNaN(timediff)) return "";
    switch (interval) {
        case "years": return date2.getFullYear() - date1.getFullYear();
        case "months": return (
            ( date2.getFullYear() * 12 + date2.getMonth() )
            -
            ( date1.getFullYear() * 12 + date1.getMonth() )
        );
        case "weeks"  : return Math.floor(timediff / week);
        case "days"   : return Math.floor(timediff / day); 
        case "hours"  : return Math.floor(timediff / hour); 
        case "minutes": return Math.floor(timediff / minute);
        case "seconds": return Math.floor(timediff / second);
        case "all": 
            var retVal = {};
            retVal["years"] = date2.getFullYear() - date1.getFullYear();
            retVal["months"] = ( date2.getFullYear() * 12 + date2.getMonth() )-( date1.getFullYear() * 12 + date1.getMonth() )
            retVal["weeks"] = Math.floor(timediff/week);
            retVal["days"] = Math.floor(timediff/day);
            retVal["hours"] = Math.floor(timediff/hour);
            retVal["minutes"] = Math.floor(timediff/minute);
            retVal["seconds"] = Math.floor(timediff/second);
            return retVal;
        case "cmp":
            return date1 <= date2;
        default: return undefined;
    }
}

function AddAfter(rowId){
    var target = document.getElementById(rowId);
    var newElement = document.createElement('tr');
    target.parentNode.insertBefore(newElement, target.nextSibling );
    return newElement;
}

function deleteGoal(key){
    var rowKey = "row_"+key+"_goalTable";
    //console.log(rowKey);
    var target = document.getElementById(rowKey); 
    //target.parentNode.remove(target);
    target.remove();
    var newJson = [];
    for (var oldKey in goalTableJson){
        if (oldKey == key)
            console.log("found old key, removing");
        else
            newJson.push(goalTableJson[oldKey]);
    }
    //console.log(newJson);
    //goalTableJson.splice(key,1);
    numEntries--;
    GM_setValue('GOALS_goal_table', JSON.stringify(newJson));
    goalTableJson = newJson;
}

function showInfo(key){
    //console.log(goalTableJson[key]);
    var itemButton = document.getElementById("button_"+key);
    var item = goalTableJson[key];
    var infoDiv = document.createElement('div');
    var timeInfo = (item['date'] ? datediff("all", item['date'], "") : "");
    var rowKey = "row_"+key;
    var divRow = AddAfter(rowKey);
    rowKey += "_info";
    var divCell = document.createElement('td');
    var amountInt = parseFloat(item['amount']);
    var amountStart = parseFloat(item['start']);
    var diff = approvedHits - amountStart;
    var pendingSum = GM_getValue('GOALS_today_pending');
    
    divCell.style.cellPadding = '10px';
    divCell.setAttribute('align', 'center');
    divCell.setAttribute('id', rowKey);
    divCell.addEventListener("click", function() { var target = document.getElementById(rowKey); target.parentNode.remove(target);}, false);
    
    divRow.appendChild(divCell);
    divCell.setAttribute('colspan', '5');
    divCell.appendChild(infoDiv);
    
    infoDiv.style.width = "90%";
    infoDiv.style.backgroundColor = "#E9D99D";
    infoDiv.setAttribute('align', 'left');
    
    var progress = ((item['type'] == 'day' ? pendingSum : diff) / amountInt);
    progress = progress * 100;
    var progFull = Math.round(progress*100)/100;
    var complete = (progFull > 100 ? "Complete :D" : 100-progFull+"%");
    
    var difference = amountInt - (item['type'] == 'day' ? pendingSum : balance);
    
    var today = new Date();
    var dd = today.getDate();
    var mm = today.getMonth()+1; //January is 0!
    var yyyy = today.getFullYear();
    if(dd<10){dd='0'+dd} if(mm<10){mm='0'+mm} today = mm+'/'+dd+'/'+yyyy;
    var todaysDate = today;    
    
    var infoText = "As of today, "+todaysDate+", your goal of "+amountInt.formatMoney(2)+(progFull > 100 ? " has " : " has not ")+"been reached";

    if (progFull < 100){
        if (!datediff("cmp", item['date'], ""))
        {
            infoText += ". You are "+complete+" away from your goal, and need to make an additional "+difference.formatMoney(2)+" to reach it.";
            if (timeInfo){                
                var perHour = (timeInfo["hours"]*-1 > 0 ? difference / timeInfo["hours"] * -1 : 0);
                var perMinute = (timeInfo["minutes"]*-1 > 0 ? difference / timeInfo["minutes"] * -1 : 0);
                var perDay = (timeInfo["days"]*-1 > 0 ? difference / timeInfo["days"] * -1 : 0);
                var perMonth = (timeInfo["months"]*-1 > 0 ? difference / timeInfo["months"] * -1 : 0);
                var perWeek = (timeInfo["weeks"]*-1 > 0 ? difference / timeInfo["weeks"] * -1 : 0);
   
                infoText += " This means you need to make:";
            
                var list = document.createElement('ul');
                var monthElement = document.createElement('li');
                var weekElement = document.createElement('li');
                var dayElement = document.createElement('li');
                var hourElement = document.createElement('li');
                var minuteElement = document.createElement('li');
            
                monthElement.innerHTML = "$" + perMonth.toFixed(4) + " per month";
                weekElement.innerHTML = "$" + perWeek.toFixed(4) + " per week";
                dayElement.innerHTML = "$" + perDay.toFixed(4) + " per day";
                hourElement.innerHTML = "$" + perHour.toFixed(4) + " per hour";
                minuteElement.innerHTML = "$" + perMinute.toFixed(4) + " per minute";

                if (!perMonth == 0 && item['type'] != 'day')
                    list.appendChild(monthElement);
                if (!perWeek == 0 && item['type'] != 'day')
                    list.appendChild(weekElement);
                if (!perDay == 0 && item['type'] != 'day')
                    list.appendChild(dayElement);
                if (!perHour == 0)
                    list.appendChild(hourElement);
                if (!perMinute == 0)
                    list.appendChild(minuteElement);
                else{
                    var tempElement = document.createElement('li');
                    tempElement.innerHTML = "You have less than a minute to make "+difference.formatMoney(2)+"! Can you make it?!";
                    list.appendChild(tempElement);
                }
    
                infoDiv.textContent = infoText;
                infoDiv.appendChild(list);
            }
        }
        else{
            infoText += "...unfortunately, the deadline has passed. You were "+difference.formatMoney(2)+" away from meeting your goal :(";
            infoDiv.textContent = infoText;            
        }
        if (!timeInfo)
            infoDiv.textContent = infoText;
    }
    else{
        infoText += ", congratulations! Your goal of "+item['name']+" is within reach, all you need to do is withdraw the money. Visit your account information screen to do so!";
        infoDiv.textContent = infoText;
    }
}

function toggleGoalDiv(){
    var target = document.getElementById('goal_div');
    if (!target){
        //console.log("created div");
        showAddGoalTable();
    }
    else
        target.remove();
}

function toggleExportDiv(){
    var target = document.getElementById('export_div');
    if (!target){
        //console.log("created div");
        showExportDiv();
    }
    else
        target.remove();
}

var goalTableJson = "";
if (GM_getValue('GOALS_goal_table')){
    var goalStuff = GM_getValue('GOALS_goal_table');
    goalTableJson = JSON.parse(goalStuff);
}
var numEntries = (GM_getValue('GOALS_goal_table') ? Object.keys(goalTableJson).length : 0);


function apply_template()
{
    var txt = TEMPLATE;
      
    var outString = "";    
  
    var vars = ['name', 'amount', 'days', 'percent', 'type'];
    
    var pendingSum = GM_getValue('GOALS_today_pending');
    
    for (var key in goalTableJson){  
        var tempTemp = txt;        
        for (var i=0; i<vars.length; i++)
        {
            t = new RegExp('\{' + vars[i] + '\}', 'g');
            if (vars[i] == 'name')
                tempTemp = tempTemp.replace(t, goalTableJson[key][vars[i]]);
            else if (vars[i] == 'amount')
                tempTemp = tempTemp.replace(t, parseFloat(goalTableJson[key][vars[i]]).formatMoney(2));
            else if (vars[i] == 'percent'){
                var progress = ((goalTableJson[key]['type'] == 'day' ? pendingSum : balance) / amountInt);
                progress = progress * 100;
                var progFull = Math.round(progress*100)/100;
                tempTemp = tempTemp.replace(t, (progFull >= 100 ? "Complete :D" : progFull+"%"));
            }
            else if (vars[i] == 'days'){
                var amountInt = parseFloat(goalTableJson[key]['amount']);
                var progress = ((goalTableJson[key]['type'] == 'day' ? pendingSum : balance) / amountInt);
                progress = progress * 100;
                var progFull = Math.round(progress*100)/100;
                console.log(progFull);
                var daysDiff = (progFull >= 100 ? "Complete :D" : (goalTableJson[key]['type'] == 'day' ? "Daily Goal" : (goalTableJson[key]['date'] ? datediff("days", goalTableJson[key]['date'], "") * -1 : "No end date given")));
                tempTemp = tempTemp.replace(t, daysDiff);
            }
            else if (vars[i] == 'type')
            {
                var replaceString = (goalTableJson[key]['type'] ? (goalTableJson[key]['type'] == 'day' ? "Daily Goal" : "Normal Goal") : (goalTableJson[key]['date'] ? "Deadline" : "No Deadline"));
                tempTemp = tempTemp.replace(t, replaceString);
            }
        }
        outString += tempTemp + "\n";
    }
    return outString;
}

function showAddGoalTable(){
    var goal_div = document.createElement('div');
    var goalTable = document.createElement('table');
    var header_row = document.createElement('tr');
    var typeCell = document.createElement('td');
    var checkbox = document.createElement('td');
    var goal_name = document.createElement('td');
    var goal_amount = document.createElement('td');
    var date = document.createElement('td');
    var order = document.createElement('td');
    var radioNames = [];
    
    goal_div.style.position = 'fixed';
    goal_div.style.left = '20%';
    goal_div.style.right = '20%';
    goal_div.style.top = '300px';
    goal_div.style.padding = '5px';
    goal_div.style.border = '2px solid black';
    goal_div.style.backgroundColor = 'white';
    goal_div.setAttribute('id', 'goal_div');
    
    goalTable.style.margin = '0 auto 0 auto';
    goalTable.style.width = '90%';
    goalTable.setAttribute('id', 'goal_table');
    
    checkbox.textContent = 'Delete?';
    typeCell.textContent = 'Type';
    goal_name.textContent = 'Goal Name';
    goal_amount.textContent = 'Goal Amount';
    date.textContent = 'Date (optional)';
    order.textContent = 'Goal fill order';
    
    goalTable.appendChild(header_row);
    header_row.style.backgroundColor = '#7fb4cf';//'#7fb4cf';
    header_row.appendChild(goal_name);
    header_row.appendChild(typeCell);
    header_row.appendChild(goal_amount);
    header_row.appendChild(date);
    header_row.appendChild(checkbox);
    header_row.appendChild(order);
    header_row.setAttribute("NoDrag", 1);

    if (!goalTableJson || goalTableJson.length == 0){
        var contentRow1 = document.createElement('tr');
        var noContent = document.createElement('td');
        noContent.textContent = 'Uh-oh, it looks like you haven\'t set any goals. Click the \'Add goal\' button below to add one!';
        noContent.setAttribute('colspan', '5');
        contentRow1.setAttribute('id', 'noContentRow');
        goalTable.appendChild(contentRow1);
        contentRow1.appendChild(noContent);
    }
    else{
        var goalString = goalTableJson;
        for (var key in goalString){
            var new_row = document.createElement('tr');
            var checkbox = document.createElement('td');
            var type = document.createElement('td');
            var goal_name = document.createElement('td');
            var goal_amount = document.createElement('td');
            var date = document.createElement('td');
            var order = document.createElement('td');
            
            order.textContent = parseInt(key)+1;
            
            var rowKey = "row_"+key+"_goalTable";
            new_row.setAttribute('id', rowKey);
                    
            var element1 = document.createElement("input");
            element1.type = "radio";
            element1.id = key ;
            checkbox.appendChild(element1);            
            
            id = "radio_"+key;
            radioNames.push(id);
            element1.setAttribute('id', id);
                
            goal_name.textContent = goalString[key]['name'];
            type.textContent = (goalString[key]['type'] ? goalString[key]['type'] : (goalString[key]['date'] ? "Deadline" : "Normal"));
            goal_amount.textContent = parseFloat(goalString[key]['amount']).formatMoney(2);
            date.textContent = goalString[key]['date'];
 
            goalTable.appendChild(new_row);
            new_row.appendChild(goal_name);
            new_row.appendChild(type);
            new_row.appendChild(goal_amount);
            new_row.appendChild(date);
            new_row.appendChild(checkbox);
            new_row.appendChild(order);
        }      
    }

    var new_row = document.createElement('tr');
    var b1 = document.createElement('td');
    var b2 = document.createElement('td');
    var b3 = document.createElement('td');
    var b4 = document.createElement('td');
    var b5 = document.createElement('td');
    var add_row = document.createElement('button');
    var delete_all = document.createElement('button');
    var save_button = document.createElement('button');
    var hide_button = document.createElement('button');
    var reorder_button = document.createElement('button');
    
    add_row.textContent = ' Add goal ';
    add_row.setAttribute('id', 'add_goal');
    add_row.style.height = '18px';
    add_row.style.width = '100px';
    add_row.style.fontSize = '10px';
    add_row.style.paddingLeft = '3px';
    add_row.style.paddingRight = '3px';
    add_row.style.backgroundColor = 'white';
    add_row.style.marginLeft = '5px';
    add_row.title = 'Add a new goal';
    b1.appendChild(add_row);
    b1.setAttribute('aligh','left');
    
    delete_all.textContent = ' Delete ';
    delete_all.setAttribute('id', 'delete_all');
    delete_all.style.height = '18px';
    delete_all.style.width = '100px';
    delete_all.style.fontSize = '10px';
    delete_all.style.paddingLeft = '3px';
    delete_all.style.paddingRight = '3px';
    delete_all.style.backgroundColor = 'white';
    delete_all.style.marginLeft = '5px';
    delete_all.title = 'Delete all goals from storage';
    b2.appendChild(delete_all);
    b2.setAttribute('align','center');
    
    save_button.textContent = 'Save';
    save_button.setAttribute('id', 'save_button');
    save_button.style.height = '18px';
    save_button.style.width = '100px';
    save_button.style.fontSize = '10px';
    save_button.style.paddingLeft = '3px';
    save_button.style.paddingRight = '3px';
    save_button.style.backgroundColor = 'white';
    save_button.style.marginLeft = '5px';
    save_button.title = 'Save goals in storage';
    b3.appendChild(save_button);
    b3.setAttribute('align','center');
    
    hide_button.textContent = 'Cancel';
    hide_button.setAttribute('id', 'hide_button');
    hide_button.style.height = '18px';
    hide_button.style.width = '100px';
    hide_button.style.fontSize = '10px';
    hide_button.style.paddingLeft = '3px';
    hide_button.style.paddingRight = '3px';
    hide_button.style.backgroundColor = 'white';
    hide_button.style.marginLeft = '5px';
    hide_button.title = 'Hide div';
    b4.appendChild(hide_button);
    b4.setAttribute('align','center');  
    
    reorder_button.textContent = 'Reorder';
    reorder_button.setAttribute('id', 'reorder_button');
    reorder_button.style.height = '18px';
    reorder_button.style.width = '100px';
    reorder_button.style.fontSize = '10px';
    reorder_button.style.paddingLeft = '3px';
    reorder_button.style.paddingRight = '3px';
    reorder_button.style.backgroundColor = 'white';
    reorder_button.style.marginLeft = '5px';
    reorder_button.title = 'Reorder Goals';
    b5.appendChild(reorder_button);
    b5.setAttribute('align','right');  
    
    new_row.setAttribute("NoDrag", 1);
    new_row.appendChild(b1);
    new_row.appendChild(b2);
    new_row.appendChild(b3);
    new_row.appendChild(b4);
    new_row.appendChild(b5);
    goalTable.appendChild(new_row);
    
    delete_all.addEventListener("click", function() {if (confirm("Are you sure you want to delete all goals forever?")) GM_deleteValue('GOALS_goal_table'); goalTableJson = []; toggleGoalDiv(); toggleGoalDiv();}, false);
    add_row.addEventListener("click", function() {addRow_func();}, false);
    save_button.addEventListener("click", function() {if (save_values()) alert("Values successfully saved!"); else alert("Some error occurred :(");}, false);
    hide_button.addEventListener("click", function() {numEntries = (GM_getValue('GOALS_goal_table') ? Object.keys(goalTableJson).length : 0); toggleGoalDiv(); addGoalInformation();}, false);
    reorder_button.addEventListener("click", function() {saveOrder_func();}, false);
    
    goal_div.appendChild(goalTable);
    document.body.insertBefore(goal_div,document.getElementsByClassName('footer_separator')[0]);
    goal_div.style.display = 'block';    
    for (var i = 0; i < radioNames.length; i++) {
    (function (i) { 
        document.getElementById(radioNames[i]).addEventListener("click", function() {if (confirm("Are you sure you want to delete that goal?")) deleteGoal(i);}, false);
        })(i);
    }
    var goalTable = document.getElementById('goal_table');
    console.log(goalTable);
    var tableDnD = new TableDnD();
    tableDnD.init(goalTable);
}

function edit_func()
{
    var textarea = document.getElementById('export_text_area');
    if (EDIT == true)
    {
        EDIT = false;
        TEMPLATE = textarea.value;
        GM_setValue('GOALS_export_template', TEMPLATE);
        document.getElementById('edit_button').textContent = 'Edit Template';
        textarea.value = apply_template();
        textarea.readOnly = true;
      }
      else
      {
        EDIT = true;
        document.getElementById('edit_button').textContent = 'Show Changes';
        textarea.textContent = TEMPLATE;
        textarea.readOnly = false;
      }  
}

function showExportDiv(){
    var exportDiv = document.createElement('div');
    var textarea = document.createElement('textarea'); 

    exportDiv.style.position = 'fixed';
    exportDiv.style.width = '500px';
    exportDiv.style.height = '235px';
    exportDiv.style.left = '50%';
    exportDiv.style.right = '50%';
    exportDiv.style.margin = '-250px 0px 0px -250px';
    exportDiv.style.top = '300px';
    exportDiv.style.padding = '5px';
    exportDiv.style.border = '2px';
    exportDiv.style.backgroundColor = 'black';
    exportDiv.style.color = 'white';
    exportDiv.style.zIndex = '100';
    exportDiv.setAttribute('id', 'export_div');

    textarea.style.padding = '2px';
    textarea.style.width = '500px';
    textarea.style.height = '200px';
    textarea.title = 'Template accepts {name}, {amount}, {days}, {type}, and {percent}';
    textarea.setAttribute('id', 'export_text_area');
    textarea.textContent = apply_template();

    exportDiv.textContent = 'Press Ctrl+C to copy to clipboard. Click exit to close.';
    exportDiv.style.fontSize = '12px';
    exportDiv.appendChild(textarea);
    var edit_button = document.createElement('button');
    var hideButton = document.createElement('button');

    edit_button.textContent = 'Edit Template';
    edit_button.setAttribute('id', 'edit_button');
    edit_button.style.height = '18px';
    edit_button.style.width = '100px';
    edit_button.style.fontSize = '10px';
    edit_button.style.paddingLeft = '3px';
    edit_button.style.paddingRight = '3px';
    edit_button.style.backgroundColor = 'white';
    
    hideButton.textContent = 'Exit';
    hideButton.setAttribute('id', 'hide_export_button');
    hideButton.style.height = '18px';
    hideButton.style.width = '100px';
    hideButton.style.fontSize = '10px';
    hideButton.style.paddingLeft = '3px';
    hideButton.style.paddingRight = '3px';
    hideButton.style.backgroundColor = 'white';
    
    exportDiv.appendChild(edit_button);
    exportDiv.appendChild(hideButton);
    hideButton.addEventListener("click", function() {toggleExportDiv();}, false);
    edit_button.addEventListener("click", function() {edit_func();}, false);
    document.body.insertBefore(exportDiv,document.getElementsByClassName('footer_separator')[0]);
    textarea.focus();
    textarea.select();
    textarea.readOnly = true;
}

function refresh_func(){
    console.log("Debug refresh started...");
    balance = get_balance();
    GM_setValue('GOALS_balance', balance);
    console.log("Balance: "+balance);
    goalTableJson = JSON.parse(GM_getValue('GOALS_goal_table'));
    console.log("JSON:");
    console.log(""+JSON.stringify(goalTableJson));
    console.log("Debug refresh ended. Please reload.");
    addGoalInformation();
}

if (window.location.href == "https://www.mturk.com/mturk/dashboard") {
    addGoalInformation();
}

function addGoalInformation(){
    if (!document.getElementById('primary_goal_table')){
        var footer = document.getElementsByClassName('footer_separator')[0];
        if (footer == null)
          return;
        
        var extra_table = document.createElement('table');
        extra_table.width = '700';
        extra_table.style.boder = '1px solid black';
        extra_table.align = 'center';
        extra_table.cellSpacing = '0px';
        extra_table.cellPadding = '0px';
        extra_table.setAttribute('id', 'primary_goal_table');
        
        var row1 = document.createElement('tr');
        var row2 = document.createElement('tr');
        var td1 = document.createElement('td');
        var td2 = document.createElement('td');
        var content_td = document.createElement('td');
        
        var whatsthis = document.createElement('a');
        
        var goals_button = document.createElement('button');
        var export_button = document.createElement('button');
        var force_refresh_button = document.createElement('button');
        //export_button.addEventListener("click", export_func(), false);
      
        row1.style.height = '25px';
        row1.setAttribute('id', 'goals_header_row');
        td1.setAttribute('class', 'white_text_14_bold');
        td1.style.backgroundColor = '#7fb4cf';//'#7fb4cf';
        td1.style.paddingLeft = '10px';
        td1.innerHTML = '	Goals ';
        content_td.setAttribute('class', 'container-content');
        content_td.setAttribute('colspan', '2');
        
        whatsthis.href = 'javascript:alert(\'Allows you to define custom goals, based on the information that you give it. For more information, click the goal name. Click the info pane to close.\')';
        whatsthis.setAttribute('class', 'whatis');
        whatsthis.textContent = '(What\'s this?)';
        goals_button.setAttribute('class', 'goals_button');
        goals_button.textContent = 'Define Goals';
        export_button.setAttribute('class', 'export_button');
        export_button.textContent = 'Export Data';
        force_refresh_button.setAttribute('class', 'refresh_button');
        force_refresh_button.textContent = "Refresh";
        
        td2.setAttribute('class', 'white_text_14_bold');
        td2.style.backgroundColor = '#7fb4cf';//'#7fb4cf';
        td2.style.paddingLeft = '10px';
        td2.setAttribute('align', 'right');
        goals_button.addEventListener("click", function() { toggleGoalDiv(); }, false);
        export_button.addEventListener("click", function() { toggleExportDiv(); }, false);
        force_refresh_button.addEventListener("click", function() { console.log("Refresh button clicked."); refresh_func(); }, false);
        td2.appendChild(force_refresh_button);
        td2.appendChild(goals_button);
        td2.appendChild(export_button);
        
        extra_table.appendChild(row1);
        row1.appendChild(td1);
        td1.appendChild(whatsthis);
        row1.appendChild(td2);
        extra_table.appendChild(row2);
        row2.appendChild(content_td);
        footer.parentNode.insertBefore(extra_table, footer);  
       
        var my_bar = document.createElement('div');
        
        my_bar.setAttribute('id', 'my_bar');
      
        content_td.appendChild(my_bar);
      
        my_bar.style.textAlign = "float";
        
        var contentTable = document.createElement('table');
        contentTable.setAttribute('id', 'goals_content_table');
        contentTable.setAttribute('width','100%');
        
        if (!GM_getValue('GOALS_goal_table')){
            var contentRow1 = document.createElement('tr');
            var noContent = document.createElement('td');
            noContent.textContent = 'Uh-oh, it looks like you haven\'t set any goals. Click the \'goals\' button above to define some!';
            contentTable.appendChild(contentRow1);
            contentRow1.appendChild(noContent);
            my_bar.appendChild(contentTable);
        }
        
        else
        {
            var goalString = GM_getValue('GOALS_goal_table');
            var goalJson = JSON.parse(goalString);
            ////console.log("JSON parsed successfully "+goalJson);
            
            var headerRow = document.createElement('tr');
            var goalTypeCell = document.createElement('td');
            var goalNameCell = document.createElement('td');
            var goalAmountCell = document.createElement('td');
            var timeLeftCell = document.createElement('td');
            var progressBarCell = document.createElement('td');
            
            goalTypeCell.textContent = "Type";
            goalNameCell.textContent = "Goal";
            goalAmountCell.textContent = "Amount";
            timeLeftCell.textContent = "Days Remaining";
            progressBarCell.textContent = "Percent complete";
            
            headerRow.style.backgroundColor = '#7fb4cf';//'#7fb4cf';
            
            contentTable.appendChild(headerRow);
            headerRow.appendChild(goalNameCell);
            headerRow.appendChild(goalTypeCell);
            headerRow.appendChild(goalAmountCell);
            headerRow.appendChild(timeLeftCell);
            headerRow.appendChild(progressBarCell);
            
            var buttonNames = [];
            var goalBalanceRemaining = 0;
            for (var key in goalJson){
                var new_row = document.createElement('tr');
                var goal_type = document.createElement('td');
                var goal_name = document.createElement('td');
                var goal_amount = document.createElement('td');
                var time_remaining = document.createElement('td');
                var progCell = document.createElement('td');
                var progBar = document.createElement('div');
    			var progLabel = document.createElement('div');         
                var amountInt = parseFloat(goalJson[key]['amount']);
                var amountStart = parseFloat(goalJson[key]['start']);
                var nameLink = document.createElement('button');
                var pendingSum = GM_getValue('GOALS_today_pending');
            
                var rowKey = "row_"+key;
                new_row.setAttribute('id', rowKey);
                
                goal_type.textContent = (goalJson[key]['type'] == 'normal' || !goalJson[key]['type'] ? (goalJson[key]['date'] ? "Deadline" : "No Deadline") : "Daily Goal");
                
                if (goalJson[key]['type'] == 'day'){
                    updateDate(key);
                }
                
                nameLink.textContent = goalJson[key]['name'];            
                nameLink.style.background = 'none';
                nameLink.style.border = 'none';
                nameLink.style.margin = '0';
                nameLink.style.padding = '0';
                var id = "button_"+key;
                buttonNames.push(id);
                nameLink.setAttribute('id', id);
                
                //goal_name.textContent = goalJson[key]['name'];
                goal_name.appendChild(nameLink);
                goal_amount.textContent = amountInt.formatMoney(2);
                        
                var now = new Date();
                daysDiff = (goalJson[key]['date'] ? datediff("days", goalJson[key]['date'], "") * -1 : null);
                //daysDiff *= -1;
                
                var balanceThisGoal = approvedHits - amountStart - goalBalanceRemaining;
                
                if (balanceThisGoal < 0){
                    goalBalanceRemaining = balanceThisGoal * -1;
                    var progress = 0;
                    console.log("balance this goal: "+balanceThisGoal);
                    var progFull = Math.round(progress*100)/100;
                    progress = (progFull >= 100 ? "100" : progFull);
                    progFull = (progFull > 100 ? "Complete :D" : progFull+"%");
                    time_remaining.textContent = "Previous goals incomplete";
                }
                else {
                    goalBalanceRemaining = balanceThisGoal;
                    var progress = ((goalJson[key]['type'] == 'day' ? pendingSum : balanceThisGoal) / amountInt);
                    progress = progress * 100;
                    var progFull = Math.round(progress*100)/100;
                    progress = (progFull >= 100 ? "100" : progFull);
                    progFull = (progFull > 100 ? "Complete :D" : progFull+"%");
                    time_remaining.textContent = (daysDiff ? (daysDiff > 0 ? daysDiff : (progress < 100 ? "Date passed :(" : "Complete :D")) : (progress < 100 ? "No date given" : "Complete :D"));
                }
          
                progBar.style.color = 'white';
                progBar.style.backgroundColor = '#7fb4cf';
                progBar.style.position = "relative";
                progBar.innerHTML = '&nbsp;';
                progBar.setAttribute = ('align', 'left');
                progBar.style.width = progress + "%";
            
                progLabel.textContent = progFull;
                progLabel.style.textAlign = 'center';
                progLabel.style.color = 'white';
                progLabel.style.position = "absolute";
                progLabel.style.top = "5%";
                progLabel.style.left = "40%";            
                progLabel.style.zIndex = '1';
            
                progCell.appendChild(progBar);
                progCell.appendChild(progLabel);
                progCell.style.display = "block";
                progCell.style.position = "relative";
                progCell.style.backgroundColor = 'gray';
 
                contentTable.appendChild(new_row);
                new_row.appendChild(goal_name);
                new_row.appendChild(goal_type);
                new_row.appendChild(goal_amount);
                new_row.appendChild(time_remaining);
                new_row.appendChild(progCell);
        }
        my_bar.appendChild(contentTable);
        for (var i = 0; i < buttonNames.length; i++) {
            (function (i) { 
                document.getElementById(buttonNames[i]).addEventListener("click", function() {if (!document.getElementById("row_"+i+"_info")) showInfo(i);}, false);
            })(i);
        }
        }
    }
    else
    {
        var target = document.getElementById('goals_content_table');
        var contentTable2 = target.parentNode.replaceChild(document.createElement('table'), target);
        for(var i = contentTable2.rows.length - 1; i > -1; i--)
        {
            contentTable2.deleteRow(i);
        }
        if (!GM_getValue('GOALS_goal_table')){
            var contentRow1 = document.createElement('tr');
            var noContent = document.createElement('td');
            noContent.textContent = 'Uh-oh, it looks like you haven\'t set any goals. Click the \'goals\' button above to define some!';
            contentTable2.appendChild(contentRow1);
            contentRow1.appendChild(noContent);
            document.getElementById('my_bar').appendChild(contentTable2);
        }
        else{
            var goalString = GM_getValue('GOALS_goal_table');
            var goalJson = JSON.parse(goalString);
            var headerRow = document.createElement('tr');
            var goalTypeCell = document.createElement('td');
            var goalNameCell = document.createElement('td');
            var goalAmountCell = document.createElement('td');
            var timeLeftCell = document.createElement('td');
            var progressBarCell = document.createElement('td');
                
            goalTypeCell.textContent = "Type";
            goalNameCell.textContent = "Goal";
            goalAmountCell.textContent = "Amount";
            timeLeftCell.textContent = "Days Remaining";
            progressBarCell.textContent = "Percent complete";
            
            headerRow.style.backgroundColor = '#7fb4cf';//'#7fb4cf';
                
            contentTable2.appendChild(headerRow);
            headerRow.appendChild(goalNameCell);
            headerRow.appendChild(goalTypeCell);
            headerRow.appendChild(goalAmountCell);
            headerRow.appendChild(timeLeftCell);
            headerRow.appendChild(progressBarCell);
                
            var buttonNames = [];
            var goalBalanceRemaining = 0;
            for (var key in goalJson){
                var new_row = document.createElement('tr');
                var goal_type = document.createElement('td');
                var goal_name = document.createElement('td');
                var goal_amount = document.createElement('td');
                var time_remaining = document.createElement('td');
                var progCell = document.createElement('td');
                var progBar = document.createElement('div');
        	    var progLabel = document.createElement('div');         
                var amountInt = parseFloat(goalJson[key]['amount']);
                var amountStart = parseFloat(goalJson[key]['start']);
                var nameLink = document.createElement('button');
                var pendingSum = GM_getValue('GOALS_today_pending');
                
                var rowKey = "row_"+key;
                new_row.setAttribute('id', rowKey);
                
                goal_type.textContent = (goalJson[key]['type'] == 'normal' || !goalJson[key]['type'] ? (goalJson[key]['date'] ? "Deadline" : "No Deadline") : "Daily Goal");
                
                if (goalJson[key]['type'] == 'day'){
                    updateDate(key);
                }
                    
                nameLink.textContent = goalJson[key]['name'];            
                nameLink.style.background = 'none';
                nameLink.style.border = 'none';
                nameLink.style.margin = '0';
                nameLink.style.padding = '0';
                var id = "button_"+key;
                buttonNames.push(id);
                nameLink.setAttribute('id', id);
                    
                //goal_name.textContent = goalJson[key]['name'];
                goal_name.appendChild(nameLink);
                goal_amount.textContent = amountInt.formatMoney(2);
                            
                var now = new Date();
                daysDiff = (goalJson[key]['date'] ? datediff("days", goalJson[key]['date'], "") * -1 : null);
                //daysDiff *= -1;
                            
                var balanceThisGoal = approvedHits - amountStart - goalBalanceRemaining;
                
				console.log("Info: "+balanceThisGoal + " " + amountInt + " " + approvedHits + " " + (approvedHits - amountStart));
                if (balanceThisGoal < 0){
                    goalBalanceRemaining = balanceThisGoal * -1;
                    var progress = 0;
                    console.log("balance this goal: "+balanceThisGoal);
                    var progFull = Math.round(progress*100)/100;
                    progress = (progFull >= 100 ? "100" : progFull);
                    progFull = (progFull > 100 ? "Complete :D" : progFull+"%");
                    time_remaining.textContent = "Previous goals incomplete";
                }
                else {
                    goalBalanceRemaining = balanceThisGoal;
					console.log("balance this goal: "+balanceThisGoal);
                    var progress = ((goalJson[key]['type'] == 'day' ? pendingSum : balanceThisGoal) / amountInt);
                    progress = progress * 100;
                    var progFull = Math.round(progress*100)/100;
                    progress = (progFull >= 100 ? "100" : progFull);
                    progFull = (progFull > 100 ? "Complete :D" : progFull+"%");
                    time_remaining.textContent = (daysDiff ? (daysDiff > 0 ? daysDiff : (progress < 100 ? "Date passed :(" : "Complete :D")) : (progress < 100 ? "No date given" : "Complete :D"));
                }
              
                progBar.style.color = 'white';
                progBar.style.backgroundColor = '#7fb4cf';
                progBar.style.position = "relative";
                progBar.innerHTML = '&nbsp;';
                progBar.setAttribute = ('align', 'left');
                progBar.style.width = progress + "%";
                
                progLabel.textContent = progFull;
                progLabel.style.textAlign = 'center';
                progLabel.style.color = 'white';
                progLabel.style.position = "absolute";
                progLabel.style.top = "5%";
                progLabel.style.left = "40%";            
                progLabel.style.zIndex = '1';
                
                progCell.appendChild(progBar);
                progCell.appendChild(progLabel);
                progCell.style.display = "block";
                progCell.style.position = "relative";
                progCell.style.backgroundColor = 'gray';
     
                contentTable2.appendChild(new_row);
                new_row.appendChild(goal_name);
                new_row.appendChild(goal_type);
                new_row.appendChild(goal_amount);
                new_row.appendChild(time_remaining);
                new_row.appendChild(progCell);
            }
            document.getElementById('my_bar').appendChild(contentTable2);
            for (var i = 0; i < buttonNames.length; i++) {
                (function (i) { 
                    document.getElementById(buttonNames[i]).addEventListener("click", function() {if (!document.getElementById("row_"+i+"_info")) showInfo(i);}, false);
                })(i);
            }
        }
    }
 
}








// ===================================================================
// Author: Denis Howlett <[email protected]>
// WWW: http://www.isocra.com/
//
// NOTICE: You may use this code for any purpose, commercial or
// private, without any further permission from the author. You may
// remove this notice from your final code if you wish, however we
// would appreciate it if at least the web site address is kept.
//
// You may *NOT* re-distribute this code in any way except through its
// use. That means, you can include it in your product, or your web
// site, or any other form where the code is actually being used. You
// may not put the plain javascript up on your site for download or
// include it in your javascript libraries for download.
// If you wish to share this code with others, please just point them
// to the URL instead.
//
// Please DO NOT link directly to this .js files from your site. Copy
// the files to your server and use them there. Thank you.
// ===================================================================

/** Keep hold of the current table being dragged */
var currenttable = null;

/** Capture the onmousemove so that we can see if a row from the current
 *  table if any is being dragged.
 * @param ev the event (for Firefox and Safari, otherwise we use window.event for IE)
 */
document.onmousemove = function(ev){
    if (currenttable && currenttable.dragObject) {
        ev   = ev || window.event;
        var mousePos = currenttable.mouseCoords(ev);
        var y = mousePos.y - currenttable.mouseOffset.y;
        if (y != currenttable.oldY) {
            // work out if we're going up or down...
            var movingDown = y > currenttable.oldY;
            // update the old value
            currenttable.oldY = y;
            // update the style to show we're dragging
            currenttable.dragObject.style.backgroundColor = "#eee";
            // If we're over a row then move the dragged row to there so that the user sees the
            // effect dynamically
            var currentRow = currenttable.findDropTargetRow(y);
            if (currentRow) {
                if (movingDown && currenttable.dragObject != currentRow) {
                    currenttable.dragObject.parentNode.insertBefore(currenttable.dragObject, currentRow.nextSibling);
                } else if (! movingDown && currenttable.dragObject != currentRow) {
                    currenttable.dragObject.parentNode.insertBefore(currenttable.dragObject, currentRow);
                }
            }
        }

        return false;
    }
}

// Similarly for the mouseup
document.onmouseup   = function(ev){
    if (currenttable && currenttable.dragObject) {
        var droppedRow = currenttable.dragObject;
        // If we have a dragObject, then we need to release it,
        // The row will already have been moved to the right place so we just reset stuff
        droppedRow.style.backgroundColor = 'transparent';
        currenttable.dragObject   = null;
        // And then call the onDrop method in case anyone wants to do any post processing
        currenttable.onDrop(currenttable.table, droppedRow);
        currenttable = null; // let go of the table too
    }
}


/** get the source element from an event in a way that works for IE and Firefox and Safari
 * @param evt the source event for Firefox (but not IE--IE uses window.event) */
function getEventSource(evt) {
    if (window.event) {
        evt = window.event; // For IE
        return evt.srcElement;
    } else {
        return evt.target; // For Firefox
    }
}

/**
 * Encapsulate table Drag and Drop in a class. We'll have this as a Singleton
 * so we don't get scoping problems.
 */
function TableDnD() {
    /** Keep hold of the current drag object if any */
    this.dragObject = null;
    /** The current mouse offset */
    this.mouseOffset = null;
    /** The current table */
    this.table = null;
    /** Remember the old value of Y so that we don't do too much processing */
    this.oldY = 0;

    /** Initialise the drag and drop by capturing mouse move events */
    this.init = function(table) {
        this.table = table;
        var rows = table.rows; //getElementsByTagName("tr")
        for (var i=0; i<rows.length; i++) {
			// John Tarr: added to ignore rows that I've added the NoDnD attribute to (Category and Header rows)
			var nodrag = rows[i].getAttribute("NoDrag");
			if (nodrag == null || nodrag == "undefined") { //There is no NoDnD attribute on rows I want to drag
				this.makeDraggable(rows[i]);
			}
        }
    }

    /** This function is called when you drop a row, so redefine it in your code
        to do whatever you want, for example use Ajax to update the server */
    this.onDrop = function(table, droppedRow) {
        var rows = this.table.rows;
        var debugStr = "rows now: ";
        for (var i=0; i<rows.length; i++) {
            debugStr += rows[i].id+" ";
        }
        console.log('row['+droppedRow.id+'] dropped<br>'+debugStr);
    }

	/** Get the position of an element by going up the DOM tree and adding up all the offsets */
    this.getPosition = function(e){
        var left = 0;
        var top  = 0;
		/** Safari fix -- thanks to Luis Chato for this! */
		if (e.offsetHeight == 0) {
			/** Safari 2 doesn't correctly grab the offsetTop of a table row
			    this is detailed here:
			    http://jacob.peargrove.com/blog/2006/technical/table-row-offsettop-bug-in-safari/
			    the solution is likewise noted there, grab the offset of a table cell in the row - the firstChild.
			    note that firefox will return a text node as a first child, so designing a more thorough
			    solution may need to take that into account, for now this seems to work in firefox, safari, ie */
			e = e.firstChild; // a table cell
		}

        while (e.offsetParent){
            left += e.offsetLeft;
            top  += e.offsetTop;
            e     = e.offsetParent;
        }

        left += e.offsetLeft;
        top  += e.offsetTop;

        return {x:left, y:top};
    }

	/** Get the mouse coordinates from the event (allowing for browser differences) */
    this.mouseCoords = function(ev){
        if(ev.pageX || ev.pageY){
            return {x:ev.pageX, y:ev.pageY};
        }
        return {
            x:ev.clientX + document.body.scrollLeft - document.body.clientLeft,
            y:ev.clientY + document.body.scrollTop  - document.body.clientTop
        };
    }

	/** Given a target element and a mouse event, get the mouse offset from that element.
		To do this we need the element's position and the mouse position */
    this.getMouseOffset = function(target, ev){
        ev = ev || window.event;

        var docPos    = this.getPosition(target);
        var mousePos  = this.mouseCoords(ev);
        return {x:mousePos.x - docPos.x, y:mousePos.y - docPos.y};
    }

	/** Take an item and add an onmousedown method so that we can make it draggable */
    this.makeDraggable = function(item) {
        if(!item) return;
        var self = this; // Keep the context of the TableDnd inside the function
        item.onmousedown = function(ev) {
            // Need to check to see if we are an input or not, if we are an input, then
            // return true to allow normal processing
            var target = getEventSource(ev);
            if (target.tagName == 'INPUT' || target.tagName == 'SELECT') return true;
            currenttable = self;
            self.dragObject  = this;
            self.mouseOffset = self.getMouseOffset(this, ev);
            return false;
        }
        item.style.cursor = "move";
    }

    /** We're only worried about the y position really, because we can only move rows up and down */
    this.findDropTargetRow = function(y) {
        var rows = this.table.rows;
		for (var i=0; i<rows.length; i++) {
			var row = rows[i];
			// John Tarr added to ignore rows that I've added the NoDnD attribute to (Header rows)
			var nodrop = row.getAttribute("NoDrop");
			if (nodrop == null || nodrop == "undefined") {  //There is no NoDnD attribute on rows I want to drag
				var rowY    = this.getPosition(row).y;
				var rowHeight = parseInt(row.offsetHeight)/2;
				if (row.offsetHeight == 0) {
					rowY = this.getPosition(row.firstChild).y;
					rowHeight = parseInt(row.firstChild.offsetHeight)/2;
				}
				// Because we always have to insert before, we need to offset the height a bit
				if ((y > rowY - rowHeight) && (y < (rowY + rowHeight))) {
					// that's the row we're over
					return row;
				}
			}
		}
		return null;
	}
}