// ==UserScript==
// @name MTurk HIT DataBase Legacy
// @namespace https://greasyfork.org/users/710
// @description Extended ability to search HITs you have worked on and other useful tools (CSV export/import, requester notes, requester block, pending/projected earnings)
// @include https://www.mturk.com/mturk/searchbar*
// @include https://www.mturk.com/mturk/findhits*
// @include https://www.mturk.com/mturk/viewhits*
// @include https://www.mturk.com/mturk/viewsearchbar*
// @include https://www.mturk.com/mturk/sortsearchbar*
// @include https://www.mturk.com/mturk/sorthits*
// @include https://www.mturk.com/mturk/dashboard
// @include https://www.mturk.com/mturk/preview?*
// @version 1.9.6.2
// @grant none
// @require http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js
// @require http://code.highcharts.com/highcharts.js
// @require https://greasyfork.org/scripts/2351-jsdiff/code/jsdiff.js?version=6256
// @require https://greasyfork.org/scripts/2350-filesaver-js/code/filesaverjs.js?version=6255
// ==/UserScript==
//
// 2012-10-03 0.9.7: This is rewrite of MTurk Extended HIT Search (http://userscripts.org/scripts/show/146277)
// with some extra features (and some missing for now: search by date).
// It now uses IndexedDB (http://en.wikipedia.org/wiki/Indexed_Database_API)
//
// 2012-10-04 0.9.8: Improved use of indexes, check Pending Payment HITs
// 0.9.9: Minor improvements
//
// 2012-10-04 0.10: Added date options
//
// 2012-10-07 0.11: Requester notes, bug fixes
// 0.12: CSV export
//
// 2012-10-09 0.13: "Block" requesters or specific HITs
//
// 2012-10-10 0.14: Requester Overview, shows summary of all requesters in DB
//
// 2012-10-11 0.15: Blocked HITs are always on bottom of the page
//
// 2012-10-14 0.16: Requester Overview improvements
//
// 2012-10-17 0.17: Bug fixes and error checks
//
// 2012-10-18 0.18: Import HIT data from MTurk Extended HIT Search script
//
// 2012-10-21 0.19: Moved main interface to dashboard, show pending earnings on dashboard,
// summary of all requesters with pending HITs.
//
// 2012-10-23 0.20: Added Turkopticon (http://turkopticon.differenceengines.com/) links to overview pages
// 0.21: Fixed overview pages reward to include only 'Paid' and 'Approved - Pending Payment' HITs.
//
// 2012-10-28 0.22: Limited Auto Update.
// 0.23: Minor improvements
//
// 2012-10-30 0.24: Projected earnings for today
//
// 2012-11-02 0.25: Smarter Auto Update
//
// 2012-11-03 0.26: GUI update
//
// 2012-11-05 0.30: Extra non-amazonian script monkeys
//
// 2012-11-06 0.31: Projected earnings progress bar
//
// 2012-11-08 0.32: Minor GUI fixes to look better on Chrome. Looks like it now works on stable Chrome!
//
// 2012-11-13 0.33: Time limits now work with Requester Overview
//
// 2012-11-15 0.34: Bug/compatibility fixes
//
// 2012-11-18 0.40: Daily Overview, update database to use YYYY-MM-DD date format.
//
// 2012-11-22 0.41: R and T button on HIT preview page. Auto-Approval time.
//
// 2012-11-30 0.42: Changes on MTurk pages. Status page in now on one page!
//
// 2012-12-02 1.0: Added @downloadURL and @updateURL
//
// 2012-12-06 1.1: Requester details.
// Try to fetch few extra days at first update (not showing on status page).
//
// 2012-12-11 1.2: Import HITs from previously exported CSV-files.
// Removed Extended HIT Search import.
//
// 2012-12-13 1.3: Fix CSV-import to put empty string instead if undefined if feedback is empty.
//
// 2012-12-14 1.4: Rewritten database update more properly.
//
// 2012-12-16 1.5: Fixed broken Auto Update (forgot to check that on pervious update).
//
// 2013-02-26 1.6: Fixed IDBTransactionModes for Chrome (note this breaks it for Firefox)
//
// 2013-02-27 1.7: Changed UI bars back to what they used to be.
//
var DAYS_TO_FETCH = [];
var DAYS_TO_FETCH_CHECK;
var HITStorage = {};
var indexedDB = window.indexedDB || window.webkitIndexedDB ||
window.mozIndexedDB;
window.IDBTransaction = window.IDBTransaction || window.webkitIDBTransaction || window.mozIDBTransaction;
window.IDBKeyRange = window.IDBKeyRange || window.webkitIDBKeyRange || window.mozIDBKeyRange;
HITStorage.IDBTransactionModes = { "READ_ONLY": "readonly", "READ_WRITE": "readwrite", "VERSION_CHANGE": "versionchange" };
var IDBKeyRange = window.IDBKeyRange;
HITStorage.indexedDB = {};
HITStorage.indexedDB = {};
HITStorage.indexedDB.db = null;
HITStorage.indexedDB.onerror = function(e) {
console.log(e);
};
var v = 4;
HITStorage.indexedDB.create = function() {
var request = indexedDB.open("HITDB", v);
request.onupgradeneeded = function (e) {
HITStorage.indexedDB.db = e.target.result;
var db = HITStorage.indexedDB.db;
var new_empty_db = false;
if(!db.objectStoreNames.contains("HIT")) {
var store = db.createObjectStore("HIT", { keyPath: "hitId" });
store.createIndex("date", "date", { unique: false });
store.createIndex("requesterName", "requesterName", { unique: false });
store.createIndex("title", "title", { unique: false });
store.createIndex("reward", "reward", { unique: false });
store.createIndex("status", "status", { unique: false });
store.createIndex("requesterId", "requesterId", { unique: false });
new_empty_db = true;
// At first update try to get few extra days that do not show on status page
localStorage['HITDB TRY_EXTRA_DAYS'] = 'YES';
}
if(!db.objectStoreNames.contains("STATS")) {
var store = db.createObjectStore("STATS", { keyPath: "date" });
}
if(!db.objectStoreNames.contains("NOTES")) {
var store = db.createObjectStore("NOTES", { keyPath: "requesterId" });
}
if(!db.objectStoreNames.contains("BLOCKS")) {
var store = db.createObjectStore("BLOCKS", { keyPath: "id", autoIncrement: true });
store.createIndex("requesterId", "requesterId", { unique: false });
}
if (new_empty_db == false)
{
alert("HIT DataBase date format must be upgraded (MMDDYYYY => YYYY-MM-DD)\n" +
"Please don't close or reload this page until it's done.\n" +
"Press OK to start. This shouldn't take long. (few minutes max)" +
"Sorry for the inconvenience.");
HITStorage.update_date_format(true);
}
db.close();
//alert("DataBase upgraded to version " + v + '!');
}
request.onsuccess = function(e) {
HITStorage.indexedDB.db = e.target.result;
var db = HITStorage.indexedDB.db;
db.close();
};
request.onerror = HITStorage.indexedDB.onerror;
}
HITStorage.indexedDB.addHIT = function(hitData) {
// Temporary extra check
if (hitData.date.indexOf('-') < 0)
{
alert('Wrong date format in addHIT()!');
return;
}
var request = indexedDB.open("HITDB", v);
request.onsuccess = function(e) {
HITStorage.indexedDB.db = e.target.result;
var db = HITStorage.indexedDB.db;
var trans = db.transaction(["HIT"], HITStorage.IDBTransactionModes.READ_WRITE);
var store = trans.objectStore("HIT");
var request = store.put(hitData);
request.onsuccess = function(e) {
db.close();
};
request.onerror = function(e) {
console.log("Error Adding: ", e);
};
};
request.onerror = HITStorage.indexedDB.onerror;
};
HITStorage.indexedDB.importHITs = function(hitData) {
var hits = hitData.length;
var label = document.getElementById('status_label');
var request = indexedDB.open("HITDB", v);
request.onsuccess = function(e) {
HITStorage.indexedDB.db = e.target.result;
var db = HITStorage.indexedDB.db;
var trans = db.transaction(["HIT"], HITStorage.IDBTransactionModes.READ_WRITE);
var store = trans.objectStore("HIT");
putNextHIT();
function putNextHIT()
{
if (hitData.length > 0)
{
store.put(hitData.pop()).onsuccess = putNextHIT;
label.innerHTML = progress_bar(((hits-hitData.length)/hits*50), 50, '█', '█', '#7fb448', 'grey') + ' (' + hitData.length + ')';
}
else
{
HITStorage.enable_inputs();
HITStorage.update_status_label('Import done', 'green');
db.close();
}
}
};
request.onerror = HITStorage.indexedDB.onerror;
};
HITStorage.indexedDB.addHITs = function(hitData, day_to_fetch, days_to_update) {
var hits = hitData.length;
if (day_to_fetch)
var label = document.getElementById('status_label');
var request = indexedDB.open("HITDB", v);
request.onsuccess = function(e) {
HITStorage.indexedDB.db = e.target.result;
var db = HITStorage.indexedDB.db;
var trans = db.transaction(["HIT"], HITStorage.IDBTransactionModes.READ_WRITE);
var store = trans.objectStore("HIT");
putNextHIT();
function putNextHIT()
{
if (hitData.length > 0)
{
store.put(hitData.pop()).onsuccess = putNextHIT;
if (day_to_fetch)
label.innerHTML = 'Saving ' + day_to_fetch.date + ': ' + progress_bar(((hits-hitData.length)/hits*40), 40, '█', '█', '#7fb448', 'grey');
}
else
{
// move to next day
if (day_to_fetch)
{
HITStorage.indexedDB.updateHITstats(day_to_fetch);
setTimeout(function() { HITStorage.do_update(days_to_update); }, 2000);
HITStorage.update_status_label('Please wait: script monkeys are taking naps ?', 'red');
}
db.close();
}
}
};
request.onerror = HITStorage.indexedDB.onerror;
};
HITStorage.indexedDB.updateHITstats = function(date)
{
// Temporary extra check
if (date.date.indexOf('-') < 0)
{
alert('Wrong date format in updateHITstats()!');
return;
}
var request = indexedDB.open("HITDB", v);
request.onsuccess = function(e) {
HITStorage.indexedDB.db = e.target.result;
var db = HITStorage.indexedDB.db;
var trans = db.transaction(["STATS"], HITStorage.IDBTransactionModes.READ_WRITE);
var store = trans.objectStore("STATS");
var request = store.put(date);
request.onsuccess = function(e) {
db.close();
};
request.onerror = function(e) {
console.log("Error Adding: ", e);
};
};
request.onerror = HITStorage.indexedDB.onerror;
};
HITStorage.prepare_update_and_check_pending_payments = function()
{
var request = indexedDB.open("HITDB", v);
request.onsuccess = function(e) {
HITStorage.indexedDB.db = e.target.result;
var db = HITStorage.indexedDB.db;
var trans = db.transaction(["HIT"], HITStorage.IDBTransactionModes.READ_ONLY);
var store = trans.objectStore("HIT");
var index = store.index('status');
var range = IDBKeyRange.only('Approved - Pending Payment');
index.openCursor(range).onsuccess = function(event) {
var cursor = event.target.result;
if (cursor && DAYS_TO_FETCH.length > 0)
{
for (var i=0; i<DAYS_TO_FETCH.length; i++)
{
if ( cursor.value.date == DAYS_TO_FETCH[i].date && cursor.value.reward>0 )
{
DAYS_TO_FETCH[i].pending_payments = true;
}
}
cursor.continue();
}
else
{
if (DAYS_TO_FETCH.length>0) {
db.close();
HITStorage.update_status_label('Please wait: script monkeys are planning to fetch relevant status pages', 'red');
setTimeout(function() { HITStorage.prepare_update(); }, 100);
}
else
{
db.close();
HITStorage.update_done();
}
}
};
}
};
// check that number of hits in DB matches what is available
HITStorage.check_update = function()
{
var request = indexedDB.open("HITDB", v);
request.onsuccess = function(e) {
HITStorage.update_status_label('Please wait: checking database', 'red');
HITStorage.indexedDB.db = e.target.result;
var db = HITStorage.indexedDB.db;
var trans = db.transaction(["HIT"], HITStorage.IDBTransactionModes.READ_ONLY);
var store = trans.objectStore("HIT");
var index = store.index('date');
var range = IDBKeyRange.bound(DAYS_TO_FETCH_CHECK[DAYS_TO_FETCH_CHECK.length-1].date, DAYS_TO_FETCH_CHECK[0].date, false, false);
index.count(range).onsuccess = function(event) {
var count = event.target.result;
var submitted_hits = 0;
for (var i=0; i<DAYS_TO_FETCH_CHECK.length; i++)
{
submitted_hits += DAYS_TO_FETCH_CHECK[i].submitted;
}
if (submitted_hits == count)
{
db.close();
HITStorage.update_done();
}
else
{
if (confirm("? ERROR! Number of HITs in DataBase does not match number of HITs available! (" + count + " != " + submitted_hits + ")\n"
+ "Would you like to refetch all status pages now?"))
{
db.close();
DAYS_TO_FETCH = DAYS_TO_FETCH_CHECK.slice(0);
HITStorage.update_status_label('Please wait: new script monkeys are fetching relevant status pages', 'red');
setTimeout(function() { HITStorage.do_update(DAYS_TO_FETCH.length); }, 100);
}
else
{
db.close();
HITStorage.update_done();
}
}
};
}
};
HITStorage.prepare_update = function()
{
var request = indexedDB.open("HITDB", v);
request.onsuccess = function(e) {
HITStorage.indexedDB.db = e.target.result;
var db = HITStorage.indexedDB.db;
var trans = db.transaction(["STATS"], HITStorage.IDBTransactionModes.READ_ONLY);
var store = trans.objectStore("STATS");
var range = IDBKeyRange.bound(DAYS_TO_FETCH[DAYS_TO_FETCH.length-1].date, DAYS_TO_FETCH[0].date, false, false);
store.openCursor(range).onsuccess = function(event) {
var cursor = event.target.result;
if (cursor && DAYS_TO_FETCH.length > 0)
{
for (var i=0; i<DAYS_TO_FETCH.length; i++)
{
if ( cursor.value.date == DAYS_TO_FETCH[i].date
&& cursor.value.submitted == DAYS_TO_FETCH[i].submitted
&& cursor.value.approved == DAYS_TO_FETCH[i].approved
&& cursor.value.rejected == DAYS_TO_FETCH[i].rejected
&& cursor.value.pending == DAYS_TO_FETCH[i].pending)
{
// This day is already in DB and stats match => no need to fetch
// unless there are 'Approved - Pending Payment' HITs
if (DAYS_TO_FETCH[i].pending_payments === undefined || DAYS_TO_FETCH[i].pending_payments == false)
DAYS_TO_FETCH.splice(i,1);
}
}
cursor.continue();
}
else
{
if (DAYS_TO_FETCH.length>0) {
db.close();
setTimeout(function() { HITStorage.do_update(DAYS_TO_FETCH.length); }, 100);
}
else
{
db.close();
HITStorage.update_done();
}
}
};
}
};
HITStorage.indexedDB.term_matches_HIT = function(term, hit)
{
var keys = ['date', 'requesterName', 'title', 'feedback', 'hitId', 'requesterId'];
var re = new RegExp(escapeRegExp(term),"ig");
for (var k in keys)
{
//for testing
if (hit[keys[k]] != null && re.test(hit[keys[k]].trim()))
{
return true;
}
}
return false;
}
function escapeRegExp(str) {
return str.trim().replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
}
HITStorage.indexedDB.matchHIT = function(hit, options)
{
if (options.status == '---' || hit.status.match(options.status))
{
if (options.search_term == '' || HITStorage.indexedDB.term_matches_HIT(options.term, hit))
{
return true;
}
}
return false;
}
function hit_sort_func()
{
return function(a,b) {
if (a.date == b.date) {
if (a.requesterName < b.requesterName)
return -1;
if (a.requesterName > b.requesterName)
return 1;
if (a.title < b.title)
return -1;
if (a.title > b.title)
return 1;
if (a.status < b.status)
return -1;
if (a.status > b.status)
return 1;
}
if (a.date > b.date)
return 1;
if (a.date < b.date)
return -1;
};
}
HITStorage.indexedDB.getHITs = function(options) {
var request = indexedDB.open("HITDB", v);
request.onsuccess = function(e) {
HITStorage.indexedDB.db = e.target.result;
var db = HITStorage.indexedDB.db;
var trans = db.transaction(["HIT"], HITStorage.IDBTransactionModes.READ_ONLY);
var store = trans.objectStore("HIT");
var req;
var results = [];
var index;
var range;
if (options.from_date || options.to_date)
{
if (options.from_date != '' || options.to_date != '')
{
index = store.index('date');
if (options.from_date == options.to_date)
{
range = IDBKeyRange.only(options.from_date);
}
else if (options.from_date != '' && options.to_date != '')
{
range = IDBKeyRange.bound(options.from_date, options.to_date, false, false);
}
else if (options.from_date == '' && options.to_date != '')
{
range = IDBKeyRange.upperBound(options.to_date, false);
}
else
{
range = IDBKeyRange.lowerBound(options.from_date, false);
}
req = index.openCursor(range);
}
}
else if (options.index && options.index != '')
{
index = store.index(options.index);
range = IDBKeyRange.only(options.term);
req = index.openCursor(range);
}
else if (options.status == 'Rejected' || options.status == 'Pending Approval'
|| options.status == 'Approved' || options.status == 'Paid')
{
var s = (options.status == 'Approved')? 'Approved - Pending Payment' : options.status;
options.index = 'status';
index = store.index(options.index);
range = IDBKeyRange.only(s);
req = index.openCursor(range);
}
else
{
req = store.openCursor();
}
req.onsuccess = function(event) {
var cursor = event.target.result;
if (cursor) {
if (HITStorage.indexedDB.matchHIT(cursor.value, options))
results.push(cursor.value);
cursor.continue();
}
else {
results.sort(hit_sort_func());
if (options.export_csv && options.export_csv == true)
HITStorage.export_csv(results);
else
HITStorage.show_results(results);
if (options.donut == '---')
document.getElementById('container').style.display = 'none';
else if (options.donut != '')
HITStorage.prepare_donut(results, options.donut);
}
db.close();
};
};
request.onerror = HITStorage.indexedDB.onerror;
};
//
// Show summary of all requesters
//
HITStorage.indexedDB.requesterOverview = function(options) {
var request = indexedDB.open("HITDB", v);
request.onsuccess = function(e) {
HITStorage.indexedDB.db = e.target.result;
var db = HITStorage.indexedDB.db;
var trans = db.transaction(["HIT"], HITStorage.IDBTransactionModes.READ_ONLY);
var store = trans.objectStore("HIT");
var index;
var req;
// [ requesterId, requesterName, sum(hits), sum(rewards), rejected, pending ]
var results = [];
var tmp_results = {};
if (options.from_date || options.to_date)
{
if (options.from_date != '' || options.to_date != '')
{
index = store.index('date');
if (options.from_date == options.to_date)
{
range = IDBKeyRange.only(options.from_date);
}
else if (options.from_date != '' && options.to_date != '')
{
range = IDBKeyRange.bound(options.from_date, options.to_date, false, false);
}
else if (options.from_date == '' && options.to_date != '')
{
range = IDBKeyRange.upperBound(options.to_date, false);
}
else
{
range = IDBKeyRange.lowerBound(options.from_date, false);
}
req = index.openCursor(range);
}
req.onsuccess = function(event) {
var cursor = event.target.result;
if (cursor) {
var hit = cursor.value;
var rejected = (hit.status == 'Rejected') ? 1 : 0;
var pending = (hit.status.match(/Approved|Paid|Rejected/) == null) ? 1 : 0;
var reward = (pending>0 || rejected>0 )? 0: hit.reward;
if (tmp_results[hit.requesterId] === undefined)
{
tmp_results[hit.requesterId] = [];
tmp_results[hit.requesterId][0] = hit.requesterId;
tmp_results[hit.requesterId][1] = hit.requesterName;
tmp_results[hit.requesterId][2] = 1;
tmp_results[hit.requesterId][3] = reward;
tmp_results[hit.requesterId][4] = rejected;
tmp_results[hit.requesterId][5] = pending;
}
else
{
tmp_results[hit.requesterId][1] = hit.requesterName;
tmp_results[hit.requesterId][2] += 1;
tmp_results[hit.requesterId][3] += reward;
tmp_results[hit.requesterId][4] += rejected;
tmp_results[hit.requesterId][5] += pending;
}
cursor.continue();
}
else {
for (var key in tmp_results) {
results.push(tmp_results[key]);
}
// sort by total reward
results.sort(function(a,b) { return b[3]-a[3]; });
if (options.export_csv == true)
HITStorage.show_requester_overview_csv(results);
else
HITStorage.show_requester_overview(results, '(' + options.from_date + '–' + options.to_date + ')');
HITStorage.update_status_label('Script monkeys are ready', 'green');
setTimeout( function() { HITStorage.update_status_label("Search powered by non-amazonian script monkeys"); }, 3000);
HITStorage.enable_inputs();
}
db.close();
};
}
else {
index = store.index('requesterId');
req = index.openCursor();
req.onsuccess = function(event) {
var cursor = event.target.result;
if (cursor) {
var hit = cursor.value;
var rejected = (hit.status == 'Rejected') ? 1 : 0;
var pending = (hit.status.match(/Approved|Paid|Rejected/) == null) ? 1 : 0;
var reward = (pending>0 || rejected>0 )? 0: hit.reward;
if (results.length == 0)
{
results.push([hit.requesterId, hit.requesterName, 1, reward, rejected, pending]);
}
else if (results[0][0] == hit.requesterId)
{
results[0][2] += 1;
results[0][3] += reward;
results[0][4] += rejected;
results[0][5] += pending;
}
else
{
results.unshift([hit.requesterId, hit.requesterName, 1, reward, rejected, pending]);
}
cursor.continue();
}
else {
// sort by total reward
results.sort(function(a,b) { return b[3]-a[3]; });
if (options.export_csv == true)
HITStorage.show_requester_overview_csv(results);
else
HITStorage.show_requester_overview(results);
HITStorage.update_status_label('Script monkeys are ready', 'green');
setTimeout( function() { HITStorage.update_status_label("Search powered by non-amazonian script monkeys"); }, 3000);
HITStorage.enable_inputs();
}
db.close();
};
}
};
request.onerror = HITStorage.indexedDB.onerror;
};
//
// Show summary of one requester
//
HITStorage.indexedDB.showRequester = function(requesterId) {
var request = indexedDB.open("HITDB", v);
request.onsuccess = function(e) {
HITStorage.indexedDB.db = e.target.result;
var db = HITStorage.indexedDB.db;
var trans = db.transaction(["HIT"], HITStorage.IDBTransactionModes.READ_ONLY);
var store = trans.objectStore("HIT");
var index;
var results = [];
index = store.index('requesterId');
var range = IDBKeyRange.only(requesterId);
index.openCursor(range).onsuccess = function(event) {
var cursor = event.target.result;
if (cursor) {
results.push(cursor.value);
cursor.continue();
}
else {
results.sort(function(a,b)
{
if (a.date > b.date)
return -1;
if (a.date < b.date)
return 1;
return 0;
});
HITStorage.show_requester(results);
HITStorage.update_status_label('Script monkeys are ready', 'green');
setTimeout( function() { HITStorage.update_status_label("Search powered by non-amazonian script monkeys"); }, 3000);
HITStorage.enable_inputs();
}
db.close();
};
};
request.onerror = HITStorage.indexedDB.onerror;
};
// Show summary of pending HITs
HITStorage.indexedDB.pendingOverview = function(options) {
var request = indexedDB.open("HITDB", v);
request.onsuccess = function(e) {
HITStorage.indexedDB.db = e.target.result;
var db = HITStorage.indexedDB.db;
var trans = db.transaction(["HIT"], HITStorage.IDBTransactionModes.READ_ONLY);
var store = trans.objectStore("HIT");
var index;
var req;
// [ requesterId, requesterName, sum(pendings), sum(rewards) ]
var results = [];
var tmp_results = {};
index = store.index('status');
range = IDBKeyRange.only('Pending Approval');
index.openCursor(range).onsuccess = function(event) {
var cursor = event.target.result;
if (cursor) {
var hit = cursor.value;
console.log(hit);
if (tmp_results[hit.requesterId] === undefined)
{
tmp_results[hit.requesterId] = [];
tmp_results[hit.requesterId][0] = hit.requesterId;
tmp_results[hit.requesterId][1] = hit.requesterName;
tmp_results[hit.requesterId][2] = 1;
tmp_results[hit.requesterId][3] = hit.reward;
}
else
{
tmp_results[hit.requesterId][1] = hit.requesterName;
tmp_results[hit.requesterId][2] += 1;
tmp_results[hit.requesterId][3] += hit.reward;
}
cursor.continue();
}
else {
for (var key in tmp_results) {
results.push(tmp_results[key]);
}
// sort by pending hits
results.sort(function(a,b) { return b[2]-a[2]; });
if (options.export_csv == true)
HITStorage.show_pending_overview_csv(results);
else
HITStorage.show_pending_overview(results);
HITStorage.update_status_label('Script monkeys are ready', 'green');
setTimeout( function() { HITStorage.update_status_label("Search powered by non-amazonian script monkeys"); }, 3000);
HITStorage.enable_inputs();
}
db.close();
};
};
request.onerror = HITStorage.indexedDB.onerror;
};
// Show summary of daily stats
HITStorage.indexedDB.statusOverview = function(options) {
var request = indexedDB.open("HITDB", v);
request.onsuccess = function(e) {
HITStorage.indexedDB.db = e.target.result;
var db = HITStorage.indexedDB.db;
var trans = db.transaction(["STATS"], HITStorage.IDBTransactionModes.READ_ONLY);
var store = trans.objectStore("STATS");
var req;
var results = [];
if (options.from_date || options.to_date)
{
if (options.from_date != '' || options.to_date != '')
{
if (options.from_date == options.to_date)
{
range = IDBKeyRange.only(options.from_date);
}
else if (options.from_date != '' && options.to_date != '')
{
range = IDBKeyRange.bound(options.from_date, options.to_date, false, false);
}
else if (options.from_date == '' && options.to_date != '')
{
range = IDBKeyRange.upperBound(options.to_date, false);
}
else
{
range = IDBKeyRange.lowerBound(options.from_date, false);
}
req = store.openCursor(range);
}
}
else
{
req = store.openCursor();
}
req.onsuccess = function(event) {
var cursor = event.target.result;
if (cursor) {
if (cursor.value.submitted > 0)
results.push(cursor.value);
cursor.continue();
}
else {
if (options.export_csv == true)
HITStorage.show_status_overview_csv(results);
else
HITStorage.show_status_overview(results, '(' + options.from_date + '–' + options.to_date + ')');
HITStorage.update_status_label('Script monkeys are ready', 'green');
setTimeout( function() { HITStorage.update_status_label("Search powered by non-amazonian script monkeys"); }, 3000);
HITStorage.enable_inputs();
}
db.close();
};
};
request.onerror = HITStorage.indexedDB.onerror;
};
HITStorage.indexedDB.getHIT = function(id) {
var request = indexedDB.open("HITDB", v);
request.onsuccess = function(e) {
HITStorage.indexedDB.db = e.target.result;
var db = HITStorage.indexedDB.db;
var trans = db.transaction(["HIT"], HITStorage.IDBTransactionModes.READ_ONLY);
var store = trans.objectStore("HIT");
var request = store.get(id);
request.onsuccess = function(e) {
db.close();
showDetails(e.target.result.note);
};
request.onerror = function(e) {
console.log("Error Getting: ", e);
};
};
request.onerror = HITStorage.indexedDB.onerror;
};
HITStorage.indexedDB.addNote = function(id, note) {
var request = indexedDB.open("HITDB", v);
request.onsuccess = function(e) {
HITStorage.indexedDB.db = e.target.result;
var db = HITStorage.indexedDB.db;
var trans = db.transaction(["NOTES"], HITStorage.IDBTransactionModes.READ_WRITE);
var store = trans.objectStore("NOTES");
var request;
if (note == '')
request = store.delete(id);
else
request = store.put({requesterId: id, note: note});
request.onsuccess = function(e) {
db.close();
};
request.onerror = function(e) {
console.log("Error Adding: ", e);
};
};
request.onerror = HITStorage.indexedDB.onerror;
};
HITStorage.indexedDB.blockHITS = function(requesterId, title, hitElement, titleElement) {
var request = indexedDB.open("HITDB", v);
request.onsuccess = function(e) {
HITStorage.indexedDB.db = e.target.result;
var db = HITStorage.indexedDB.db;
if (!db.objectStoreNames.contains("BLOCKS"))
{
db.close();
return;
}
var trans = db.transaction(["BLOCKS"], HITStorage.IDBTransactionModes.READ_ONLY);
var store = trans.objectStore("BLOCKS");
var index = store.index("requesterId");
var range = IDBKeyRange.only(requesterId);
index.openCursor(range).onsuccess = function(event) {
var cursor = event.target.result;
if (cursor && cursor.value.re)
{
if (cursor.value.re.test(title))
{
hitElement.style.display = 'none';
titleElement.addEventListener("click", unblock_func(requesterId, title));
titleElement.style.fontSize = 'small';
// move blocked hits to the bottom
var table = hitElement.parentNode.parentNode.parentNode.parentNode.parentNode;
var hit = hitElement.parentNode.parentNode.parentNode.parentNode;
table.removeChild(hit);
table.appendChild(hit);
}
cursor.continue();
}
else
{
db.close();
}
};
};
request.onerror = HITStorage.indexedDB.onerror;
};
HITStorage.indexedDB.addBlock = function(requesterId, re) {
var request = indexedDB.open("HITDB", v);
request.onsuccess = function(e) {
HITStorage.indexedDB.db = e.target.result;
var db = HITStorage.indexedDB.db;
var trans = db.transaction(["BLOCKS"], HITStorage.IDBTransactionModes.READ_WRITE);
var store = trans.objectStore("BLOCKS");
var request;
request = store.put({requesterId: requesterId, re: re});
request.onsuccess = function(e) {
db.close();
};
};
request.onerror = HITStorage.indexedDB.onerror;
};
// Removes all blocks for requesterId, where RE matches this HIT title
HITStorage.indexedDB.removeBlocks = function(requesterId, title) {
var request = indexedDB.open("HITDB", v);
request.onsuccess = function(e) {
HITStorage.indexedDB.db = e.target.result;
var db = HITStorage.indexedDB.db;
if (!db.objectStoreNames.contains("BLOCKS"))
{
db.close();
return;
}
var trans = db.transaction(["BLOCKS"], HITStorage.IDBTransactionModes.READ_WRITE);
var store = trans.objectStore("BLOCKS");
var index = store.index("requesterId");
var range = IDBKeyRange.only(requesterId);
index.openCursor(range).onsuccess = function(event)
{
var cursor = event.target.result;
if (cursor)
{
if (cursor.value.re.test(title))
store.delete(cursor.value.id);
db.close();
}
};
};
request.onerror = HITStorage.indexedDB.onerror;
};
HITStorage.indexedDB.updateNoteButton = function(id, label) {
var request = indexedDB.open("HITDB", v);
request.onsuccess = function(e) {
HITStorage.indexedDB.db = e.target.result;
var db = HITStorage.indexedDB.db;
if (!db.objectStoreNames.contains("NOTES"))
{
label.title = 'Update HIT database on statusdetail page to use this feature';
db.close();
return;
}
var trans = db.transaction(["NOTES"], HITStorage.IDBTransactionModes.READ_ONLY);
var store = trans.objectStore("NOTES");
store.get(id).onsuccess = function(event)
{
if (event.target.result === undefined)
{
label.textContent = '';
}
else
{
var note = event.target.result.note;
label.textContent = note;
label.style.border = '1px dotted';
if (note.indexOf('!') >= 0)
label.style.color = 'red';
else
label.style.color = 'black';
}
db.close();
};
};
request.onerror = HITStorage.indexedDB.onerror;
};
HITStorage.indexedDB.colorRequesterButton = function(id, button) {
var request = indexedDB.open("HITDB", v);
request.onsuccess = function(e) {
HITStorage.indexedDB.db = e.target.result;
var db = HITStorage.indexedDB.db;
if (!db.objectStoreNames.contains("HIT"))
{
button.title = 'Update HIT database on statusdetail page to use this feature';
db.close();
return;
}
var trans = db.transaction(["HIT"], HITStorage.IDBTransactionModes.READ_ONLY);
var store = trans.objectStore("HIT");
var index = store.index("requesterId");
index.get(id).onsuccess = function(event)
{
if (event.target.result === undefined)
{
button.style.backgroundColor = 'pink';
}
else
{
button.style.backgroundColor = 'lightgreen';
button.style.fontWeight = 'bold';
}
db.close();
};
};
request.onerror = HITStorage.indexedDB.onerror;
};
HITStorage.indexedDB.colorTitleButton = function(title, button) {
var request = indexedDB.open("HITDB", v);
request.onsuccess = function(e) {
HITStorage.indexedDB.db = e.target.result;
var db = HITStorage.indexedDB.db;
if (!db.objectStoreNames.contains("HIT"))
{
button.title = 'Update HIT database on statusdetail page to use this feature';
db.close();
return;
}
var trans = db.transaction(["HIT"], HITStorage.IDBTransactionModes.READ_ONLY);
var store = trans.objectStore("HIT");
var index = store.index("title");
index.get(title).onsuccess = function(event)
{
if (event.target.result === undefined)
{
button.style.backgroundColor = 'pink';
}
else
{
button.style.backgroundColor = 'lightgreen';
button.style.fontWeight = 'bold';
}
db.close();
};
};
request.onerror = HITStorage.indexedDB.onerror;
};
HITStorage.indexedDB.deleteDB = function () {
var deleteRequest = indexedDB.deleteDatabase("HITDB");
deleteRequest.onsuccess = function (e)
{
alert("deleted");
}
deleteRequest.onblocked = function (e)
{
alert("blocked");
}
deleteRequest.onerror = HITStorage.indexedDB.onerror;
}
HITStorage.indexedDB.get_pending_approvals = function() {
var element = document.getElementById('pending_earnings_value');
var header_element = document.getElementById('pending_earnings_header');
if (element == null)
return;
var request = indexedDB.open("HITDB", v);
request.onsuccess = function(e) {
HITStorage.indexedDB.db = e.target.result;
var db = HITStorage.indexedDB.db;
var trans = db.transaction(["HIT"], HITStorage.IDBTransactionModes.READ_ONLY);
var store = trans.objectStore("HIT");
var result = 0;
var index;
var range;
index = store.index('status');
range = IDBKeyRange.only('Pending Approval');
index.openCursor(range).onsuccess = function(event) {
var cursor = event.target.result;
if (cursor) {
result += cursor.value.reward;
cursor.continue();
}
else {
element.textContent = '$' + result.toFixed(2);
if (header_element != null)
header_element.textContent = 'Pending earnings (HITDB updated: ' + localStorage['HITDB UPDATED']+ ')';
}
db.close();
};
};
request.onerror = HITStorage.indexedDB.onerror;
};
HITStorage.indexedDB.get_pending_payments = function() {
var element = document.getElementById('pending_earnings_value');
if (element == null)
return;
var request = indexedDB.open("HITDB", v);
request.onsuccess = function(e) {
HITStorage.indexedDB.db = e.target.result;
var db = HITStorage.indexedDB.db;
var trans = db.transaction(["HIT"], HITStorage.IDBTransactionModes.READ_ONLY);
var store = trans.objectStore("HIT");
var result = 0;
var index;
var range;
index = store.index('status');
range = IDBKeyRange.only('Approved - Pending Payment');
index.openCursor(range).onsuccess = function(event) {
var cursor = event.target.result;
if (cursor) {
result += cursor.value.reward;
cursor.continue();
}
else {
element.title = 'Approved - Pending Payment: $' + result.toFixed(2);
}
}
db.close();
};
request.onerror = HITStorage.indexedDB.onerror;
};
HITStorage.indexedDB.get_todays_projected_earnings = function(date) {
var element = document.getElementById('projected_earnings_value');
if (element == null)
return;
var request = indexedDB.open("HITDB", v);
request.onsuccess = function(e) {
HITStorage.indexedDB.db = e.target.result;
var db = HITStorage.indexedDB.db;
var trans = db.transaction(["HIT"], HITStorage.IDBTransactionModes.READ_ONLY);
var store = trans.objectStore("HIT");
var result = 0;
var rejected = 0;
var index;
var range;
index = store.index('date');
range = IDBKeyRange.only(date);
index.openCursor(range).onsuccess = function(event) {
var cursor = event.target.result;
if (cursor) {
if (cursor.value.status == 'Rejected')
rejected += cursor.value.reward;
else
result += cursor.value.reward;
cursor.continue();
}
else {
element.textContent = '$' + result.toFixed(2);
element.title = '$' + rejected.toFixed(2) + ' rejected';
if (localStorage['TODAYS TARGET'] !== undefined)
{
var target = parseFloat(localStorage['TODAYS TARGET']).toFixed(2);
var my_target = document.getElementById('my_target');
var progress = Math.floor(result/target*40);
if (progress > 40)
progress = 40;
my_target.innerHTML = progress_bar(progress, 40, '█', '█', '#7fb448', 'grey') + ' ' +
((result>target)? '+' : '') + (result-target).toFixed(2);
my_target.style.fontSize = '9px';
}
}
}
db.close();
};
request.onerror = HITStorage.indexedDB.onerror;
};
// Update database date format from MMDDYYYY to YYYY-MM-DD
// Shouldn't break anything even if used on already updated db
HITStorage.update_date_format = function(verbose)
{
var request = indexedDB.open("HITDB", v);
request.onsuccess = function(e) {
HITStorage.indexedDB.db = e.target.result;
var db = HITStorage.indexedDB.db;
var trans = db.transaction(["HIT"], HITStorage.IDBTransactionModes.READ_WRITE);
var store = trans.objectStore("HIT");
store.openCursor().onsuccess = function(event) {
var cursor = event.target.result;
if (cursor)
{
if (cursor.value.date.indexOf('-') < 0)
{
var i = cursor.value;
i.date = convert_date(i.date);
i.requesterName = i.requesterName.trim();
i.title = i.title.trim();
cursor.update(i);
}
cursor.continue();
}
else
{
db.close();
HITStorage.update_stats_date_format(verbose);
}
};
}
}
HITStorage.update_stats_date_format = function(verbose)
{
var request = indexedDB.open("HITDB", v);
request.onsuccess = function(e) {
HITStorage.indexedDB.db = e.target.result;
var db = HITStorage.indexedDB.db;
var trans = db.transaction(["STATS"], HITStorage.IDBTransactionModes.READ_WRITE);
var store = trans.objectStore("STATS");
store.openCursor().onsuccess = function(event) {
var cursor = event.target.result;
if (cursor)
{
if (cursor.value.date.indexOf('-') < 0)
{
var i = cursor.value;
i.date = convert_date(i.date);
cursor.delete();
store.put(i);
}
cursor.continue();
}
else
{
// DB should be fully updated
db.close();
if (verbose == true)
alert('Date conversion done.');
}
};
}
};
/* ------------------------------------------------------------- */
HITStorage.prepare_donut = function (donutData, type)
{
if (type == '---')
return;
var countHits = true;
if (type.match('REWARDS'))
countHits = false;
var tmpData = {};
var topRequesters = [];
var topHits = [];
var sum = 0;
for (var i=0; i < donutData.length; i++) {
var requesterName = donutData[i].requesterName.trim() + " (" + donutData[i].requesterId + ")";
var hitTitle = donutData[i].title;
var hitReward = donutData[i].reward;
sum += (countHits) ? 1 : hitReward;
if (tmpData[requesterName]) {
tmpData[requesterName]['HITS'] += (countHits) ? 1 : hitReward;
}
else {
tmpData[requesterName] = {};
tmpData[requesterName]['HITS'] = (countHits) ? 1 : hitReward;
}
if (tmpData[requesterName][hitTitle])
tmpData[requesterName][hitTitle] += (countHits) ? 1 : hitReward;
else
tmpData[requesterName][hitTitle] = (countHits) ? 1 : hitReward;
}
for (var key in tmpData) {
topRequesters.push({name: key, y: tmpData[key]['HITS']});
}
topRequesters.sort(function(a,b){return b.y-a.y});
var colors = Highcharts.getOptions().colors;
for (var i=0; i<topRequesters.length; i++) {
var tmpHits = [];
topRequesters[i].color = colors[i];
for (var key2 in tmpData[topRequesters[i].name]) {
if (key2 != 'HITS') {
tmpHits.push({name: key2, y: tmpData[topRequesters[i].name][key2], color: colors[i]});
}
}
tmpHits.sort(function(a,b){return b.y-a.y});
for (var j=0; j<tmpHits.length ; j++) {
var brightness = 0.2 - (j / tmpHits.length) / 5;
tmpHits[j].color = Highcharts.Color(colors[i]).brighten(brightness).get();
}
topHits = topHits.concat(tmpHits);
}
document.getElementById('container').style.display = 'block';
chart = new Highcharts.Chart({
chart: {
renderTo: 'container',
type: 'pie'
},
title: {
text: 'Requesters and HITs matching your latest search'
},
yAxis: {
title: {
text: ''
}
},
plotOptions: {
pie: {
shadow: false,
dataLabels: { enabled: true}
}
},
tooltip: {
animation: false,
valuePrefix: (countHits)? '' : '$',
valueSuffix: (countHits)? ' HITs' : '',
valueDecimals: (countHits)? 0 : 2,
pointFormat: (countHits)? '<span style="color:{series.color}">{series.name}</span>: <b>{point.y}</b> (of all ' + sum + ' HITs)<br/>' :
'<span style="color:{series.color}">{series.name}</span>: <b>{point.y}</b> (of all $' + sum.toFixed(2) + ')<br/>'
},
series: [{
name: 'Requesters',
data: topRequesters,
size: '60%',
dataLabels: {
formatter: function() {
if (countHits) {
return this.y/sum >= 0.20 ? this.point.name: null;
}
else {
return this.y/sum >= 0.20 ? this.point.name : null;
}
},
color: 'black',
distance: -10
}
}, {
name: 'HITs',
data: topHits,
innerSize: '60%',
dataLabels: {
formatter: function() {
if (countHits) {
return this.y/sum > 0.05 ? this.point.name : null;
}
else {
return this.y/sum > 0.05 ? this.point.name : null;
}
},
color: 'black',
}
}]
});
}
// Stolen from Today's Projected Earnings (http://userscripts.org/scripts/show/95331)
HITStorage.getHTTPObject = function()
{
if (typeof XMLHttpRequest != 'undefined')
{
return new XMLHttpRequest();
}
try
{
return new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e)
{
try
{
return new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e) {}
}
return false;
}
// Stolen from Today's Projected Earnings (http://userscripts.org/scripts/show/95331)
// date format MMDDYYYY!
HITStorage.process_page = function(link, date, hitData)
{
var page = HITStorage.getHTTPObject();
page.open("GET", link, false);
page.send(null);
return HITStorage.parse_data(page.responseText, date, hitData);
}
// Partly stolen from Today's Projected Earnings (http://userscripts.org/scripts/show/95331)
// date format MMDDYYYY!
HITStorage.parse_data = function(page_text, date, hitData)
{
var index = 0;
var index2 = 0;
var page_html = document.createElement('div');
page_html.innerHTML = page_text;
var requesters = page_html.getElementsByClassName('statusdetailRequesterColumnValue');
var titles = page_html.getElementsByClassName('statusdetailTitleColumnValue');
var amounts = page_html.getElementsByClassName('statusdetailAmountColumnValue');
var statuses = page_html.getElementsByClassName('statusdetailStatusColumnValue');
var feedbacks = page_html.getElementsByClassName('statusdetailRequesterFeedbackColumnValue');
var requesterName;
var hitTitle;
var hitReward;
var hitStatus;
var requesterId;
var hitId;
for(var k = 0; k < amounts.length; k++)
{
requesterName = requesters[k].textContent;
requesterLink = requesters[k].childNodes[1].href;
hitTitle = titles[k].textContent;
index = amounts[k].innerHTML.indexOf('$');
hitReward = parseFloat(amounts[k].innerHTML.substring(index+1));
hitStatus = statuses[k].innerHTML;
hitFeedback = feedbacks[k].textContent;
requesterId = getQueryVariable(requesterLink,"requesterId");
subject = getQueryVariable(requesterLink,"subject");
subject = subject.split("+");
hitId = subject[subject.length-1];
var hit = {
hitId : hitId,
date : convert_date(date),
requesterName : requesterName.trim(),
requesterLink : requesterLink.trim(),
title : hitTitle.trim(),
reward : hitReward,
status : hitStatus,
feedback : hitFeedback.trim(),
requesterId : requesterId
};
//HITStorage.indexedDB.addHIT(hitData);
hitData.push(hit);
}
return amounts.length;
}
//Used to simplify getting requester ID's and such
function getQueryVariable(url,variable)
{
var query = url.substring(1);
var vars = query.split("?")[1].split("&");
for (var i=0;i<vars.length;i++)
{
var pair = vars[i].split("=");
if(pair[0] == variable)
{
return pair[1];
}
}
return(false);
}
// Returns available days (YYYY-MM-DD)
HITStorage.getAllAvailableDays = function(try_extra_days)
{
var days = [];
var page = HITStorage.getHTTPObject();
page.open("GET", 'https://www.mturk.com/mturk/status', false);
page.send(null);
var page_html = document.createElement('div');
page_html.innerHTML = page.responseText;
var dateElements = page_html.getElementsByClassName('statusDateColumnValue');
var submittedElements = page_html.getElementsByClassName('statusSubmittedColumnValue');
var approvedElements = page_html.getElementsByClassName('statusApprovedColumnValue');
var rejectedElements = page_html.getElementsByClassName('statusRejectedColumnValue');
var pendingElements = page_html.getElementsByClassName('statusPendingColumnValue');
var earningsElements = page_html.getElementsByClassName('statusEarningsColumnValue');
for (var i=0; i<dateElements.length; i++)
{
var date = dateElements[i].childNodes[1].href.substr(53);
date = convert_date(date);
days.push( { date: date,
submitted: parseInt(submittedElements[i].textContent),
approved : parseInt(approvedElements[i].textContent),
rejected : parseInt(rejectedElements[i].textContent),
pending : parseInt(pendingElements[i].textContent),
earnings : parseFloat(earningsElements[i].textContent.slice(1)) });
}
if (try_extra_days > 0)
{
var date = days[days.length-1].date;
var d = new Date();
d.setFullYear(parseInt(date.substr(0,4)), parseInt(date.substr(5,2))-1, parseInt(date.substr(8,2)));
for (var i=0; i<try_extra_days; i++)
{
d.setDate(d.getDate()-1);
var month = '0' + (d.getMonth() + 1);
var day = '0' + d.getDate();
if (month.length > 2)
month = month.substr(1);
if (day.length > 2)
day = day.substr(1);
date = '' + d.getFullYear() + '-' + month + '-' + day;
days.push( { date: date,
submitted: -1,
approved : -1,
rejected : -1,
pending : -1,
earnings : -1 } );
}
}
return days;
}
HITStorage.getLatestHITs = function()
{
if (localStorage['HITDB AUTO UPDATE'] === undefined || localStorage['HITDB AUTO UPDATE'] == 'OFF')
return;
if (localStorage['HITDB TIMESTAMP'] !== undefined)
{
if (new Date().getTime() < new Date(parseInt(localStorage['HITDB TIMESTAMP'])).getTime() + 90000)
{
return;
}
}
localStorage['HITDB TIMESTAMP'] = new Date().getTime();
var auto_button = document.getElementById('auto_button');
var page = HITStorage.getHTTPObject();
page.open("GET", 'https://www.mturk.com/mturk/status', false);
page.send(null);
auto_button.textContent += ' +';
var page_html = document.createElement('div');
page_html.innerHTML = page.responseText;
var dateElements = page_html.getElementsByClassName('statusDateColumnValue');
var submittedElements = page_html.getElementsByClassName('statusSubmittedColumnValue');
var approvedElements = page_html.getElementsByClassName('statusApprovedColumnValue');
var rejectedElements = page_html.getElementsByClassName('statusRejectedColumnValue');
var pendingElements = page_html.getElementsByClassName('statusPendingColumnValue');
var earningsElements = page_html.getElementsByClassName('statusEarningsColumnValue');
if (dateElements[0].childNodes[1].textContent.trim() != 'Today')
return;
var url = dateElements[0].childNodes[1].href;
var date = url.substr(53); // keep MMDDYYYY
var submitted = parseInt(submittedElements[0].textContent);
//var approved = parseInt(approvedElements[0].textContent);
//var rejected = parseInt(rejectedElements[0].textContent);
//var pending = parseInt(pendingElements[0].textContent);
//var earnings = parseFloat(earningsElements[0].textContent.slice(1));
var pages_done = null;
if (localStorage['HITDB AUTOUPDATE PAGES'] !== undefined)
{
pages_done = JSON.parse(localStorage['HITDB AUTOUPDATE PAGES']);
}
if (pages_done == null || pages_done.date != date)
pages_done = {date: date};
var new_hits = 0;
var page = 1 + Math.floor(submitted/25);
page = (page<1) ? 1 : page;
var hitData = [];
if (submitted != pages_done.submitted)
{
url = "https://www.mturk.com/mturk/statusdetail?sortType=All&pageNumber=" + page + "&encodedDate=" + date;
HITStorage.process_page(url, date, hitData);
new_hits += submitted - pages_done.submitted;
pages_done.submitted = submitted;
localStorage['HITDB AUTOUPDATE PAGES'] = JSON.stringify(pages_done);
auto_button.textContent += '+';
}
if (page > 1)
{
extra_page = page-1;
while (extra_page >= 1)
{
if (pages_done[extra_page] != true)
{
url = "https://www.mturk.com/mturk/statusdetail?sortType=All&pageNumber=" + extra_page + "&encodedDate=" + date;
if (HITStorage.process_page(url, date, hitData) == 25)
{
pages_done[extra_page] = true;
localStorage['HITDB AUTOUPDATE PAGES'] = JSON.stringify(pages_done);
auto_button.textContent += '+';
}
break;
}
extra_page -= 1;
}
}
HITStorage.indexedDB.addHITs(hitData);
}
// Gets status details for given date (MMDDYYYY)
// Collects all HITs for given date to hitData array
HITStorage.getHITData = function(day_to_fetch, hitData, page, days_to_update)
{
var dataDate = convert_iso_date(day_to_fetch.date);
page = page || 1;
detailed_status_page_link = "https://www.mturk.com/mturk/statusdetail?sortType=All&pageNumber=" + page + "&encodedDate=" + dataDate;
if (HITStorage.process_page(detailed_status_page_link, dataDate, hitData) == 0)
{
if (day_to_fetch.submitted == -1 || hitData.length == day_to_fetch.submitted)
{
setTimeout(function(){ HITStorage.indexedDB.addHITs(hitData, day_to_fetch, days_to_update); }, 1000);
}
else
{
alert("There was an error while fetching HITs for date: " + day_to_fetch.date + ".\n" +
"Script monkeys expected " + day_to_fetch.submitted + " bananas, but got " + hitData.length + "! ?");
HITStorage.update_done();
}
}
else
{
HITStorage.update_status_label('Please wait: script monkeys are fetching status pages (' +
day_to_fetch.date + ', page ' + page + ')', 'red');
setTimeout(function(){ HITStorage.getHITData(day_to_fetch, hitData, page+1, days_to_update); }, 1000);
}
}
HITStorage.formatTime = function(msec)
{
if (isNaN(msec))
return "-";
var seconds = Math.floor(msec / 1000) % 60;
var minutes = Math.floor((msec / 1000) / 60) % 60;
var hours = Math.floor(((msec / 1000) / 60) / 60) % 24;
var days = Math.floor(((msec / 1000) / 60) / 60 / 24);
if (hours > 0)
seconds = "";
else
seconds = "" + seconds + "s";
minutes == 0 ? minutes = "" : minutes = "" + minutes + "m ";
hours == 0 ? hours = "" : hours = "" + hours + "h ";
if (days > 0)
return '' + days + ' day' + ((days>1)? 's' : ' ') + hours;
return hours + minutes + seconds;
}
HITStorage.update_status_label = function(new_status, color)
{
var label = document.getElementById('status_label');
label.innerHTML = new_status;
label.style.color = color || 'black';
}
// validate input field dates
// Accept YYYY-MM-DD
HITStorage.validate_date = function(input)
{
date = input.value;
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;
}
HITStorage.validate_dates = function()
{
from = document.getElementById('from_date');
to = document.getElementById('to_date');
if (HITStorage.validate_date(from) && HITStorage.validate_date(to))
{
if (from.value > to.value && to.value != '')
{
alert('Invalid date!');
return false;
}
return true;
}
alert('Invalid date!');
return false;
}
HITStorage.start_search = function()
{
if (HITStorage.validate_dates() == false)
return;
HITStorage.update_status_label('Using local HIT database', 'green');
var options = {};
options.term = document.getElementById('search_term').value;
options.status = document.getElementById('status_select').value;
options.donut = document.getElementById('donut_select').value;
options.from_date = document.getElementById('from_date').value;
options.to_date = document.getElementById('to_date').value;
options.export_csv = document.getElementById('export_csv').checked;
HITStorage.disable_inputs();
setTimeout(function(){ HITStorage.do_search(options); }, 500);
}
HITStorage.disable_inputs = function()
{
document.getElementById('delete_button').disabled = true;
document.getElementById('search_button').disabled = true;
document.getElementById('update_button').disabled = true;
document.getElementById('overview_button').disabled = true;
document.getElementById('import_button').disabled = true;
document.getElementById('pending_button').disabled = true;
document.getElementById('status_button').disabled = true;
document.getElementById('from_date').disabled = true;
document.getElementById('to_date').disabled = true;
document.getElementById('search_term').disabled = true;
document.getElementById('status_select').disabled = true;
document.getElementById('donut_select').disabled = true;
}
HITStorage.enable_inputs = function()
{
document.getElementById('delete_button').disabled = false;
document.getElementById('search_button').disabled = false;
document.getElementById('update_button').disabled = false;
document.getElementById('overview_button').disabled = false;
document.getElementById('import_button').disabled = false;
document.getElementById('pending_button').disabled = false;
document.getElementById('status_button').disabled = false;
document.getElementById('from_date').disabled = false;
document.getElementById('to_date').disabled = false;
document.getElementById('search_term').disabled = false;
document.getElementById('status_select').disabled = false;
document.getElementById('donut_select').disabled = false;
}
HITStorage.do_search = function(options)
{
HITStorage.indexedDB.getHITs(options);
setTimeout( function() { HITStorage.update_status_label("Search powered by non-amazonian script monkeys"); }, 3000);
HITStorage.enable_inputs();
}
HITStorage.show_results = function(results)
{
resultsWindow = window.open();
resultsWindow.document.write("<html><head><title>Status Detail Search Results</title></head><body>\n");
resultsWindow.document.write("<h1>HITs matching your search:</h1>\n");
resultsWindow.document.write('<table style="border: 1px solid black;border-collapse:collapse;width:90%;margin-left:auto;margin-right:auto;">\n');
resultsWindow.document.write('<tr style="background-color:lightgrey"><th>Date</th><th>Requester</th><th>HIT Title</th><th>Reward</th><th>Status</th><th>Feedback</th></tr>\n');
var odd = true;
var sum = 0;
var sum_rejected = 0;
var sum_approved = 0;
var sum_pending = 0;
var new_day = false;
for (var i=0; i<results.length; i++) {
odd = !odd;
sum += results[i].reward;
if (results[i].status == 'Rejected')
sum_rejected += results[i].reward;
else if (results[i].status == 'Pending Approval')
sum_pending += results[i].reward;
else
sum_approved += results[i].reward;
if (i>0 && (results[i-1].date != results[i].date))
new_day = true;
else
new_day = false;
resultsWindow.document.write(HITStorage.format_hit_line(results[i], odd, HITStorage.status_color(results[i].status), new_day ));
}
resultsWindow.document.write('<tr style="background-color:lightgrey"><th></th><th></th><th></th><th>$' + sum.toFixed(2) + '</th><th></th><th></th></tr>\n');
resultsWindow.document.write("</table>");
resultsWindow.document.write("<p>Found " + results.length + " matching HITs. $" + sum_approved.toFixed(2) + " approved, " +
"$" + sum_rejected.toFixed(2) + " rejected and $" + sum_pending.toFixed(2) + " pending.</p>");
resultsWindow.document.write("</body></html>")
resultsWindow.document.close();
}
HITStorage.status_color = function(status)
{
var color = "green";
if (status.match("Pending Approval"))
color = "orange";
else if (status.match("Rejected"))
color = "red";
return color;
}
HITStorage.format_hit_line = function(hit, odd, status_color, new_day)
{
var line = '<tr style="background-color:';
if (odd)
line += '#f1f3eb;';
else
line += 'white;';
line += ' valign=top;';
if (new_day)
line += ' border: 0px dotted #000000; border-width: 2px 0px 0px 0px">';
else
line += '">';
line += '<td>' + hit.date + '</td>';
if (hit.requesterLink != null)
line += '<td style="width:165px"><a href="' + hit.requesterLink + '" title="Contact this Requester">' + hit.requesterName + '</a></td>';
else
line += '<td style="width:165px">' + hit.requesterName + '</td>';
line += '<td style="width:213px">' + hit.title + '</td>';
line += '<td style="width:45px">$' + hit.reward.toFixed(2) + '</td>';
line += '<td style="color:' + status_color + '; width:55px">' + hit.status + '</td>';
line += '<td><div style="width:225px; overflow:hidden">' + hit.feedback + '</div></td>';
line += '</tr>\n';
return line;
}
HITStorage.show_pending_overview = function(results)
{
resultsWindow = window.open();
resultsWindow.document.write("<html><head><title>Summary of Pending HITs</title></head><body>\n");
resultsWindow.document.write("<h1>Summary of Pending HITs</h1>\n");
resultsWindow.document.write('<table style="border: 1px solid black;border-collapse:collapse;width:90%;margin-left:auto;margin-right:auto;">\n');
resultsWindow.document.write('<tr style="background-color:lightgrey"><th>requesterId</th><th>Requester</th><th></th><th>Pending</th><th>Rewards</th>\n');
// 'requesterId,requesterName,pending,reward';
var odd = false;
var sum = 0;
var pending = 0;
for (var i=0; i<results.length; i++) {
odd = !odd;
sum += results[i][3];
pending += results[i][2];
resultsWindow.document.write(HITStorage.format_pending_line(results[i], odd, i));
}
resultsWindow.document.write('<tr style="background-color:lightgrey"><th>' + results.length + ' different requesterIds</th><th></th><th></th><th style="text-align: right">' + pending + '</th><th style="text-align: right">$' + sum.toFixed(2) + '</th>\n');
resultsWindow.document.write("</table>");
resultsWindow.document.write("</body></html>")
resultsWindow.document.close();
for (var i=0; i<results.length; i++)
{
resultsWindow.document.getElementById('id-' + i).addEventListener("click", search_func(results[i][0], 'requesterId'), false);
resultsWindow.document.getElementById('id2-' + i).addEventListener("click", show_requester_func(results[i][0]) , false);
}
}
HITStorage.show_status_overview = function(results, date)
{
resultsWindow = window.open();
resultsWindow.document.write("<html><head><title>Daily HIT stats</title></head><body>\n");
if (date)
resultsWindow.document.write("<h1>Daily HIT stats</h1>\n");
else
resultsWindow.document.write("<h1>Daily HIT stats (' + date + ')</h1>\n");
resultsWindow.document.write('<table style="border: 1px solid black;border-collapse:collapse;width:90%;margin-left:auto;margin-right:auto;">\n');
resultsWindow.document.write('<tr style="background-color:lightgrey"><th>Date</th><th>Submitted</th><th>Approved</th><th>Rejected</th><th>Pending</th><th>Earnings</th>\n');
var odd = false;
var sum = 0;
var submitted = 0;
var approved = 0;
var rejected = 0;
var pending = 0;
var new_month = false;
for (var i=results.length-1; i>=0; i--) {
odd = !odd;
sum += results[i].earnings;
submitted += results[i].submitted;
approved += results[i].approved;
rejected += results[i].rejected;
pending += results[i].pending;
if (i<results.length-1)
new_month = (results[i].date.substr(0,7) != results[i+1].date.substr(0,7));
resultsWindow.document.write(HITStorage.format_status_line(results[i], odd, new_month));
}
resultsWindow.document.write('<tr style="background-color:lightgrey"><th>' + results.length + ' days</th><th style="text-align: left">' + submitted +
'</th><th style="text-align: left">' + approved +
'</th><th style="text-align: left">' + rejected +
'</th><th style="text-align: left">' + pending +
'</th><th style="text-align: left">$' + sum.toFixed(2) + '</th>\n');
resultsWindow.document.write("</table>");
resultsWindow.document.write("</body></html>")
resultsWindow.document.close();
for (var i=0; i<results.length; i++)
resultsWindow.document.getElementById(results[i].date).addEventListener("click", search_func('', 'date', results[i].date, results[i].date), false);
}
HITStorage.show_requester_overview = function(results, date)
{
resultsWindow = window.open();
resultsWindow.document.write("<html><head><title>Requester Overview</title></head><body>\n");
if (date)
resultsWindow.document.write("<h1>Requester Overview " + date + "</h1>\n");
else
resultsWindow.document.write("<h1>Requester Overview</h1>\n");
resultsWindow.document.write('<table style="border: 1px solid black;border-collapse:collapse;width:90%;margin-left:auto;margin-right:auto;">\n');
resultsWindow.document.write('<tr style="background-color:lightgrey"><th>requesterId</th><th>Requester</th><th></th><th>HITs</th><th>Pending</th><th>Rewards</th><th colspan="2">Rejected</th></tr>\n');
// 'requesterId,requesterName,hits,pending,reward,rejected';
var odd = false;
var sum = 0;
var hits = 0;
var rejected = 0;
var pending = 0;
var new_day = false;
var top = true;
var dot_line;
for (var i=0; i<results.length; i++) {
odd = !odd;
sum += results[i][3];
hits += results[i][2];
rejected += results[i][4];
pending += results[i][5];
dot_line = false;
if (i==10)
{
dot_line = true;
top = false;
}
if (i>10 && results[i][3] == 0 && results[i-1][3] != 0)
dot_line = true;
resultsWindow.document.write(HITStorage.format_overview_line(results[i], odd, dot_line, top, i));
}
resultsWindow.document.write('<tr style="background-color:lightgrey"><th>' + results.length + ' different requesterIds</th>' +
'<th></th><th></th><th style="text-align: right">' + hits + '<th style="text-align: right">' + pending +
'</th><th style="text-align: right">$' + sum.toFixed(2) + '</th><th style="text-align: right">' + rejected + '</th>' +
'<th style="text-align: right">' +
(rejected/hits*100).toFixed(2) + '%</th></tr>\n');
resultsWindow.document.write("</table>");
resultsWindow.document.write("<p>Reward includes all 'Paid' and 'Approved - Pending Payment' HITs. " +
"Reward does not include any bonuses.</p>");
resultsWindow.document.write("</body></html>")
resultsWindow.document.close();
for (var i=0; i<results.length; i++)
{
resultsWindow.document.getElementById('id-' + i).addEventListener("click", search_func(results[i][0], 'requesterId'), false);
resultsWindow.document.getElementById('id2-' + i).addEventListener("click", show_requester_func(results[i][0]) , false);
}
}
HITStorage.show_requester = function(results)
{
resultsWindow = window.open();
resultsWindow.document.write('<html><head><title>' + results[0].requesterName + '</title></head><body>\n');
resultsWindow.document.write('<h1>' + results[0].requesterName + ' (' + results[0].requesterId + ')</h1>\n');
resultsWindow.document.write('You have submitted ' + results.length + ' HITs for this requester. Earliest ' + results[results.length-1].date +
', latest ' + results[0].date);
resultsWindow.document.write('<p><a href="https://www.mturk.com/mturk/searchbar?selectedSearchType=hitgroups&requesterId=' + results[0].requesterId + '">' +
'Search HITs created by this requester</a></p>');
resultsWindow.document.write('<p><a href="http://turkopticon.differenceengines.com/' + results[0].requesterId + '">' +
'See reviews about this requester on Turkopticon</a> or ');
resultsWindow.document.write('<a href="' + TO_report_link(results[0].requesterId,results[0].requesterName) + '">' +
'review this requester on Turkopticon</a></p>');
var reward = 0;
var hits = 0;
var sum = 0;
var rejected = 0;
var approved = 0;
var pending = 0;
var all_rejected = 0;
var all_approved = 0;
var all_pending = 0;
resultsWindow.document.write('<table style="border: 1px solid black;border-collapse:collapse;margin-left:10px;margin-right:auto;">\n');
resultsWindow.document.write('<tr style="background-color:lightgrey"><th>Month' +
'</th><th>Submitted' +
'</th><th>Approved' +
'</th><th>Rejected' +
'</th><th>Pending' +
'</th><th>Earnings</th></tr>\n');
for (var i=0; i<results.length; i++) {
hits++;
if (results[i].status == 'Rejected')
{
all_rejected++;
rejected++;
}
else if (results[i].status == 'Pending Approval')
{
all_pending++;
pending++;
}
else
{
all_approved++;
approved++;
sum += results[i].reward;
reward += results[i].reward;
}
if (i==results.length-1 || (i<results.length-1 && (results[i].date.substr(0,7) != results[i+1].date.substr(0,7))))
{
resultsWindow.document.write('<tr><td style="text-align: right">' + results[i].date.substr(0,7) +
'</td><td style="text-align: right">' + hits +
'</td><td style="text-align: right">' + approved +
'</td><td style="text-align: right">' + rejected +
'</td><td style="text-align: right">' + pending +
'</td><td style="text-align: right">$' + reward.toFixed(2) + '</td></tr>\n');
reward = 0;
hits = 0;
approved = 0;
rejected = 0;
pending = 0;
}
}
resultsWindow.document.write('<tr style="background-color:lightgrey"><th>' +
'</th><th style="text-align: right">' + results.length +
'</th><th style="text-align: right">' + all_approved +
'</th><th style="text-align: right">' + all_rejected +
'</th><th style="text-align: right">' + all_pending +
'</th><th style="text-align: right">$' + sum.toFixed(2) + '</th></tr>\n');
resultsWindow.document.write('</table>');
resultsWindow.document.write('<p>Rewards do not include any bonuses</p>');
resultsWindow.document.write("</body></html>");
resultsWindow.document.close();
}
function TO_report_link(requesterId, requesterName)
{
return 'http://turkopticon.differenceengines.com/report?requester[amzn_id]=' + requesterId +
'&requester[amzn_name]=' + encodeURI(requesterName.trim());
}
HITStorage.format_overview_line = function(req, odd, dot_line, top, i)
{
var color;
if (top)
color = (odd)? 'ffffe0;' : '#eee8aa;';
else
color = (odd)? 'white;' : '#f1f3eb;';
var line = '<tr style="background-color:' + color;
if (dot_line)
line += ' border: 0px dotted #000000; border-width: 2px 0px 0px 0px';
line += '">';
line += '<td><button type="button" title="Show all HITs" style="height: 16px;font-size: 8px; padding: 0px;" id="id-' +
i + '">>></button>' +
'<button type="button" title="Show details about requester" style="height: 16px;font-size: 8px; padding: 0px;" id="id2-' +
i + '">+</button> ' + req[0].trim() +
'</td>';
line += '<td><a title="Requesters Turkopticon page" target="_blank" href="http://turkopticon.differenceengines.com/' + req[0].trim() + '">[TO]</a> ';
line += req[1].trim() + '</td>';
line += '<td style="width: 50px"><a title="Report requester to Turkopticon" target="_blank" href="' + TO_report_link(req[0], req[1]) + '">[report]</a></td>';
line += '<td style="text-align: right">' + req[2] + '</td>';
line += '<td style="text-align: right">' + req[5] + '</td>';
line += '<td style="text-align: right">$' + req[3].toFixed(2) + '</td>';
var p = (req[4]/req[2]*100).toFixed(1);
var pc = (p>0)? 'red' : 'green';
line += '<td style="text-align: right; color:' + pc + ';">' + req[4] + '</td>';
line += '<td style="text-align: right; color:' + pc + ';">' + p + '%</td>';
line += '</tr>\n';
return line;
}
HITStorage.format_pending_line = function(req, odd, i)
{
console.log(req);
var color = (odd)? 'white;' : '#f1f3eb;';
var line = '<tr style="background-color:' + color;
line += '">';
line += '<td style="white-space: nowrap; width: 150px; margin-right: 10px;"><button type="button" title="Show all HITs" style="height: 16px;font-size: 8px; padding: 0px;" id="id-' +
i + '">>>></button>' +
'<button type="button" title="Show details about requester" style="height: 16px;font-size: 8px; padding: 0px;" id="id2-' +
i + '">+</button> ' + req[0].trim() + '</td>';
line += '<td><a title="Requesters Turkopticon page" target="_blank" href="http://turkopticon.differenceengines.com/' + req[0].trim() + '">[TO]</a> ';
line += req[1].trim() + '</td>';
line += '<td style="width: 50px"><a title="Report requester to Turkopticon" target="_blank" href="' + TO_report_link(req[0], req[1]) + '">[report]</a></td>';
line += '<td style="text-align: right">' + req[2] + '</td>';
line += '<td style="text-align: right">$' + req[3].toFixed(2) + '</td>';
line += '</tr>\n';
return line;
}
HITStorage.format_status_line = function(d, odd, new_month)
{
var color = (odd)? 'white;' : '#f1f3eb;';
var line = '<tr style="background-color:' + color;
if (new_month)
line += ' border: 0px dotted #000000; border-width: 2px 0px 0px 0px">';
else
line += '">';
line += '<td><button type="button" title="Show all HITs" style="height: 16px;font-size: 8px; padding: 0px;" id="' +
d.date + '">>>></button> ' + d.date + '</td>';
line += '<td>' + d.submitted + '</td>';
line += '<td>' + d.approved + '</td>';
line += '<td>' + d.rejected + '</td>';
line += '<td>' + d.pending + '</td>';
line += '<td>$' + d.earnings.toFixed(2) + '</td>';
line += '</tr>\n';
return line;
}
HITStorage.show_pending_overview_csv = function(results)
{
var csvData = [];
csvData.push(["requesterId","requesterName","pending","reward","\n"]);
for (var i=0; i<results.length; i++) {
csvData.push(HITStorage.format_pending_line_csv(results[i]));
}
var blob = new Blob(csvData, {type: "text/csv;charset=utf-8"});
saveAs(blob, "pending_overview.csv");
}
HITStorage.format_pending_line_csv = function(req)
{
var line = [];
line.push(req[0].trim());
line.push('"' + req[1].trim() + '"');
line.push(req[2]);
line.push(req[3].toFixed(2));
line.push('\n');
return line;
}
HITStorage.show_requester_overview_csv = function(results)
{
var csvData = [];
csvData.push(['requesterId','requesterName','hits','reward','rejected','pending','\n']);
for (var i=0; i<results.length; i++) {
csvData.push(HITStorage.format_overview_line_csv(results[i]));
}
var blob = new Blob(csvData, {type: "text/csv;charset=utf-8"});
saveAs(blob, "requester_overview.csv");
}
HITStorage.format_overview_line_csv = function(req)
{
var line = [];
line.push(req[0].trim());
line.push('"' + req[1].trim() + '"');
line.push(req[2]);
line.push(req[3].toFixed(2));
line.push(req[4]);
line.push(req[5]);
line.push('\n');
return line;
}
HITStorage.show_status_overview_csv = function(results)
{
var csvData = [];
csvData.push(['Date','Submitted','Approved','Rejected','Pending','Earnings','\n']);
for (var i=results.length-1; i>=0; i--) {
csvData.push(HITStorage.format_status_line_csv(results[i]));
}
var blob = new Blob(csvData, {type: "text/csv;charset=utf-8"});
//location.href='data:text/csv;charset=utf8,' + encodeURIComponent(csvData);
saveAs(blob, "status_overview.csv");
}
HITStorage.format_status_line_csv = function(d)
{
var line = [];
line.push('"' + d.date + '"');
line.push(d.submitted);
line.push(d.approved);
line.push(d.rejected);
line.push(d.pending);
line.push(d.earnings.toFixed(2));
line.push('\n');
return line;
}
HITStorage.export_csv = function(results)
{
var csvData = [];
csvData.push(['hitId','date','requesterName','requesterId','title','reward','status','feedback','\n']);
for (var i=0; i<results.length; i++) {
csvData.push(HITStorage.format_csv_line(results[i]));
}
var blob = new Blob(csvData, {type: "text/csv;charset=utf-8"});
//location.href='data:text/csv;charset=utf8,' + encodeURIComponent(csvData);
saveAs(blob, "hit_database.csv");
}
HITStorage.format_csv_line = function(hit)
{
var line = [];
line.push('"' + hit.hitId.trim() + '"');
line.push('"' + hit.date.trim() + '"');
line.push('"' + hit.requesterName.trim() + '"');
line.push('"' + hit.requesterId.trim() + '"');
line.push('"' + hit.title.trim() + '"');
line.push(hit.reward.toFixed(2));
line.push('"' + hit.status.trim().replace(/\ /g,' ') + '"');
line.push('"' + hit.feedback.trim() + '"');
line.push('\n');
return line;
}
HITStorage.do_update = function(days_to_update)
{
if (DAYS_TO_FETCH.length<1)
{
HITStorage.check_update();
return;
}
HITStorage.update_status_label('Please wait: ' + progress_bar(days_to_update-DAYS_TO_FETCH.length, days_to_update) +
' (' + (days_to_update-DAYS_TO_FETCH.length) + '/' + days_to_update + ')', 'red');
var hits = [];
setTimeout(function(){ HITStorage.getHITData( DAYS_TO_FETCH.shift(), hits, 1, days_to_update); }, 2000);
}
HITStorage.update_done = function()
{
HITStorage.update_status_label('Script monkeys have updated your local database', 'green');
setTimeout( function() { HITStorage.update_status_label("Search powered by non-amazonian script monkeys"); }, 5000);
HITStorage.enable_inputs();
localStorage['HITDB UPDATED'] = new Date().toString();
var e = document.getElementById('user_activities.date_column_header.tooltip').parentNode.parentNode.childNodes[2].childNodes[1].childNodes[1];
if (e != null && e.textContent.trim() == 'Today') {
var today = e.href.slice(-8);
today = convert_date(today);
HITStorage.indexedDB.get_todays_projected_earnings(today);
}
HITStorage.indexedDB.get_pending_approvals();
HITStorage.indexedDB.get_pending_payments();
}
HITStorage.update_database = function()
{
HITStorage.disable_inputs();
if (localStorage['HITDB TRY_EXTRA_DAYS'] == 'YES') {
DAYS_TO_FETCH = HITStorage.getAllAvailableDays(20);
delete localStorage['HITDB TRY_EXTRA_DAYS'];
}
else
{
DAYS_TO_FETCH = HITStorage.getAllAvailableDays();
}
DAYS_TO_FETCH_CHECK = DAYS_TO_FETCH.slice(0);
// remove extra days from checklist
for (var i=0; i<DAYS_TO_FETCH_CHECK.length; i++)
{
if (DAYS_TO_FETCH_CHECK[i].submitted == -1) {
DAYS_TO_FETCH_CHECK = DAYS_TO_FETCH_CHECK.slice(0,i);
break;
}
}
DAYS_TO_FETCH = DAYS_TO_FETCH_CHECK.slice(0);
HITStorage.update_status_label('Please wait: script monkeys are preparing to start working', 'red');
setTimeout(function(){ HITStorage.prepare_update_and_check_pending_payments(); }, 100);
}
HITStorage.show_overview = function()
{
if (HITStorage.validate_dates() == false)
return;
var options = {};
options.term = document.getElementById('search_term').value;
options.status = document.getElementById('status_select').value;
options.donut = document.getElementById('donut_select').value;
options.from_date = document.getElementById('from_date').value;
options.to_date = document.getElementById('to_date').value;
options.export_csv = document.getElementById('export_csv').checked;
HITStorage.update_status_label('Please wait: script monkeys are picking bananas ?', 'red');
HITStorage.disable_inputs();
HITStorage.indexedDB.requesterOverview(options);
}
HITStorage.show_pendings = function()
{
var options = {};
options.term = document.getElementById('search_term').value;
options.status = document.getElementById('status_select').value;
options.donut = document.getElementById('donut_select').value;
options.from_date = document.getElementById('from_date').value;
options.to_date = document.getElementById('to_date').value;
options.export_csv = document.getElementById('export_csv').checked;
HITStorage.update_status_label('Please wait: script monkeys are picking bananas ?', 'red');
HITStorage.disable_inputs();
HITStorage.indexedDB.pendingOverview(options);
}
HITStorage.show_status = function()
{
if (HITStorage.validate_dates() == false)
return;
var options = {};
options.term = document.getElementById('search_term').value;
options.status = document.getElementById('status_select').value;
options.donut = document.getElementById('donut_select').value;
options.from_date = document.getElementById('from_date').value;
options.to_date = document.getElementById('to_date').value;
options.export_csv = document.getElementById('export_csv').checked;
HITStorage.update_status_label('Please wait: script monkeys are picking bananas ?', 'red');
HITStorage.disable_inputs();
HITStorage.indexedDB.statusOverview(options);
}
var IMPORT_DIALOG = null;
function import_dialog()
{
if (IMPORT_DIALOG == null)
{
IMPORT_DIALOG = document.createElement('div');
IMPORT_DIALOG.style.display = 'block';
IMPORT_DIALOG.style.position = 'fixed';
IMPORT_DIALOG.style.width = '600px';
//IMPORT_DIALOG.style.height = '400px';
IMPORT_DIALOG.style.height = '90%';
IMPORT_DIALOG.style.left = '50%';
IMPORT_DIALOG.style.right = '50%';
IMPORT_DIALOG.style.margin = '-300px 0px 0px -300px';
//IMPORT_DIALOG.style.top = '400px';
IMPORT_DIALOG.style.bottom = '10px';
IMPORT_DIALOG.style.padding = '10px';
IMPORT_DIALOG.style.border = '2px';
IMPORT_DIALOG.style.textAlign = 'center';
IMPORT_DIALOG.style.verticalAlign = 'middle';
IMPORT_DIALOG.style.borderStyle = 'solid';
IMPORT_DIALOG.style.borderColor = 'black';
IMPORT_DIALOG.style.backgroundColor = 'white';
IMPORT_DIALOG.style.color = 'black';
IMPORT_DIALOG.style.zIndex = '100';
var table = document.createElement('table');
var input = document.createElement('textarea');
var input2 = document.createElement('input');
var label = document.createElement('label');
var label2 = document.createElement('label');
label.textContent = 'Paste CSV-file in the textarea below.';
label2.textContent = 'CVS separator: ';
input.style.width = '100%';
input.style.height = '90%';
input2.maxLength = '1';
input2.size = '1';
input2.defaultValue = ',';
var import_button = document.createElement('button');
import_button.textContent = 'Import HITs';
import_button.addEventListener("click", import_dialog_close_func(true, input, input2), false);
import_button.style.margin = '5px';
var cancel_button = document.createElement('button');
cancel_button.textContent = 'Cancel';
cancel_button.addEventListener("click", import_dialog_close_func(false, input, input2), false);
cancel_button.style.margin = '5px';
IMPORT_DIALOG.appendChild(label);
IMPORT_DIALOG.appendChild(document.createElement('br'));
IMPORT_DIALOG.appendChild(label2);
IMPORT_DIALOG.appendChild(input2);
IMPORT_DIALOG.appendChild(document.createElement('br'));
IMPORT_DIALOG.appendChild(input);
IMPORT_DIALOG.appendChild(document.createElement('br'));
IMPORT_DIALOG.appendChild(cancel_button);
IMPORT_DIALOG.appendChild(import_button);
document.body.appendChild(IMPORT_DIALOG);
}
else
{
IMPORT_DIALOG.style.display = 'block';
}
}
/*
* CSVToArray() function is taken from:
*
* Blog Entry:
* Ask Ben: Parsing CSV Strings With Javascript Exec() Regular Expression Command
*
* Author:
* Ben Nadel / Kinky Solutions
*
* Link:
* http://www.bennadel.com/index.cfm?event=blog.view&id=1504
*
* Date Posted:
* Feb 19, 2009 at 10:03 AM
*/
// This will parse a delimited string into an array of
// arrays. The default delimiter is the comma, but this
// can be overriden in the second argument.
function CSVToArray( strData, strDelimiter ) {
// Check to see if the delimiter is defined. If not,
// then default to comma.
strDelimiter = (strDelimiter || ",");
// Create a regular expression to parse the CSV values.
var objPattern = new RegExp(
(
// Delimiters.
"(\\" + strDelimiter + "|\\r?\\n|\\r|^)" +
// Quoted fields.
"(?:\"([^\"]*(?:\"\"[^\"]*)*)\"|" +
// Standard fields.
"([^\"\\" + strDelimiter + "\\r\\n]*))"
),
"gi"
);
// Create an array to hold our data. Give the array
// a default empty first row.
var arrData = [[]];
// Create an array to hold our individual pattern
// matching groups.
var arrMatches = null;
// Keep looping over the regular expression matches
// until we can no longer find a match.
while (arrMatches = objPattern.exec( strData )){
// Get the delimiter that was found.
var strMatchedDelimiter = arrMatches[ 1 ];
// Check to see if the given delimiter has a length
// (is not the start of string) and if it matches
// field delimiter. If id does not, then we know
// that this delimiter is a row delimiter.
if (
strMatchedDelimiter.length &&
(strMatchedDelimiter != strDelimiter)
){
// Since we have reached a new row of data,
// add an empty row to our data array.
arrData.push( [] );
}
// Now that we have our delimiter out of the way,
// let's check to see which kind of value we
// captured (quoted or unquoted).
if (arrMatches[ 2 ]){
// We found a quoted value. When we capture
// this value, unescape any double quotes.
var strMatchedValue = arrMatches[ 2 ].replace(
new RegExp( "\"\"", "g" ),
"\""
);
} else {
// We found a non-quoted value.
var strMatchedValue = arrMatches[ 3 ];
}
// Now that we have our value string, let's add
// it to the data array.
arrData[ arrData.length - 1 ].push( strMatchedValue );
}
// Return the parsed data.
return( arrData );
}
function import_dialog_close_func(save, input, separator)
{
return function()
{
if (save == true)
{
var lines = [];
var hits = [];
var dates = [];
if (input.value.length > 0)
lines = CSVToArray(input.value, separator.value);
var errors = 0;
for (var i = 0; i<lines.length; i++)
{
var error = false;
try {
if (lines[i][0] == null || lines[i][0] == 'hitId')
continue;
if(lines[i][6] == 'Approved - Pending Payment')
lines[i][6] = 'Approved - Pending Payment';
if (lines[i].length != 8)
error = true;
var hit = {
hitId : lines[i][0],
date : convert_date(lines[i][1]),
requesterName : lines[i][2],
//This line was null in the version I was using. I added it in, giving it the proper format.
//This setting is for the links to contact the requester in the status window
requesterLink : "https://www.mturk.com/mturk/contact?subject=Regarding+Amazon+Mechanical+Turk+HIT+"+lines[i][0]+"&requesterId="+lines[i][3]+"&requesterName="+lines[i][2].replace(" ","+"),
requesterId : lines[i][3],
title : lines[i][4],
reward : parseFloat(lines[i][5]),
status : lines[i][6],
feedback : lines[i][7] || "" // If no feedback, put empty string
};
//This status thing is actually for the Hit Status page (daily overview). It was non-existent with the current version, I added the functionality in here.
//This sets up a simple associative array for the initial "date" entry for the hit stats. See below for implementation
var status = {
date : hit.date,
approved : (hit.status != "Rejected" ? 1 : 0),
earnings : (hit.status != "Rejected" ? hit.reward : 0),
pending : (hit.status != "Pending" ? 0 : 1),
rejected : (hit.status == "Rejected" ? 1 : 0),
submitted : 1
};
} catch(err) { error = true; }
if (error == false){
hits.push(hit);
//Implementation of status stuff. First I see if the object exists in my "dates" array,
var index = lookup(hit.date, "date", dates);
if (index != -1){
//if it does, add each value except date to update it. The values will either be 1 or 0, so just += should give the proper values (and it does based on testing
for (var key in dates[index]){
if (key != "date")
dates[index][key] += status[key];
}
}
else
dates.push(status); //if the date doesn't exist in the array, add it as an initial object
}
else
errors++;
}
if (hits.length < 1)
{
alert('No HITs found!');
return;
}
else if (confirm('Found ' + hits.length + ' HITs' + (errors>0? ' and ' + errors + (errors==1? ' error' : ' errors') : '') +
'.\nDo not reload this page until import is ready.\n' +
'Press Ok to start.') == true)
{
HITStorage.disable_inputs();
HITStorage.update_status_label('Please wait: importing HITs', 'red');
IMPORT_DIALOG.style.display = 'none';
input.value = '';
HITStorage.indexedDB.importHITs(hits);
//You have to call updateHITstats on a date object:
//object = { date:"yyyy-mm-dd", (approved|pending|rejected):int num(Approved|Pending|Rejected), earnings:float totalEarningsForDay, submitted:int numHitsSubmittedThatDay }
//Easiest hack to do so, parse over the dates objects I manipulated above, call update hit stats on each of them.
for (var i = 0; i < dates.length; i++){
HITStorage.indexedDB.updateHITstats(dates[i]);
}
return;
}
else { return; }
}
IMPORT_DIALOG.style.display = 'none';
input.value = '';
};
}
//simple lookup function for searching I'm reusing.
function lookup (needle, key, haystack) {
for (var i = 0; i < haystack.length; i++){
if (haystack[i][key] == needle)
return i;
}
return -1;
}
function get_requester_id(s) {
var idx = 12 + s.search('requesterId=');
return s.substr(idx);
}
function show_requester_func(requesterId)
{
return function()
{
HITStorage.indexedDB.showRequester(requesterId);
};
}
function search_func(key, index, d1, d2)
{
d1 = d1 || '';
d2 = d2 || d1;
return function()
{
HITStorage.indexedDB.getHITs({term: key, index: index, status: '---', from_date: d1, to_date: d2, donut: '', this_day: ''});
};
}
function visible_func(element, visible)
{
return function()
{
element.style.visibility = (visible)? 'visible' : 'hidden';
};
}
function delete_func()
{
return function()
{
if (confirm('This will remove your local HIT DataBase!\nContinue?'))
{
HITStorage.indexedDB.deleteDB();
}
};
}
function import_func()
{
return function()
{
import_dialog();
};
}
function note_func(id, label)
{
return function()
{
note = prompt('Note for requesterId \'' + id + '\':', label.textContent);
if (note == null)
{
return;
}
HITStorage.indexedDB.addNote(id, note);
label.textContent = note;
label.style.border = '1px dotted';
if (note.indexOf('!') >= 0)
label.style.color = 'red';
else
label.style.color = 'black';
};
}
function block_func(requesterId, title, hitElement)
{
return function()
{
re = prompt('Block HITs from requesterId \'' + requesterId + '\' matching:\n' +
'(default matches only exactly same HIT title, leave empty to match all HITS)', '^'
+ title.replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1") + '$');
if (re == null)
{
return;
}
re = new RegExp(re);
if (!re.test(title)) {
if (confirm("Your regular expression does not match current HIT title.\nSave it anyway?") == false)
return;
}
HITStorage.indexedDB.addBlock(requesterId, re);
};
}
function unblock_func(requesterId, title)
{
return function()
{
var unblock = confirm('Unblocking removes all blocks that match this HITs title and requesterId.');
if (unblock == true)
{
HITStorage.indexedDB.removeBlocks(requesterId, title);
}
};
}
function auto_update_func()
{
return function()
{
var button = document.getElementById('auto_button');
if (localStorage['HITDB AUTO UPDATE'] === undefined)
{
alert('Enable Hit DataBase Auto Update\nWhen enabled, script will fetch last ' +
'statusdetail pages and add them to database when this page is reloaded ' +
'and at least two minutes have passed from last update. You still need to ' +
'do full update from dashboard every now and then.');
button.textContent = 'Auto Update is ON';
button.style.color = 'green';
localStorage['HITDB AUTO UPDATE'] = 'ON';
}
else if (localStorage['HITDB AUTO UPDATE'] == 'ON')
{
button.textContent = 'Auto Update is OFF';
button.style.color = 'red';
localStorage['HITDB AUTO UPDATE'] = 'OFF';
}
else
{
button.textContent = 'Auto Update is ON';
button.style.color = 'green';
localStorage['HITDB AUTO UPDATE'] = 'ON';
}
};
}
function set_target_func(date)
{
return function()
{
var target = localStorage['TODAYS TARGET'];
if (target === undefined)
target = '';
else
target = parseFloat(localStorage['TODAYS TARGET']).toFixed(2);
target = prompt('Set your target:', target);
if (target == null)
return;
target = parseFloat(target);
localStorage['TODAYS TARGET'] = target.toFixed(2);
if (date != null)
HITStorage.indexedDB.get_todays_projected_earnings(date);
};
}
function random_face()
{
var faces = ['?','?','?','?','?','?','?','?','?','?','?','?','?','?','?','?'];
var n = Math.floor((Math.random()*faces.length));
return '<span style="color: black; font-weight: normal;" title="Featured non-amazonian script ' + ((n>11) ? '... kitten?': 'monkey') + '">' + faces[n] + '</span>';
}
function progress_bar(done, max, full, empty, c1, c2)
{
max = (max<1)? 1 : max;
done = (done<0)? 0 : done;
done = (done>max)? max : done;
var bar = '<span style="color: ' + (c1||'green') + '">';
for (var i=0; i<done; i++)
{
bar += full || '■';
}
bar += '</span><span style="color: ' + (c2||'black') + '">';
for (var i=done; i<max; i++)
{
bar += empty || '⬜';
}
bar += '</span>';
return bar;
}
// convert date to more practical form (MMDDYYYY => YYYY-MM-DD)
function convert_date(date)
{
if (date.indexOf('-') > 0)
return date;
var day = date.substr(2,2);
var month = date.substr(0,2);
var year = date.substr(4,4);
return (year + '-' + month + '-' + day);
}
// convert date from YYYY-MM-DD to MMDDYYYY if it isn't already
function convert_iso_date(date)
{
if (date.indexOf('-') < 0)
return date;
var t = date.split('-');
return t[1] + t[2] + t[0];
}
// Format date for display YYYY-MM-DD, DD/MM/YYYY or DD.MM.YYYY
function display_date(date, format)
{
if (format === undefined || format == null)
return date;
var d = date.split('-');
if (format == 'little')
{
return d[2] + '.' + d[1] + '.' + d[0];
}
if (format == 'middle')
{
return d[1] + '/' + d[2] + '/' + d[0];
}
}
HITStorage.indexedDB.create();
// Backup plan
//HITStorage.update_date_format(true);
if (document.location.href.match('https://www.mturk.com/mturk/dashboard'))
{
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';
var row1 = document.createElement('tr');
var row2 = document.createElement('tr');
var td1 = document.createElement('td');
var content_td = document.createElement('td');
var whatsthis = document.createElement('a');
row1.style.height = '25px';
td1.setAttribute('class', 'white_text_14_bold');
td1.style.backgroundColor = '#7fb448';//'#7fb4cf';
td1.style.paddingLeft = '10px';
td1.innerHTML = 'HIT DataBase' + random_face() + ' ';
content_td.setAttribute('class', 'container-content');
whatsthis.href = 'http://userscripts.org/scripts/show/149548';
whatsthis.setAttribute('class', 'whatis');
whatsthis.textContent = '(What\'s this?)';
extra_table.appendChild(row1);
row1.appendChild(td1);
td1.appendChild(whatsthis);
extra_table.appendChild(row2);
row2.appendChild(content_td);
footer.parentNode.insertBefore(extra_table, footer);
var my_bar = document.createElement('div');
var search_button = document.createElement('button');
var status_select = document.createElement('select');
var label = document.createElement('label');
var label2 = document.createElement('label');
var input = document.createElement('input');
var donut_select = document.createElement('select');
var csv_label = document.createElement('label');
var csv = document.createElement('input');
var update_button = document.createElement('button');
var delete_button = document.createElement('button');
var pending_button = document.createElement('button');
var overview_button = document.createElement('button');
var import_button = document.createElement('button');
var status_button = document.createElement('button');
var from_input = document.createElement('input');
var to_input = document.createElement('input');
var date_label1 = document.createElement('label');
var date_label2 = document.createElement('label');
date_label1.textContent = 'from date ';
date_label2.textContent = ' to ';
from_input.setAttribute('id', "from_date");
to_input.setAttribute('id', "to_date");
to_input.setAttribute('maxlength', "10");
from_input.setAttribute('maxlength', "10");
to_input.setAttribute('size', "10");
from_input.setAttribute('size', "10");
from_input.title = 'Date format YYYY-MM-DD\nOr leave empty.';
to_input.title = 'Date format YYYY-MM-DD\nOr leave empty.';
var donut_options = [];
donut_options[0] = document.createElement("option");
donut_options[1] = document.createElement("option");
donut_options[2] = document.createElement("option");
donut_options[0].text = "---";
donut_options[1].text = "Donut Chart HITS";
donut_options[2].text = "Donut Chart REWARDS";
donut_options[0].value = "---";
donut_options[1].value = "HITS";
donut_options[2].value = "REWARDS";
var status_options = [];
status_options[0] = document.createElement("option");
status_options[1] = document.createElement("option");
status_options[2] = document.createElement("option");
status_options[3] = document.createElement("option");
status_options[4] = document.createElement("option");
status_options[5] = document.createElement("option");
status_options[0].text = "Pending Approval";
status_options[0].style.color = "orange";
status_options[1].text = "Rejected";
status_options[1].style.color = "red";
status_options[2].text = "Approved - Pending Payment";
status_options[2].style.color = "green";
status_options[3].text = "Paid";
status_options[3].style.color = "green";
status_options[4].text = "Paid AND Approved";
status_options[4].style.color = "green";
status_options[5].text = "ALL";
status_options[0].value = "Pending Approval";
status_options[1].value = "Rejected";
status_options[2].value = "Approved";
status_options[3].value = "Paid";
status_options[4].value = "Paid|Approved";
status_options[5].value = "---";
search_button.setAttribute('id', "search_button");
input.setAttribute('id', "search_term");
status_select.setAttribute('id', "status_select");
label.setAttribute('id', "status_label");
donut_select.setAttribute('id', "donut_select");
delete_button.setAttribute('id', "delete_button");
update_button.setAttribute('id', "update_button");
overview_button.setAttribute('id', "overview_button");
import_button.setAttribute('id', "import_button");
pending_button.setAttribute('id', "pending_button");
status_button.setAttribute('id', "status_button");
my_bar.style.marginLeft = 'auto';
my_bar.style.marginRight = 'auto';
my_bar.style.textAlign = 'center';
label.style.marginLeft = 'auto';
label.style.marginRight = 'auto';
label.style.textAlign = 'center';
var donut = document.createElement('div');
donut.setAttribute('id', "container");
donut.style.display = 'none';
content_td.appendChild(my_bar);
my_bar.appendChild(delete_button);
my_bar.appendChild(import_button);
my_bar.appendChild(update_button);
my_bar.appendChild(document.createElement("br"));
my_bar.appendChild(pending_button);
my_bar.appendChild(overview_button);
my_bar.appendChild(status_button);
my_bar.appendChild(document.createElement("br"));
my_bar.appendChild(donut_select);
my_bar.appendChild(status_select);
my_bar.appendChild(label2);
my_bar.appendChild(input);
my_bar.appendChild(search_button);
my_bar.appendChild(document.createElement("br"));
my_bar.appendChild(date_label1);
my_bar.appendChild(from_input);
my_bar.appendChild(date_label2);
my_bar.appendChild(to_input);
my_bar.appendChild(csv_label);
my_bar.appendChild(csv);
my_bar.appendChild(document.createElement("br"));
my_bar.appendChild(label);
my_bar.appendChild(document.createElement("br"));
(footer.parentNode).insertBefore(donut, footer);
my_bar.style.textAlign = "float";
search_button.textContent = "Search";
search_button.title = "Search from local HIT database\nYou can set time limits and export as CSV-file";
label2.textContent = " HITs matching: ";
input.value = "";
label.textContent = "Search powered by non-amazonian script monkeys";
for (var i=0; i<status_options.length; i++)
status_select.options.add(status_options[i]);
for (var i=0; i<donut_options.length; i++)
donut_select.options.add(donut_options[i]);
update_button.title = "Fetch status pages and copy HITs to local indexed database.\nFirst time may take several minutes!";
update_button.textContent = "Update database";
update_button.style.color = 'green';
update_button.style.margin = '5px 5px 5px 5x';
delete_button.textContent = "Delete database";
delete_button.style.color = 'red';
delete_button.style.margin = '5px 5px 5px 5px';
delete_button.title = "Delete Local DataBase!";
import_button.textContent = "Import";
import_button.style.margin = '5px 5px 5px 5px';
import_button.title = "Import HIT data from exported CSV-file";
overview_button.textContent = "Requester Overview";
overview_button.style.margin = '0px 5px 5px 5px';
overview_button.title = "Summary of all requesters you have worked for\nYou can set time limit and export as CSV-file";
pending_button.textContent = "Pending Overview";
pending_button.style.margin = '0px 5px 5px 5px';
pending_button.title = "Summary of all pending HITs\nYou can export as CSV-file";
status_button.textContent = "Daily Overview";
status_button.style.margin = '0px 5px 5px 5px';
status_button.title = "Summary of each day you have worked on MTurk\nYou can set time limit and export as CSV-file";
pending_button.addEventListener("click", HITStorage.show_pendings, false);
overview_button.addEventListener("click", HITStorage.show_overview, false);
search_button.addEventListener("click", HITStorage.start_search, false);
update_button.addEventListener("click", HITStorage.update_database, false);
delete_button.addEventListener("click", delete_func(), false);
import_button.addEventListener("click", import_func(), false);
status_button.addEventListener("click", HITStorage.show_status, false);
csv_label.textContent = 'export CSV';
csv_label.title = 'Export results as comma-separated values';
csv_label.style.verticalAlign = 'middle';
csv_label.style.marginLeft = '50px';
csv.title = 'Export results as comma-separated values';
csv.setAttribute('type', 'checkbox');
csv.setAttribute('id', 'export_csv');
csv.style.verticalAlign = 'middle';
from_input.value = '';
to_input.value = '';
var table = document.getElementById('bonus_earnings_amount');
if (table != null)
{
table = table.parentNode.parentNode.parentNode.parentNode;
var pending_tr = document.createElement('tr');
var pending_td1 = document.createElement('td');
var pending_td2 = document.createElement('td');
var today_tr = document.createElement('tr');
var today_td1 = document.createElement('td');
var today_td2 = document.createElement('td');
pending_tr.setAttribute('class', 'even');
pending_td1.setAttribute('class', 'metrics-table-first-value');
pending_td1.setAttribute('id', 'pending_earnings_header');
pending_td2.setAttribute('id', 'pending_earnings_value');
today_tr.setAttribute('class', 'odd');
today_td1.setAttribute('class', 'metrics-table-first-value');
today_td1.setAttribute('id', 'projected_earnings_header');
today_td2.setAttribute('id', 'projected_earnings_value');
pending_tr.appendChild(pending_td1);
pending_tr.appendChild(pending_td2);
today_tr.appendChild(today_td1);
today_tr.appendChild(today_td2);
table.appendChild(pending_tr);
table.appendChild(today_tr);
pending_td1.style.borderTop = '1px dotted darkgrey';
pending_td2.style.borderTop = '1px dotted darkgrey';
today_td1.style.borderBottom = '1px dotted darkgrey';
today_td2.style.borderBottom = '1px dotted darkgrey';
today_td1.title = 'This value can be inaccurate if HITDB has not been updated recently';
pending_td1.title = 'This value can be inaccurate if HITDB has not been updated recently';
if (localStorage['HITDB UPDATED'] === undefined)
pending_td1.textContent = 'Pending earnings';
else
pending_td1.textContent = 'Pending earnings (HITDB updated: ' + localStorage['HITDB UPDATED'] + ')';
today_td1.innerHTML = 'Projected earnings for today ';
today_td2.textContent = 'ಠ_ಠ';
pending_td2.textContent = 'ಠ_ಠ';
var e = document.getElementById('user_activities.date_column_header.tooltip').parentNode.parentNode.childNodes[2].childNodes[1].childNodes[1];
var today = null;
if (e != null && e.textContent.trim() == 'Today') {
today = convert_date(e.href.slice(-8));
HITStorage.indexedDB.get_todays_projected_earnings(today);
}
HITStorage.indexedDB.get_pending_approvals();
HITStorage.indexedDB.get_pending_payments();
var target = document.createElement('span');
target.setAttribute('id', 'my_target');
target.textContent = 'click here to set your target';
target.style.fontSize = 'small';
target.style.color = 'blue';
today_td1.appendChild(target);
target.addEventListener("click", set_target_func(today), false);
}
}
else if (document.location.href.match('https://www.mturk.com/mturk/preview'))
{
var table = document.getElementById('requester.tooltip');
if (table == null)
return;
table = table.parentNode.parentNode.parentNode;
var title = table.parentNode.parentNode.parentNode.parentNode.getElementsByTagName('div')[0].textContent.trim();
var extra_row = document.createElement('tr');
var td_1 = document.createElement('td');
var td_2 = document.createElement('td');
var requesterId = document.getElementsByName('requesterId')[0].value;
var auto_approve = parseInt(document.getElementsByName('hitAutoAppDelayInSeconds')[0].value);
var buttons = [];
var b = ['Requester', 'HIT Title'];
for (var i=0; i<b.length; i++)
{
buttons[i] = document.createElement('button');
buttons[i].textContent = b[i];
buttons[i].id = b[i] + 'Button' + i;
buttons[i].style.fontSize = '10px';
buttons[i].style.height = '18px';
buttons[i].style.width = '80px';
buttons[i].style.border = '1px solid';
buttons[i].style.paddingLeft = '3px';
buttons[i].style.paddingRight = '3px';
buttons[i].style.backgroundColor = 'lightgrey';
buttons[i].setAttribute('form', 'NOThitForm');
td_1.appendChild(buttons[i]);
}
buttons[0].title = 'Search requester ' + requesterId + ' from HIT database';
buttons[1].title = 'Search title \'' + title + '\' from HIT database';
HITStorage.indexedDB.colorRequesterButton(requesterId, buttons[0]);
HITStorage.indexedDB.colorTitleButton(title, buttons[1]);
buttons[0].addEventListener("click", search_func(requesterId, 'requesterId'), false);
buttons[1].addEventListener("click", search_func(title, 'title'), false);
td_2.innerHTML = '<span class="capsule_field_title">Auto-Approval:</span>  ' + HITStorage.formatTime(auto_approve*1000) + '';
td_1.colSpan = '3';
td_2.colSpan = '8';
extra_row.appendChild(td_1);
extra_row.appendChild(td_2);
table.appendChild(extra_row);
}
else
{
for (var item=0; item<10; item++) {
var tooltip = document.getElementById('requester.tooltip--' + item);
if (tooltip == null)
break; // no need to continue
var titleElement = document.getElementById('capsule' + item + '-0');
var emptySpace = tooltip.parentNode.parentNode.parentNode.parentNode.parentNode;
var hitItem = tooltip.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode;//.parentNode;
var requesterLabel = tooltip.parentNode;
var requesterId = tooltip.parentNode.parentNode.getElementsByTagName('a');
var title = titleElement.textContent.trim();
requesterId = get_requester_id(requesterId[1].href);
var buttons = [];
var row = document.createElement('tr');
var div = document.createElement('div');
emptySpace.appendChild(row);
row.appendChild(div);
/* Turkopticon link next to requester name */
//to_link = document.createElement('a');
//to_link.textContent = ' TO ';
//to_link.href = 'http://turkopticon.differenceengines.com/' + requesterId;
//to_link.target = '_blank';
//to_link.title = requesterId + ' on Turkopticon';
//tooltip.parentNode.parentNode.appendChild(to_link);
/*-----------------------------------------*/
HITStorage.indexedDB.blockHITS(requesterId, title, hitItem, titleElement);
var b = ['R', 'T', 'N', 'B'];
for (var i=0; i<b.length; i++)
{
buttons[i] = document.createElement('button');
buttons[i].textContent = b[i];
buttons[i].id = b[i] + 'Button' + i;
buttons[i].style.height = '18px';
buttons[i].style.fontSize = '10px';
buttons[i].style.border = '1px solid';
buttons[i].style.paddingLeft = '3px';
buttons[i].style.paddingRight = '3px';
buttons[i].style.backgroundColor = 'lightgrey';
div.appendChild(buttons[i]);
}
buttons[0].title = 'Search requester ' + requesterId + ' from HIT database';
buttons[1].title = 'Search title \'' + title + '\' from HIT database';
buttons[2].title = 'Add a requester note';
buttons[3].title = '"Block" requester';
var notelabel = document.createElement('label');
notelabel.textContent = '';
notelabel.id = b[i] + 'notelabel' + item;
notelabel.style.height = '18px';
notelabel.style.fontSize = '10px';
notelabel.style.marginLeft = '10px';
notelabel.style.padding = '1px';
notelabel.style.backgroundColor = 'transparent';
HITStorage.indexedDB.updateNoteButton(requesterId, notelabel);
div.appendChild(notelabel);
HITStorage.indexedDB.colorRequesterButton(requesterId, buttons[0]);
HITStorage.indexedDB.colorTitleButton(title, buttons[1]);
buttons[0].addEventListener("click", search_func(requesterId, 'requesterId'), false);
buttons[1].addEventListener("click", search_func(title, 'title'), false);
buttons[2].addEventListener("click", note_func(requesterId, notelabel), false);
buttons[3].addEventListener("click", block_func(requesterId, title, hitItem), false);
div.style.margin = "0px";
buttons[2].style.visibility = "hidden"; // "visible"
buttons[2].parentNode.addEventListener("mouseover", visible_func(buttons[2], true), false);
buttons[2].parentNode.addEventListener("mouseout", visible_func(buttons[2], false), false);
buttons[2].addEventListener("mouseout", visible_func(buttons[2], false), false);
buttons[3].style.visibility = "hidden"; // "visible"
buttons[3].parentNode.addEventListener("mouseover", visible_func(buttons[3], true), false);
buttons[3].parentNode.addEventListener("mouseout", visible_func(buttons[3], false), false);
buttons[3].addEventListener("mouseout", visible_func(buttons[3], false), false);
}
var auto_button = document.createElement('button');
auto_button.setAttribute('id', 'auto_button');
auto_button.title = 'HIT DataBase Auto Update\nAutomagically update newest HITs to database when reloading this page';
if (localStorage['HITDB AUTO UPDATE'] === undefined)
{
auto_button.textContent = 'Auto update ?';
auto_button.style.color = 'red';
}
else if (localStorage['HITDB AUTO UPDATE'] == 'ON')
{
auto_button.textContent = 'Auto Update is ON';
auto_button.style.color = 'green';
}
else
{
auto_button.textContent = 'Auto Update is OFF';
auto_button.style.color = 'red';
}
//var element = document.body.childNodes[13].childNodes[3].childNodes[1].childNodes[0].childNodes[5];
var element = document.getElementsByName("/sort")[0];
//element.insertBefore(auto_button, element.firstChild);
element.parentNode.insertBefore(auto_button, element.nextSibling);
auto_button.addEventListener("click", auto_update_func(), false);
setTimeout(HITStorage.getLatestHITs, 100);
}