// ==UserScript==
// @name mmmturkeybacon Color Coded Queue
// @author mmmturkeybacon
// @description Changes the title row of a HIT's description to match the average of it's Turkopticon ratings. Changes the color of the reward amount to match the color of the Turkopticon rating for pay. Adds colored checkboxes to show/hide HITs by color rating. Changes the background color of the HIT title and link to white for Master's HITs. Changes the color of visited links to black.
// @namespace http://userscripts.org/users/523367
// @match https://www.mturk.com/mturk/myhits
// @match https://www.mturk.com/mturk/sortmyhits?*
// @match https://www.mturk.com/mturk/viewmyhits?*
// @require https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js
// @version 1.01
// @grant GM_xmlhttpRequest
// @grant GM_getValue
// @grant GM_setValue
// ==/UserScript==
/**********************************************************************/
/* NB: turkopticon.ucsd.edu (TO website) uses yellow for a rating between 2 and 3,
* but TO extension uses orange
*
* Turkopticon scale
* green : 3 < average <= 5
* orange: 2 < average <= 3
* red : 1 < average <= 2
*
* Color Coded Search scale (so that green represents the very best HITs)
* green : 4 < average <= 5
* yellow: 3 < average <= 4 yellow are OK HITs, that's why the yellow has a touch of green
* orange: 2 < average <= 3
* red : 1 < average <= 2
*/
var GREEN = '#66CC66'; // (4,5]
//var YELLOW = '#FFFF00'; // (3,4] yellow
//var YELLOW = '#CDFF2F'; // (3,4] yellow with hint of green
var YELLOW = '#ADFF2F'; // (3,4] green yellow
//var YELLOW = '#9CE62A'; // (3,4] darker green yello
var ORANGE = '#FF9900'; // (2,3]
//var RED = '#FF0000'; // (1,2]
var RED = '#FF3030'; // (1,2]
var BLUE = '#7FAAEB'; // no rating
var VISITED_LINK = '#000000'; // black
var COMM_WEIGHT = 1;
var PAY_WEIGHT = 3;
var FAIR_WEIGHT = 3;
var FAST_WEIGHT = 1;
var SHOW_ALL_DETAILS = false;
/**********************************************************************/
// URLs for testing, learning parameters
//http://mturk-api.istrack.in/multi-attrs.php?ids=ABSF8UXFZYEK6
//http://data.istrack.in/turkopticon.php?data=2.57,2.31,2.89,2.71
var TIMEOUT = 10000; // [ms] milliseconds, 0 means wait forever
var API_BASE = 'https://turkopticon.ucsd.edu/api/';
var API_MULTI_ATTRS_URL = API_BASE + 'multi-attrs.php?ids=';
var API_PROXY_BASE = 'https://mturk-api.istrack.in/';
var API_PROXY_MULTI_ATTRS_URL = API_PROXY_BASE + 'multi-attrs.php?ids=';
var REVIEWS_BASE = 'http://turkopticon.ucsd.edu/';
var HIT_GROUPS_BASE_LINK = '/mturk/searchbar?selectedSearchType=hitgroups&requesterId=';
var green_checkbox;
var yellow_checkbox;
var orange_checkbox;
var red_checkbox;
var blue_checkbox;
var $parent_tables;
function process_TO_data(requester_data)
{
var average = 0;
var comm_rnd = 0;
var pay_rnd = 0;
var fair_rnd = 0;
var fast_rnd = 0;
var reviews = 0;
var tos = 0;
// after the API update, this if isn't necessary. leaving it in until
// sure API is stable
if (requester_data)
{
var comm = requester_data.attrs.comm;
var pay = requester_data.attrs.pay;
var fair = requester_data.attrs.fair;
var fast = requester_data.attrs.fast;
var sum = 0;
var divisor = 0;
if (comm > 0)
{
sum += COMM_WEIGHT*comm;
divisor += COMM_WEIGHT;
}
if (pay > 0)
{
sum += PAY_WEIGHT*pay;
divisor += PAY_WEIGHT;
}
if (fair > 0)
{
sum += FAIR_WEIGHT*fair;
divisor += FAIR_WEIGHT;
}
if (fast > 0)
{
sum += FAST_WEIGHT*fast;
divisor += FAST_WEIGHT;
}
if (divisor > 0)
{
average = sum/divisor;
}
comm_rnd = Math.round(comm*4)/4;
pay_rnd = Math.round(pay*4)/4;
fair_rnd = Math.round(fair*4)/4;
fast_rnd = Math.round(fast*4)/4;
if (requester_data.reviews)
{
reviews = requester_data.reviews;
}
if (requester_data.tos_flags)
{
tos = requester_data.tos_flags;
}
}
comm_rnd = comm_rnd.toFixed(2);
pay_rnd = pay_rnd.toFixed(2);
fair_rnd = fair_rnd.toFixed(2);
fast_rnd = fast_rnd.toFixed(2);
return {comm_rnd:comm_rnd, pay_rnd:pay_rnd, fair_rnd:fair_rnd, fast_rnd:fast_rnd, reviews:reviews, tos:tos, average:average};
}
function determine_color(rating)
{
// The lowest rating that can be given is a 1.
// green is (4,5]
// yellow is (3,4]
// orange is (2,3]
// red is (1,2]
// blue is 0 (no rating)
// (0,1) is no man's land but I set the lower bound for red to 0 to agree with data.istrack.in
var color = BLUE;
if (rating > 4)
{
color = GREEN;
}
else if (rating > 3)
{
color = YELLOW;
}
else if (rating > 2 )
{
color = ORANGE;
}
else if (rating > 0)
{
color = RED;
}
return color;
}
function show_hide_color(color)
{
//var $color_subset_tables = $parent_tables.filter('[title_color='+color+'][hideable!=false]');
var $color_subset_tables = $parent_tables.filter('[title_color='+color+']');
switch(color)
{
case GREEN:
{
GM_setValue('green_checkbox_checked', green_checkbox.checked);
if (green_checkbox.checked == false)
{
$color_subset_tables.each(function()
{
$(this).hide();
});
}
else
{
$color_subset_tables.each(function()
{
$(this).show();
});
}
break;
}
case YELLOW:
{
GM_setValue('yellow_checkbox_checked', yellow_checkbox.checked);
if (yellow_checkbox.checked == false)
{
$color_subset_tables.each(function()
{
$(this).hide();
});
}
else
{
$color_subset_tables.each(function()
{
$(this).show();
});
}
break;
}
case ORANGE:
{
GM_setValue('orange_checkbox_checked', orange_checkbox.checked);
if (orange_checkbox.checked == false)
{
$color_subset_tables.each(function()
{
$(this).hide();
});
}
else
{
$color_subset_tables.each(function()
{
$(this).show();
});
}
break;
}
case RED:
{
GM_setValue('red_checkbox_checked', red_checkbox.checked);
if (red_checkbox.checked == false)
{
$color_subset_tables.each(function()
{
$(this).hide();
});
}
else
{
$color_subset_tables.each(function()
{
$(this).show();
});
}
break;
}
case BLUE:
{
GM_setValue('blue_checkbox_checked', blue_checkbox.checked);
if (blue_checkbox.checked == false)
{
$color_subset_tables.each(function()
{
$(this).hide();
});
}
else
{
$color_subset_tables.each(function()
{
$(this).show();
});
}
break;
}
}
}
function show_hide_all_colors()
{
show_hide_color(GREEN);
show_hide_color(YELLOW);
show_hide_color(ORANGE);
show_hide_color(RED);
show_hide_color(BLUE);
}
function create_colored_checkboxes()
{
var checkbox_div = document.createElement('DIV');
var green_div = document.createElement('DIV');
var yellow_div = document.createElement('DIV');
var orange_div = document.createElement('DIV');
var red_div = document.createElement('DIV');
var blue_div = document.createElement('DIV');
green_div.style.cssText = 'display:inline-block; background-color: '+GREEN+';'
yellow_div.style.cssText = 'display:inline-block; background-color: '+YELLOW+';'
orange_div.style.cssText = 'display:inline-block; background-color: '+ORANGE+';'
red_div.style.cssText = 'display:inline-block; background-color: '+RED+';'
blue_div.style.cssText = 'display:inline-block; background-color: '+BLUE+';'
green_checkbox = document.createElement('INPUT');
yellow_checkbox = document.createElement('INPUT');
orange_checkbox = document.createElement('INPUT');
red_checkbox = document.createElement('INPUT');
blue_checkbox = document.createElement('INPUT');
green_checkbox.type = 'checkbox';
yellow_checkbox.type = 'checkbox';
orange_checkbox.type = 'checkbox';
red_checkbox.type = 'checkbox';
blue_checkbox.type = 'checkbox';
green_checkbox.checked = GM_getValue('green_checkbox_checked', true);
yellow_checkbox.checked = GM_getValue('yellow_checkbox_checked', true);
orange_checkbox.checked = GM_getValue('orange_checkbox_checked', true);
red_checkbox.checked = GM_getValue('red_checkbox_checked', true);
blue_checkbox.checked = GM_getValue('blue_checkbox_checked', true);
green_checkbox.name = 'green_checkbox';
yellow_checkbox.name = 'yellow_checkbox';
orange_checkbox.name = 'orange_checkbox';
red_checkbox.name = 'red_checkbox';
blue_checkbox.name = 'blue_checkbox';
green_checkbox.title = 'Show/Hide green';
yellow_checkbox.title = 'Show/Hide yellow';
orange_checkbox.title = 'Show/Hide orange';
red_checkbox.title = 'Show/Hide red';
blue_checkbox.title = 'Show/Hide no TO';
green_checkbox.addEventListener('click', function(){show_hide_color(GREEN);});
yellow_checkbox.addEventListener('click', function(){show_hide_color(YELLOW);});
orange_checkbox.addEventListener('click', function(){show_hide_color(ORANGE);});
red_checkbox.addEventListener('click', function(){show_hide_color(RED);});
blue_checkbox.addEventListener('click', function(){show_hide_color(BLUE);});
green_div.appendChild(green_checkbox);
yellow_div.appendChild(yellow_checkbox);
orange_div.appendChild(orange_checkbox);
red_div.appendChild(red_checkbox);
blue_div.appendChild(blue_checkbox);
checkbox_div.align = 'center';
checkbox_div.appendChild(green_div);
checkbox_div.appendChild(yellow_div);
checkbox_div.appendChild(orange_div);
checkbox_div.appendChild(red_div);
checkbox_div.appendChild(blue_div);
return checkbox_div;
}
function color_code($parent_tables, api_base, requester_IDs_csv)
{
GM_xmlhttpRequest(
{
method: 'GET',
url: api_base+requester_IDs_csv,
timeout: TIMEOUT,
onload: function (results)
{
var rdata = $.parseJSON(results.responseText);
var checkbox_div = create_colored_checkboxes();
$('table[cellspacing="0"][cellpadding="0"][border="0"][style="margin:5px; clear:both;"]').eq(1).after(checkbox_div);
$parent_tables.each(function()
{
var $requester_ID_link = $(this).find('a[href^="/mturk/contact?subject="]').attr('href');
var requester_ID = $requester_ID_link.split(/=|&/)[3];
var title_row = $(this).find('tr').eq(1);
var link_bgcolor = $(this).find('td[width="100%"][valign="middle"][height="20"][align="left"]').attr('bgcolor');
var pdata = process_TO_data(rdata[requester_ID]);
var title_color = determine_color(pdata.average);
var qualified_for = !($(this).find('a[href^="/mturk/notqualified?"]').length > 0);
$(this).attr('title_color', title_color);
$(this).attr('qualified_for', qualified_for);
$(this).find('td[valign="middle"][nowrap=""][align="left"]').css('background-color', title_color);
$(this).find('td[valign="middle"][align="left"]').css('background-color', title_color);
$(this).find('td[width="100%"][valign="middle"][nowrap=""][align="right"]').css('background-color', title_color);
var link_href = REVIEWS_BASE + requester_ID;
var link_text = pdata.reviews + ((pdata.reviews != 1) ? ' reviews ' : ' review ');
link_text = '['+link_text + '|pay: '+pdata.pay_rnd+'|fair: '+pdata.fair_rnd+'|comm: '+pdata.comm_rnd+'|fast: '+pdata.fast_rnd+'|tos: '+pdata.tos+']';
var link = '<a href="'+link_href+'" target="_blank">'+link_text+'</a> ';
title_row.after('<tr><td width="1" valign="middle" bgcolor="#336699" align="center"></td><td width="18" valign="middle" bgcolor="'+link_bgcolor+'" align="center"></td><td width="100%" valign="top" bgcolor="'+title_color+'" align="right">'+link+'</td><td width="8" valign="middle" bgcolor="'+link_bgcolor+'" align="center"></td><td width="1" valign="middle" bgcolor="#336699" align="center"></td></tr>');
// after the API update, this if isn't necessary. leaving it in until
// sure API is stable
var pay = 0;
if (rdata[requester_ID])
{
pay = rdata[requester_ID].attrs.pay;
}
var pay_color = determine_color(pay);
//var pay_color = determine_color(rdata[requester_ID].attrs.pay);
$(this).find('span[class="reward"]').css('background-color', pay_color);
// highlight Masters HITs title and link
var is_masters = $(this).find('td[style="padding-right: 2em; white-space: nowrap;"]:contains("Masters")').length > 0;
if (is_masters)
{
$(this).find('td[valign="middle"][nowrap=""][align="left"]').css('background-color', MASTERS);
$(this).find('a[href^="/mturk/preview?groupId="]').css('background-color', MASTERS);
}
});
show_hide_all_colors();
},
ontimeout: function()
{
if (api_base == API_MULTI_ATTRS_URL)
{ // tried main api server and failed, now try mirror
color_code($parent_tables, API_PROXY_MULTI_ATTRS_URL, requester_IDs_csv);
}
else
{ // tried mirror and failed, add basic link to reviews and checkpoints
$parent_tables.each(function()
{
var $requester_ID_link = $(this).find('a[href^="/mturk/contact?subject="]').attr('href');
var requester_ID = $requester_ID_link.split(/=|&/)[3];
var title_row = $(this).find('tr').eq(1);
var link_bgcolor = $(this).find('td[width="100%"][valign="middle"][height="20"][align="left"]').attr('bgcolor');
var link_href = REVIEWS_BASE + requester_ID;
var link_text = 'Turkopticon reviews';
var link = '<a href="'+link_href+'" target="_blank">'+link_text+'</a> ';
title_row.after('<tr><td width="1" valign="middle" bgcolor="#336699" align="center"></td><td width="18" valign="middle" bgcolor="'+link_bgcolor+'" align="center"></td><td width="100%" valign="top" bgcolor="'+link_bgcolor+'" align="right">'+link+'</td><td width="8" valign="middle" bgcolor="'+link_bgcolor+'" align="center"></td><td width="1" valign="middle" bgcolor="#336699" align="center"></td></tr>');
});
}
},
onerror: function()
{
if (api_base == API_MULTI_ATTRS_URL)
{ // tried main api server and failed, now try mirror
color_code($parent_tables, API_PROXY_MULTI_ATTRS_URL, requester_IDs_csv);
}
else
{ // tried mirror and failed, add basic link to reviews and checkpoints
$parent_tables.each(function()
{
var $requester_ID_link = $(this).find('a[href^="/mturk/contact?subject="]').attr('href');
var requester_ID = $requester_ID_link.split(/=|&/)[3];
var title_row = $(this).find('tr').eq(1);
var link_bgcolor = $(this).find('td[width="100%"][valign="middle"][height="20"][align="left"]').attr('bgcolor');
var link_href = REVIEWS_BASE + requester_ID;
var link_text = 'Turkopticon reviews';
var link = '<a href="'+link_href+'" target="_blank">'+link_text+'</a> ';
title_row.after('<tr><td width="1" valign="middle" bgcolor="#336699" align="center"></td><td width="18" valign="middle" bgcolor="'+link_bgcolor+'" align="center"></td><td width="100%" valign="top" bgcolor="'+link_bgcolor+'" align="right">'+link+'</td><td width="8" valign="middle" bgcolor="'+link_bgcolor+'" align="center"></td><td width="1" valign="middle" bgcolor="#336699" align="center"></td></tr>');
});
}
}
});
}
//$(document).ready(function()
//{
var is_HIT = $('input[type="hidden"][name="isAccepted"]').length > 0;
if (is_HIT)
{
throw new Error('Not on a search page. Exit.');
}
// change visited link color to make it easier to differentiate from unvisited link
// code snippet from http://stackoverflow.com/questions/7030289/how-to-set-link-visited-color-in-jquery
var visited_link_styling = '<style> a:visited {color:'+VISITED_LINK+';} </style>';
$('head').append(visited_link_styling);
// end snippet
if (SHOW_ALL_DETAILS)
{
// click 'Show all details'
$(window).load(function(){$('a[id="expandall"][class="footer_links"][href="#"]:contains("Show all details")').get(0).click();});
}
var requester_IDs = new Array();
$parent_tables = $('table[width="100%"][cellspacing="0"][cellpadding="0"][border="0"][height="100%"]');
$parent_tables.each(function()
{
var $requester_ID_link = $(this).find('a[href^="/mturk/contact?subject="]').attr('href');
requester_IDs.push($requester_ID_link.split(/=|&/)[3]);
});
// code snippet from http://stackoverflow.com/questions/5381621/jquery-function-to-get-all-unique-elements-from-an-array
requester_IDs = requester_IDs.filter(function(itm,i,a)
{
return i==a.indexOf(itm);
});
// end snippet
var requester_IDs_csv = '';
for (var i = 0; i < requester_IDs.length-1; i++)
{
requester_IDs_csv += requester_IDs[i] + ','
}
requester_IDs_csv += requester_IDs[i];
color_code($parent_tables, API_MULTI_ATTRS_URL, requester_IDs_csv);
//});