MTurk Dashboard Goals

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

// ==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 <feedback@isocra.com>
// 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;
	}
}