turkopticon-async

Review requesters on Amazon Mechanical Turk

Versão de: 15/12/2015. Veja: a última versão.

// ==UserScript==
// @name           turkopticon-async
// @version        2015.11.18.1002
// @description    Review requesters on Amazon Mechanical Turk
// @author         feihtality
// @include        https://*.mturk.com/*
// @exclude        https://*.mturk.com/mturk/findhits?match=true?hit_scraper*
// @namespace      https://greasyfork.org/users/12709
// ==/UserScript==
/*jshint esnext:true*/

/* 
 *
 * fork of 'turkopticon' Lilly Irani and Six Silberman --
 * * turkopticon-async requests data from the Turkopticon servers asynchronously which improves
 *   performance and prevents the page from locking up until the request completes
 * * other minor refactoring
 *
 */

(function() {
    'use strict';
    
    var TURKOPTICON_BASE = "https://turkopticon.ucsd.edu/";
    var API_BASE = "https://turkopticon.ucsd.edu/api/";
    var API_MULTI_ATTRS_URL = API_BASE + "multi-attrs.php?ids=";

    function makeXhrQuery(rai) {
        return new Promise( function(accept, reject) {
            var xhr = new XMLHttpRequest(), url = API_MULTI_ATTRS_URL + Object.keys(rai).join(',');
            xhr.open('GET', url, true);
            xhr.responseType = 'json';
            xhr.send();
            xhr.onload = e => accept(e.target.response);
            xhr.onerror = xhr.ontimeout = e => reject(e.target);
        }); }

    function ul(cl, inner) {
        return "<ul class='" + cl + "'>" + inner + "</ul>"; }

    function li(cl, inner) {
        return "<li class='" + cl + "'>" + inner + "</li>"; }

    function span(cl, inner) {
        return "<span class='" + cl + "'>" + inner + "</span>"; }

    function pad(word, space) {
        if (word.length >= space) { return word; }
        else { return word + '&nbsp;'.repeat(space - word.length); } }

    function long_word(word) {
        switch(word) {
            case "comm": return "communicativity";
            case "pay" : return "generosity";
            case "fair": return "fairness";
            case "fast": return "promptness"; } }

    function attr_html(n, i) {
        var bar = `<meter min="0.8" low="2.5" high="3.4" optimum="5" max="5" value=${i} style="width:120px"></meter>`;
        return pad(long_word(n), 15) + ": " + bar + "&nbsp;" + i + " / 5"; }

    function ro_html(ro) {
        var rohtml = [];
        if (typeof ro.attrs !== 'undefined') {
            var keys = Object.keys(ro.attrs);
            for (var k of keys) {
                rohtml.push( li("attr", attr_html(k, ro.attrs[k])) ); } }
        return rohtml.join(''); }

    function what(ro) {
        var str = "";
        if (typeof ro.attrs != 'undefined') {
            str =  li("gray_link", "<a href='" + TURKOPTICON_BASE + "help#attr'>What do these scores mean?</a>"); }
        return str; }

    function nrs(rid, nrevs) {
        var str = "";
        if (typeof nrevs === 'undefined') {
            str = "<li>No reviews for this requester</li>"; }
        else { str = "<li>Scores based on <a href='" + TURKOPTICON_BASE + rid + "'>" + nrevs + " reviews</a></li>"; }
        return str; }

    function tos(tosflags) {
        var str = "<li>Terms of Service violation flags: " + tosflags + "</li>";
        return str; }

    function rl(rid, name) {
        var _rl = "<li><a href='" + TURKOPTICON_BASE + "report?requester[amzn_id]=" + rid;
        _rl    += "&requester[amzn_name]=" + name + "'>";
        _rl    += "Report your experience with this requester &raquo;</a></li>";
        return _rl; }

    function dropDown(ro, rid) {
        var n = ro.name;
        var arrcls = "";
        if (typeof ro.attrs != 'undefined') { arrcls = "toc"; }
        var dd = ul("tob", li(arrcls, "&#9660;") + ul("tom", ro_html(ro) + what(ro) + nrs(rid, ro.reviews) + tos(ro.tos_flags) + rl(rid, n)));
        return dd; }

    function insertInlineCss() {
        var css = "<style type='text/css'>\n"
           + ".tob, .tom { list-style-type: none; padding-left: 0; }\n"
           + ".tob { float: left; margin-right: 5px; }\n"
           + ".tob > .tom { display: none; position: absolute; background-color: #ebe5ff; border: 1px solid #aaa; padding: 5px; }\n"
           + ".tob:hover > .tom { display: block; }\n"
           + ".tob > li { border: 1px solid #9db9d1; background-color: #ebe5ff; color: #00c; padding: 3px 3px 1px 3px; }\n"
           + ".tob > li.toc { color: #f33; }\n"
           + "@media screen and (-webkit-min-device-pixel-ratio:0) { \n .tob { margin-top: -5px; } \n}\n"
           + ".attr { font-family: Monaco, Courier, monospace; color: #333; }\n"
           + ".bar { font-size: 0.6em; }\n"
           + ".gray_link { margin-bottom: 15px; }\n"
           + ".gray_link a { color: #666; }\n"
           + "</style>";
        document.head.innerHTML = css + document.head.innerHTML; }

    function getNames(rai, resp) {
        for(var rid in rai) { if (rai.hasOwnProperty(rid)) {
            if (resp[rid] === "")  // empty response, no data in Turkopticon DB for this ID
                resp[rid] = {}; 
            resp[rid].name = rai[rid][0].name;  // overwrite name attribute of response object from page
        }} 
        return resp; }

    function insertDropDowns(rai, resp) {
        for(var rid in rai) {
            if (rai.hasOwnProperty(rid)) {
                for(var i = 0; i < rai[rid].length; i++) {
                    var td = rai[rid][i].node;
                    td.innerHTML = dropDown(resp[rid], rid) + " "  + td.innerHTML; } } } }

    function getAnchors() {
        var _a = {}, _id, _name;
        try { // search page
            Array.from(document.querySelectorAll('.requesterIdentity')).forEach( v => {
                _id = v.parentNode.href.match(/Id=(.+)$/)[1]; _name = v.textContent;
                if (!(_id in _a)) _a[_id] = [];
                _a[_id].push({name: _name, node: v.parentNode.parentNode});
            }); if (!Object.keys(_a).length) throw 0;
        } catch(err) { 
            try { // preview page
                var node = document.querySelector('a[id|="requester.tooltip"]').parentNode.nextElementSibling;
                _id = document.querySelector('input[name=requesterId]').value;
                _name = document.querySelector('input[name=prevRequester]').value;
                _a[_id] = [{name: _name, node: node}];
            } catch(errr) { _a = null; }
        } return _a;
    }

    insertInlineCss();
    var anchors = getAnchors();
    //console.log(anchors);
    if (anchors) {
        makeXhrQuery(anchors).then(function(r) {
            var resp = getNames(anchors, r);
            insertDropDowns(anchors, resp);
        }, err => console.warn(err.statusText, err));
    }
    
})();