Last active
July 20, 2019 21:20
-
-
Save cuylerstuwe/0e91c22eb717f0fe88109a0cdd539b33 to your computer and use it in GitHub Desktop.
mTurk Batches - Cents-Per-Word/Decision Estimate
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ==UserScript== | |
// @name mTurk Batches - Cents-Per-Word/Decision Estimate (for generic, single-page, instant-load batch HITs) | |
// @namespace salembeats | |
// @version 1.2 | |
// @description Display a quick heads-up estimate of how many cents-per-decision a given mTurk batch job offers. | |
// @author Cuyler Stuwe (salembeats) | |
// @include https://worker.mturk.com/projects/* | |
// @include https://www.mturkcontent.com/dynamic/hit?assignmentId=* | |
// @grant none | |
// ==/UserScript== | |
async function parentMain() { | |
window.addEventListener("message", e => { | |
if(e.data.askForHitValue) { | |
const hitValue = +document.querySelectorAll(".detail-bar-value")[3].innerText.replace("$", ""); | |
e.source.postMessage({hitValue}, "*"); | |
} | |
}); | |
} | |
async function frameMain() { | |
const lowercaseBodyText = document.body.innerText.toLowerCase(); | |
const isHintedAsSurvey = () => ( | |
document.querySelector("a[href*='qualtrics']") || // Qualtrics | |
["survey", "completion code"].some(keyword => lowercaseBodyText.includes(keyword)) || // Keywords | |
document.querySelector("#surveycode") || // Stock mTurk Template | |
document.querySelector(".takesurveyform") // TurkPrime | |
); | |
if(isHintedAsSurvey()) { return; } | |
const countOfSingleChoiceElements = ( | |
[ | |
"input[type='checkbox']", | |
"input[type='text']", | |
"input[type='button']" | |
].reduce((sum, selector) => ( | |
document.querySelectorAll(selector).length + sum | |
), 0) | |
); | |
const countOfRadioGroups = ( | |
[...document.querySelectorAll("input[type='radio'][name]")] | |
.reduce((set, namedRadioEl) => ( | |
set.add(namedRadioEl.getAttribute("name")) | |
), new Set()) | |
.size | |
); | |
const countOfAwsButtonGroups = document.querySelectorAll(".btn-group").length; | |
const countOfFreeformInputs = ["input[type='text']", "textarea", "input:not([type])", "crowd-input"].reduce( | |
(sum, selector) => sum + document.querySelectorAll(selector).length, | |
0 | |
); | |
const numberOfChoices = countOfSingleChoiceElements + countOfRadioGroups + countOfAwsButtonGroups + countOfFreeformInputs; | |
console.log("noc", numberOfChoices) | |
if(numberOfChoices === 0) { return; } | |
const hitValue = await new Promise(resolve => { | |
const messageListener = e => { | |
if(e.data.hitValue) { | |
window.removeEventListener("message", messageListener); | |
resolve(e.data.hitValue); | |
} | |
}; | |
window.addEventListener("message", messageListener); | |
window.parent.postMessage({askForHitValue: true}, "*"); | |
}); | |
const centsPerDecision = ((hitValue / numberOfChoices) * 100).toFixed(1); | |
const wordCountEstimate = document.body.innerText.split(" ").length; | |
const centsPerHundredWords = ((hitValue / (wordCountEstimate / 100)) * 100).toFixed(1); | |
document.body.insertAdjacentHTML("afterbegin", ` | |
<style> | |
.estimate_container { | |
border: 1px dotted black; | |
padding: 2px; | |
margin: 2px; | |
display: flex; | |
flex-direction: column; | |
align-items: flex-end; | |
} | |
.action_type { | |
color: rgb(96, 96, 96); | |
} | |
.cents_per_decision_line { | |
} | |
.cents_per_word_line { | |
} | |
.major_value { | |
padding: 2px; | |
font-weight: bold; | |
border-left: 1px dotted rgb(64, 64, 64); | |
border-right: 1px dotted rgb(64, 64, 64); | |
} | |
.minor_value { | |
padding: 1px; | |
border-bottom: 1px dotted rgb(64, 64, 64); | |
} | |
.normal_breakdown_line { | |
} | |
.freeform_input_warning_line { | |
background: rgba(255, 255, 0, 0.3); | |
} | |
</style> | |
<div class="estimate_container"> | |
<div class="cents_per_word_line"> | |
<strong>CPW</strong> (<span class="action_type">Reading</span>): | |
<span class="major_value">${centsPerHundredWords}</span> Cents Per 100 Words. | |
</div> | |
<div class="cents_per_decision_line"> | |
<strong>CPD</strong> (<span class="action_type">Doing</span>): | |
<span class="major_value">${centsPerDecision}</span> Cents Per Decision. | |
</div> | |
<div class="normal_breakdown_line"> | |
<span class="minor_value">${countOfSingleChoiceElements}</span> x Single-Choice, | |
<span class="minor_value">${countOfRadioGroups}</span> x Radio Group, | |
<span class="minor_value">${countOfAwsButtonGroups}</span> x AWS Button Group. | |
</div> | |
<div class="freeform_input_warning_line"> | |
⚠ <span class="minor_value">${countOfFreeformInputs}</span> x Text Input. | |
</div> | |
</div> | |
`); | |
[...document.querySelectorAll(".estimate_container")].slice(1).forEach(extraEstimateContainer => extraEstimateContainer.remove()); | |
} | |
async function main() { | |
if(window.location.href.includes("worker.mturk.com")) { | |
parentMain(); | |
} | |
else { | |
frameMain(); | |
new MutationObserver(mutations => { | |
if(!document.querySelector(".estimate_container")) { | |
frameMain(); | |
} | |
}).observe(document.body, {childList: true, subtree: true, attributes: true}); | |
} | |
} | |
main(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment