turkopticon-async

Review requesters on Amazon Mechanical Turk

当前为 2015-12-22 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name turkopticon-async
  3. // @version 2015.11.18.1003
  4. // @description Review requesters on Amazon Mechanical Turk
  5. // @author feihtality
  6. // @include https://*.mturk.com/*
  7. // @exclude https://*.mturk.com/mturk/findhits?match=true?hit_scraper*
  8. // @namespace https://greasyfork.org/users/12709
  9. // ==/UserScript==
  10. /*jshint esnext:true*/
  11.  
  12. /*
  13. *
  14. * fork of 'turkopticon' Lilly Irani and Six Silberman --
  15. * * turkopticon-async requests data from the Turkopticon servers asynchronously which improves
  16. * performance and prevents the page from locking up until the request completes
  17. * * other minor refactoring
  18. *
  19. */
  20.  
  21. (function() {
  22. 'use strict';
  23. var TURKOPTICON_BASE = "https://turkopticon.ucsd.edu/";
  24. var API_BASE = "https://turkopticon.ucsd.edu/api/";
  25. var API_MULTI_ATTRS_URL = API_BASE + "multi-attrs.php?ids=";
  26.  
  27. function makeXhrQuery(rai) {
  28. return new Promise( function(accept, reject) {
  29. var xhr = new XMLHttpRequest(), url = API_MULTI_ATTRS_URL + Object.keys(rai).join(',');
  30. xhr.open('GET', url, true);
  31. xhr.responseType = 'json';
  32. xhr.send();
  33. xhr.onload = e => accept(e.target.response);
  34. xhr.onerror = xhr.ontimeout = e => reject(e.target);
  35. }); }
  36.  
  37. function ul(cl, inner) {
  38. return "<ul class='" + cl + "'>" + inner + "</ul>"; }
  39.  
  40. function li(cl, inner) {
  41. return "<li class='" + cl + "'>" + inner + "</li>"; }
  42.  
  43. function span(cl, inner) {
  44. return "<span class='" + cl + "'>" + inner + "</span>"; }
  45.  
  46. function pad(word, space) {
  47. if (word.length >= space) { return word; }
  48. else { return word + '&nbsp;'.repeat(space - word.length); } }
  49.  
  50. function long_word(word) {
  51. switch(word) {
  52. case "comm": return "communicativity";
  53. case "pay" : return "generosity";
  54. case "fair": return "fairness";
  55. case "fast": return "promptness"; } }
  56.  
  57. function attr_html(n, i) {
  58. var bar = `<meter min="0.8" low="2.5" high="3.4" optimum="5" max="5" value=${i} style="width:120px"></meter>`;
  59. return pad(long_word(n), 15) + ": " + bar + "&nbsp;" + i + " / 5"; }
  60.  
  61. function ro_html(ro) {
  62. var rohtml = [];
  63. if (typeof ro.attrs !== 'undefined') {
  64. var keys = Object.keys(ro.attrs);
  65. for (var k of keys) {
  66. rohtml.push( li("attr", attr_html(k, ro.attrs[k])) ); } }
  67. return rohtml.join(''); }
  68.  
  69. function what(ro) {
  70. var str = "";
  71. if (typeof ro.attrs != 'undefined') {
  72. str = li("gray_link", "<a href='" + TURKOPTICON_BASE + "help#attr'>What do these scores mean?</a>"); }
  73. return str; }
  74.  
  75. function nrs(rid, nrevs) {
  76. var str = "";
  77. if (typeof nrevs === 'undefined') {
  78. str = "<li>No reviews for this requester</li>"; }
  79. else { str = "<li>Scores based on <a href='" + TURKOPTICON_BASE + rid + "'>" + nrevs + " reviews</a></li>"; }
  80. return str; }
  81.  
  82. function tos(tosflags) {
  83. var str = "<li>Terms of Service violation flags: " + tosflags + "</li>";
  84. return str; }
  85.  
  86. function rl(rid, name) {
  87. var _rl = "<li><a href='" + TURKOPTICON_BASE + "report?requester[amzn_id]=" + rid;
  88. _rl += "&requester[amzn_name]=" + name + "'>";
  89. _rl += "Report your experience with this requester &raquo;</a></li>";
  90. return _rl; }
  91.  
  92. function dropDown(ro, rid) {
  93. var n = ro.name;
  94. var arrcls = "";
  95. if (typeof ro.attrs != 'undefined') { arrcls = "toc"; }
  96. 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)));
  97. return dd; }
  98.  
  99. function insertInlineCss() {
  100. var css = "<style type='text/css'>\n"
  101. + ".tob, .tom { list-style-type: none; padding-left: 0; }\n"
  102. + ".tob { float: left; margin-right: 5px; margin-top: -5px;}\n"
  103. + ".tob > .tom { display: none; position: absolute; background-color: #ebe5ff; border: 1px solid #aaa; padding: 5px; }\n"
  104. + ".tob:hover > .tom { display: block; }\n"
  105. + ".tob > li { border: 1px solid #9db9d1; background-color: #ebe5ff; color: #00c; padding: 3px 3px 1px 3px; }\n"
  106. + ".tob > li.toc { color: #f33; }\n"
  107. //+ "@media screen and (-webkit-min-device-pixel-ratio:0) { \n .tob { margin-top: -5px; } \n}\n"
  108. + ".attr { font-family: Monaco, Courier, monospace; color: #333; }\n"
  109. + ".bar { font-size: 0.6em; }\n"
  110. + ".gray_link { margin-bottom: 15px; }\n"
  111. + ".gray_link a { color: #666; }\n"
  112. + "</style>";
  113. document.head.innerHTML = css + document.head.innerHTML; }
  114.  
  115. function getNames(rai, resp) {
  116. for(var rid in rai) { if (rai.hasOwnProperty(rid)) {
  117. if (resp[rid] === "") // empty response, no data in Turkopticon DB for this ID
  118. resp[rid] = {};
  119. resp[rid].name = rai[rid][0].name; // overwrite name attribute of response object from page
  120. }}
  121. return resp; }
  122.  
  123. function insertDropDowns(rai, resp) {
  124. for(var rid in rai) {
  125. if (rai.hasOwnProperty(rid)) {
  126. for(var i = 0; i < rai[rid].length; i++) {
  127. var td = rai[rid][i].node;
  128. td.innerHTML = dropDown(resp[rid], rid) + " " + td.innerHTML; } } } }
  129.  
  130. function getAnchors() {
  131. var _a = {}, _id, _name;
  132. try { // search page
  133. Array.from(document.querySelectorAll('.requesterIdentity')).forEach( v => {
  134. _id = v.parentNode.href.match(/Id=(.+)$/)[1]; _name = v.textContent;
  135. if (!(_id in _a)) _a[_id] = [];
  136. _a[_id].push({name: _name, node: v.parentNode.parentNode});
  137. }); if (!Object.keys(_a).length) throw 0;
  138. } catch(err) {
  139. try { // preview page
  140. var node = document.querySelector('a[id|="requester.tooltip"]').parentNode.nextElementSibling;
  141. _id = document.querySelector('input[name=requesterId]').value;
  142. _name = document.querySelector('input[name=prevRequester]').value;
  143. _a[_id] = [{name: _name, node: node}];
  144. } catch(errr) { _a = null; }
  145. } return _a;
  146. }
  147.  
  148. insertInlineCss();
  149. var anchors = getAnchors();
  150. //console.log(anchors);
  151. if (anchors) {
  152. makeXhrQuery(anchors).then(function(r) {
  153. var resp = getNames(anchors, r);
  154. insertDropDowns(anchors, resp);
  155. }, err => console.warn(err.statusText, err));
  156. }
  157. })();