vBulletin
Show a button in the results to export the specified HIT with vBulletin formatted text to share on forums.
IRC
Show a button in the results to export the specified HIT streamlined for sharing on IRC.
Reddit
Show a button in the results to export the specified HIT for sharing on Reddit, formatted to
r/HITsWorthTurkingFor standards.
Color Type
simple HIT Scraper will use a simple weighted average to
determine the overall TO rating and colorize results using that value. Use this setting to make coloring consistent between
HIT Scraper and Color Coded Search.
adjusted HIT Scraper will calculate a Bayesian adjusted average
based on confidence of the TO rating to colorize results. Confidence is proportional to the number of reviews.
Sort Type
simple
HIT Scraper will sort results based simply on value regardless of the number of reviews.
adjusted HIT Scraper will use a Bayesian adjusted rating
based on reliability (i.e. confidence) of the data. It factors in the number of reviews such that, for example,
a requester with 100 reviews rated at 4.6 will rightfully be ranked higher than a requester with 3 reviews rated at 5.
This gives a more accurate representation of the data.
TO Weighting
Specify weights for TO attributes to place greater importance on certain attributes over others.
The default values, [1, 3, 3, 1], ensure consistency between HIT Scraper and
Color Coded Search;
recommended values for adjusted coloring are [1, 6, 3.5, 1].
`,//}}}
_appearance =//{{{
`
Display Checkboxes
show
Shows all checkboxes and radio inputs on the control panel for sake of clarity.
hide
Hides checkboxes and radio inputs for a cleaner, neater appearance. Their visibility is not required for proper
operation; all options can still be toggled while hidden.
Themes
HIT Coloring
link
Apply coloring based on Turkopticon reviews to all applicable links in the results table.
cell
Apply coloring based on Turkopticon reviews to the background of all applicable cells in the results table.
Note: The Classic theme is exempt from these settings and will always colorize cells.
`,//}}}
_blocks = //{{{
`
Advanced Matching
Allows for the use of asterisks (*) as wildcards in the blocklist for simple glob matching. Any blocklist entry
without an asterisk is treated the same as the default behavior--the entry must exactly match a HIT title or requester to
trigger a block.
Wildcards have the potential to block more HITs than intended if using a pattern that's too generic.
Matching is not case sensitive regardless of the wildcard setting. Entries without an opening asterisk are
expected to match the beginning of a line, likewise, entries without a closing asterisk are expected to match
the end of a line. Example usage below.
Matches
Does not match
Notes
foo*baz
foo bar bat baz
bar foo bat baz
no leading or closing asterisks; foo must be at the start of a line,
and baz must be at the end of a line for a positive match
foobarbatbaz
foo bar bat
*foo
bar baz foo
foo baz
matches and blocks any line ending in foo
foo*
foo bat bar
bat foo baz
matches and blocks any line beginning with foo
*bar*
foo bar bat baz
foo bat baz
matches and blocks any line containing bar
bar bat baz
foo bar
foobatbarbaz
** foo
** foo
** foo bar baz
Multiple consecutive asterisks will be treated as a string rather than a wildcard. This makes it
compatible with HITs using multiple asterisks in their titles, e.g., *** contains peanuts ***.
** *bar* ***
** foo bar baz bat ***
foo bar baz
Consecutive asterisks used in conjunction with single asterisks.
*
nothing
all
A single asterisk would usually match anything and everything,
but here, it matches nothing. This prevents accidentally blocking everything from the results table.
`,//}}}
_notify = //{{{
`
Additional Notifications
blink
Blink the tab when there are new HITs.
taskbar
Create an HTML5 browser notification when there are new HITs, which appears over the taskbar for 10 seconds.
Note: These notification options will only apply when the page does not have active focus.
`,//}}}
_main = //{{{
`
GeneralAppearanceBlocklistNotifications
${_general}
${_appearance}
${_blocks}
${_notify}
`;//}}}
this.main = document.body.appendChild(document.createElement('DIV'));
this.main.id = 'settingsMain';
this.main.innerHTML = _main;
return this;
},//}}} Settings::draw
init: function() {//{{{
var get = (q,all) => this.main['querySelector' + (all ? 'All': '')](q),
sidebarFn = function(e) {
if (e.target.classList.contains('settingsSelected')) return;
get('#'+get('.settingsSelected').textContent).style.display = 'none';
get('.settingsSelected').classList.toggle('settingsSelected');
e.target.classList.toggle('settingsSelected');
get('#'+e.target.textContent).style.display = 'block';
}.bind(this),
optChangeFn = function(e) {//{{{
var tag = e.target.tagName, type = e.target.type, id = e.target.id,
isChecked = e.target.checked, name = e.target.name, value = e.target.value;
switch(tag) {
case 'SELECT':
get('#thedit').textContent = value === 'random' ? 'Re-roll!' : 'Edit Current Theme';
this.user.themes.name = value;
Themes.apply(value, this.user.hitColor);
break;
case 'INPUT':
switch(type) {
case 'radio':
if (name === 'checkbox') {
this.user.showCheckboxes = (value === 'true');
Array.from(document.querySelectorAll('#controlpanel input[type=checkbox],#controlpanel input[type=radio]'))
.forEach(v => v.classList.toggle('hidden'));
}
else this.user[name] = value;
if (name === 'hitColor') Themes.apply(this.user.themes.name, value);
break;
case 'checkbox':
this.user[id] = isChecked;
if (name === 'export')
Array.from(document.querySelectorAll(`button.${value}`))
.forEach(v => v.style.display = isChecked ? '' : 'none');
if (id === 'notifyTaskbar' && isChecked && Notification.permission === 'default')
Notification.requestPermission();
break;
case 'number':
this.user.toWeights[id] = value; break;
} break;
}
Settings.save();
}.bind(this);//}}}
get('#settingsClose').onclick = this.die.bind(this);
get('#General').style.display = 'block';
Array.from(get('#settingsSidebar span', true)).forEach(v => v.onclick = sidebarFn);
Array.from(get('input,select',true)).forEach(v => v.onchange = optChangeFn);
get('#thedit').onclick = () => { this.die.call(this); new Editor('theme'); };
},//}}} Settings::init
die: function() { Interface.toggleOverflow('off'); this.main.remove(); }
},//}}} Settings
Themes = {//{{{
default: defaults.themes,
generateCSS: function(theme, mode) {//{{{
var ref = theme === 'random' ? this.randomize() : Settings.user.themes.colors[theme],
_ms = mode === 'cell' || theme === 'classic',
cellFix = {
row: k => `.${k} ` + (_ms ? '{background:' : 'a {color:') + ref[k] + '}',
text: k => `.${k} {color:` + (_ms ? this.tune(ref.bodytable,ref[k]) : ref.bodytable) + '}',
export: k => `.${k} button {color:` + (_ms ? this.tune(ref.export,ref[k]) : ref.export) + '}',
vlink: k => `.${k} a:not(.static):visited {color:` + (_ms ? this.tune(ref.vlink,ref[k]) : ref.vlink) + '}'
},
css = `body {color:${ref.defaultText}; background-color:${ref.background}}
/*#status {color:${ref.secondText}}*/
#sortdirs {color:${ref.inputText}}
#curtain {background:${ref.background}; opacity:0.5}
.controlpanel i:after {color:${ref.accent}}
#controlpanel {background:${ref.cpBackground}}
#controlpanel input${theme === 'classic' ? '' : ', #controlpanel select'}
{color:${ref.inputText}; border:1px solid; background:${theme === 'classic' ? '#fff' : ref.cpBackground}}
#controlpanel label {color:${ref.defaultText}; background:${ref.cpBackground}}
#controlpanel label:hover {background:${ref.hover}}
#controlpanel label.checked {color:${ref.secondText}; background:${ref.highlight}}
/*#resultsTable tbody a:not(.static):visited {color:${ref.vlink}}*/
/*#resultsTable button {color:${ref.export}}*/
thead, caption, a {color:${ref.defaultText}}
tbody a {color:${ref.link}}
.nohitDB {color:#000; background:${ref.nohitDB}}
.hitDB {color:#000; background:${ref.hitDB}}
.reqmaster {color:#000; background:${ref.reqmaster}}
.nomaster {color:#000; background:${ref.nomaster}}
.tooweak {background:${ref.unqualified}}
${cellFix.row('toNone')} ${cellFix.text('toNone')} ${cellFix.export('toNone')} ${cellFix.vlink('toNone')}
${cellFix.row('toHigh')} ${cellFix.text('toHigh')} ${cellFix.export('toHigh')} ${cellFix.vlink('toHigh')}
${cellFix.row('toGood')} ${cellFix.text('toGood')} ${cellFix.export('toGood')} ${cellFix.vlink('toGood')}
${cellFix.row('toAverage')} ${cellFix.text('toAverage')} ${cellFix.export('toAverage')} ${cellFix.vlink('toAverage')}
${cellFix.row('toLow')} ${cellFix.text('toLow')} ${cellFix.export('toLow')} ${cellFix.vlink('toLow')}
${cellFix.row('toPoor')} ${cellFix.text('toPoor')} ${cellFix.export('toPoor')} ${cellFix.vlink('toPoor')}`;
if (theme !== 'classic') css += `\n.controlpanel button {color:${ref.accent}; background:transparent;}`;
return css;
},//}}} Themes::generateCSS
tune: function(fg,bg) {//{{{
var cbg = this.getBrightness(bg),
lighten = c => { c.s = Math.max(0, c.s-5); c.v = Math.min(100, c.v+5); return c; },
darken = c => { c.s = Math.min(100, c.s+5); c.v = Math.max(0, c.v-5); return c; },
tune = (function() { if (cbg >= 128) return darken; else return lighten; })(),
hex2hsv = function(c) {//{{{
var r = parseInt(c.slice(1,3),16), g = parseInt(c.slice(3,5),16), b = parseInt(c.slice(5,7),16),
min = Math.min(r,g,b), max = Math.max(r,g,b), delta = max-min, _hue;
switch(max) {
case r: _hue = Math.round(60 * (g - b)/delta); break;
case g: _hue = Math.round(120 + 60 * (b - r)/delta); break;
case b: _hue = Math.round(240 + 60 * (r - g)/delta); break;
}
return { h:_hue < 0 ? _hue + 360 : _hue, s:max === 0 ? 0 : Math.round(100 * delta/max), v:Math.round(max * 100/255) };
}, //}}}
hsv2hex = function(c) {//{{{
var r, g, b, pad = s => ('00'+s.toString(16)).slice(-2);
if (c.s === 0) r = g = b = Math.round(c.v * 2.55).toString(16);
else {
c = { h: c.h/60, s: c.s/100, v: c.v/100 }; // convert to prime to calc chroma
var _t1 = Math.round((c.v * (1 - c.s)) * 255),
_t2 = Math.round((c.v * (1 - c.s * (c.h - Math.floor(c.h)))) * 255),
_t3 = Math.round((c.v * (1 - c.s * (1 - (c.h - Math.floor(c.h))))) * 255);
switch (Math.floor(c.h)) {
case 1: r = _t2; g = Math.round(c.v * 255); b = _t1; break;
case 2: r = _t1; g = Math.round(c.v * 255); b = _t3; break;
case 3: r = _t1; g = _t2; b = Math.round(c.v * 255); break;
case 4: r = _t3; g = _t1; b = Math.round(c.v * 255); break;
case 0: r = Math.round(c.v * 255); g = _t3; b = _t1; break;
default: r = Math.round(c.v * 255); g = _t1; b = _t2; break;
}
} return '#' + pad(r) + pad(g) + pad(b);
};//}}}
while (Math.abs(this.getBrightness(fg)-cbg) < 90) fg = hsv2hex(tune(hex2hsv(fg)));
return fg;
},//}}}
getBrightness: function(hex) {//{{{
// TODO: put in Colors object
var r = parseInt(hex.slice(1,3),16), g = parseInt(hex.slice(3,5),16), b = parseInt(hex.slice(5,7),16);
return ((r*299) + (g*587) + (b*114))/1000;
},//}}} Themes::getBrightness
apply: function(theme, mode) {//{{{
var cssNew = URL.createObjectURL(new Blob([this.generateCSS(theme, mode)], {type:'text/css'})),
rel = document.head.querySelector('link[rel=stylesheet]'), cssOld = rel.href;
rel.href = cssNew;
URL.revokeObjectURL(cssOld);
},//}}} Themes::apply
},//}}} Themes
Interface = {//{{{
user: Settings.user, time: Date.now(), focused: true, blackhole: {},
isLoggedout: document.querySelector('#lnkWorkerSignin') ? true : false,
resetTitle: function() {//{{{
if (this.blackhole.blink) clearInterval(this.blackhole.blink);
document.title = DOC_TITLE;
},//}}}
toggleOverflow: function(state) {//{{{
document.body.querySelector('#curtain').style.display = state === 'on' ? 'block' : 'none';
document.body.style.overflow = state === 'on' ? 'hidden' : 'auto';
},//}}} Interface::curtains
draw: function() {//{{{
var user = this.user, _cb = user.showCheckboxes ? '' : 'hidden',
_u0 = new Uint8Array(Array.prototype.map.call(window.atob(audio0), v => v.charCodeAt(0))),
_u1 = new Uint8Array(Array.prototype.map.call(window.atob(audio1), v => v.charCodeAt(0))),
_audio0 = URL.createObjectURL(new Blob([_u0], {type:'audio/ogg'})),
_audio1 = URL.createObjectURL(new Blob([_u1], {type:'audio/mp3'})),
titles = {//{{{
refresh: "Enter search refresh delay in seconds.\nEnter 0 for no auto-refresh.\nDefault is 0 (no auto-refresh).",
pages: "Enter number of pages to scrape. Default is 3.\nHas no effect in a batch search (Most Available sort).",
skips: "Searches additional pages to get a more consistent number of results. Helpful if you're blocking a lot of items.",
resultsPerPage: "Number of results to return per page (maximum is 100, default is 10)",
batch: "Enter minimum HITs for batch search (must be searching by Most Available).",
pay: "Enter the minimum desired pay per HIT (e.g. 0.10).",
qual: "Only show HITs you're currently qualified for (must be logged in).",
monly: "Only show HITs that require Masters qualifications.",
mhide: "Remove masters hits from the results if selected, otherwise display both masters and non-masters HITS.\n" +
"The 'qualified' setting superceedes this option.",
searchBy: "Get search results by...\n Latest = HIT Creation Date (newest first),\n " +
"Most Available = HITs Available (most first),\n Reward = Reward Amount (most first),\n Title = Title (A-Z)",
invert: "Reverse the order of the Search By choice, so...\n Latest = HIT Creation Date (oldest first),\n " +
"Most Available = HITs Available (least first),\n Reward = Reward Amount (least first),\n Title = Title (Z-A)",
shine: "Enter time (in seconds) to keep new HITs highlighted.\nDefault is 300 (5 minutes).",
sound: "Play a sound when new results are found.",
soundSelect: "Select which sound will be played.",
minTOPay: "After getting search results, hide any results below this average Turkopticon pay rating.\n" +
"Minimum is 1, maximum is 5, decimals up to 2 places, such as 3.25",
hideNoTO: "After getting search results, hide any results that have no, or too few, Turkopticon pay ratings.",
disableTO: "Disable attempts to download ratings data from Turkopticon for the results table.",
sortPay: "After getting search results, re-sort the results based on their average Turkopticon pay ratings.",
sortAll: "After getting search results, re-sort the results by their overall Turkopticon rating.",
sortAsc: "Sort results in ascending (low to high) order.",
sortDsc: "Sort results in descending (high to low) order.",
search: "Enter keywords to search for; default is blank (no search terms).",
hideBlock: "When enabled, hide HITs that match your blocklist.\n"+
"When disabled, HITs that match your blocklist will be displayed with a red border.",
onlyIncludes: "Show only HITs that match your includelist.\nBe sure to edit your includelist first or no results will be displayed.",
shineInc: "Outline HITs that match your includelist with a dashed green border.",
mainlink: "Read the documentation for HIT Scraper With Export on its Greasyfork page.",
gbatch: "Apply the 'Minimum batch size' filter to all search options.",
},//}}}
css = [//{{{
'body {font-family:Verdana, Arial; font-size:14px}',
'p {margin:8px auto}',
'.cpdefault {width:900px; height:155px; visibility:visible; overflow:hidden; padding:8px 5px 1px 5px; transition:all 0.3s;}',
'#controlpanel i:after, #status i:after {content:" | "}',
'input[type="checkbox"], input[type="radio"] {vertical-align:middle}',
'input[type="number"] {width:50px; text-align:center}',
'label {padding:2px}',
'.hiddenpanel {width:0px; height:0px; visibility:hidden}',
'.hidden {display:none}',
'button {border:1px solid}',
'textarea {font-family:inherit; font-size:11px; margin:auto; padding:2px}',
'.pop {position:fixed; top:15%; left:50%; margin:auto; transform:translateX(-50%); padding:5px;' + // for editors/exporters
'background:black; color:white; z-index:20; font-size:12px; box-shadow:0px 0px 6px 1px #fff}',
'dt {text-transform:uppercase; clear:both; margin:3px}',
'.icbutt {float:left;border:1px solid #fff;cursor:pointer} .icbutt > input {opacity:0;display:block;width:25px;height:25px;border:none}',
// settings
'#settingsMain {z-index:20; position:fixed; background:#fff; color:#000; box-shadow:-3px 3px 2px 2px #7B8C89; line-height:initial;' +
'top:50%; left:50%; width:85%; height:85%; margin-right:-50%; transform:translate(-50%, -50%)}',
'#settingsMain > div {margin:5px; padding:3px; position:relative; border:1px solid grey; line-height:initial}',
'.close {position:relative; font-weight:bold; font-size:1em; color:white; background:black; cursor:pointer}',
'#settingsSidebar {width:100px; min-width:90px; height:92%; float:left}',
'#settingsSidebar > span {display:block; margin-bottom:5px; width:100px; font-size:1em; cursor:pointer}',
'.settingsPanel {position:absolute; top:0;left:0; display:none; width:100%; height:100%; font-size:11px}',
'.settingsPanel > div {margin:15px 5px; position:relative; background:#CCFFFA; overflow:auto; padding:6px 10px}',
'.settingsSelected {background:aquamarine}',
'.ble {border:1px solid black; border-collapse:collapse;} .blec {padding:5px; text-align:left;}',
'.toLink {position:relative;}',
'.toLink:before {content:""; display:none; z-index:5; position:absolute; top:0; left:-6px; width:0; height:0;' +
'border-top:6px solid transparent; border-bottom:6px solid transparent; border-left:6px solid black}',
'.toLink:hover:before {display:block;}',
'.tooltip {position:absolute;top:0;right:calc(100% + 6px);text-align:left;transform:translateY(-20%);padding:5px;font-weight:normal;' +
'font-size:11px; line-height:1; display:none; background:black; color:white; box-shadow:0px 0px 6px 1px #fff}',
'meter {width:100%; position:relative; height:15px;}',
'meter:before {font-size:10px; font-weight:bold; color:black; content:attr(data-attr); position:absolute; top:1px}',
'meter:after {font-size:10px; font-weight:bold; color:black; content:attr(value); position:absolute; top:1px; right:0}',
'#resultsTable button {height:14px; font-size:8px; border:1px solid; padding:0; background:transparent}',
'#resultsTable tbody td > div {display:table-cell}',
'#resultsTable tbody td > div:first-child {padding-right:2px; vertical-align:middle; white-space:nowrap}',
'button.disabled {position:relative}',
'button.disabled:before {content:""; display:none; z-index:5; position:absolute; top:-7px; left:50%; width:0; height:0;' +
'border-left:6px solid transparent; border-right:6px solid transparent; border-top:6px solid black; transform:translateX(-50%)}',
'button.disabled:after {content:"Exports are disabled while logged out."; display:none; z-index:5; position:absolute;' +
'top:-7px; left:50%; color:white; background:black; width:230px; padding:2px; transform:translate(-50%,-100%);' +
'box-shadow:0px 0px 6px 1px #fff}',
'button.disabled:focus:before {display:block} button.disabled:focus:after {display:block}',
'.spinner {animation: kfspin 0.7s infinite linear; font-weight:bold;}',
'@keyframes kfspin { 0% { transform: rotate(0deg) } 100% { transform: rotate(359deg) } }',
'.spinner:before{content:"*"}',
'.exhwtf {width:70px; background:black; color:white; vertical-align:top; border-radius:5px}',
'.shine td {border:1px dotted #fff; font-weight:bold}',
'.ignored td {border:2px solid #00E5FF}',
'.includelisted td {border:3px dashed #008800}',
'.blocklisted td {border:3px solid #cc0000}',
],//}}}
//{{{ body
body = `
Auto-refresh delay:
Pages to scrape:
Results per page:
`,//}}}
head = `${DOC_TITLE}` +
``;
document.head.innerHTML = head;
document.body.innerHTML = body;
this.elkeys = Object.keys(titles);
return this;
},//}}} Interface::draw
init: function() {//{{{
this.panel = {}; this.buttons = {};
var get = (q,all) => document['querySelector' + (all ? 'All': '')](q),
sortdirs = get('#sortdirs'),
moveSortdirs = function(node) {
if (!node.checked) { sortdirs.style.display = 'none'; return; }
sortdirs.style.display = 'inline';
sortdirs.remove();
node.parentNode.insertBefore(sortdirs, node.nextSibling);
},
kdFn = e => { if (e.keyCode === 13) setTimeout(() => this.buttons.main.click(), 30); },
optChangeFn = function(e) {//{{{
var tag = e.target.tagName, type = e.target.type, id = e.target.id,
isChecked = e.target.checked, name = e.target.name, value = e.target.value;
switch(tag) {
case 'SELECT':
if (id === 'soundSelect')
this.user.notifySound[1] = e.target.value;
else
this.user[id] = e.target.selectedIndex;
break;
case 'INPUT':
switch(type) {
case 'number':
case 'text':
this.user[id] = value; break;
case 'radio':
Array.from(get(`input[name=${name}]`,true))
.forEach(v => { this.user[v.id] = v.checked; get(`label[for=${v.id}]`).classList.toggle('checked'); });
break;
case 'checkbox':
if (name === 'sort') {
Array.from(get(`input[name=${name}]`,true)).forEach(v => {
if (e.target !== v) v.checked = false;
get(`label[for=${v.id}]`).className = v.checked ? 'checked' : '';
this.user[v.id] = v.checked;
});
moveSortdirs(e.target);
break;
} else if (id === 'sound') {
this.user.notifySound[0] = isChecked;
e.target.nextElementSibling.style.display = isChecked ? 'inline' : 'none';
}
this.user[id] = isChecked;
get(`label[for=${id}]`).classList.toggle('checked');
break;
} break;
}
Settings.save();
}.bind(this);//}}}
Themes.apply(this.user.themes.name);
// get references to control panel elements and set up click events
this.Status = {
node: get('#status').firstChild,
push: function(t) { this.node.innerHTML = t; },
append: function(t) { this.node.innerHTML += t; },
cd: function() { this.node.innerHTML = this.node.innerHTML.replace(/\d+(?= seconds)/, m => +m-1); }
};
for (var k of this.elkeys) {
if (k === 'mainlink') continue;
this.panel[k] = document.getElementById(k);
this.panel[k].onchange = optChangeFn;
if (k === 'pay' || k === 'search') this.panel[k].onkeydown = kdFn;
if ((k === 'sortPay' || k === 'sortAll') && this.panel[k].checked) moveSortdirs(this.panel[k]);
}
// get references to buttons
Array.from(get('button',true)).forEach(v => this.buttons[v.id.slice(3).toLowerCase()] = v);
// set up button click events
this.buttons.main.onclick = function(e) {
e.target.textContent = e.target.textContent === 'Start' ? 'Stop' : 'Start';
Core.run();
};
this.buttons.hide.onclick = function(e) {
get('#controlpanel').classList.toggle('hiddenpanel');
e.target.textContent = e.target.textContent === 'Hide Panel' ? 'Show Panel' : 'Hide Panel';
};
this.buttons.blocks.onclick = () => { this.toggleOverflow('on'); new Editor('ignore'); };
this.buttons.incs.onclick = () => { this.toggleOverflow('on'); new Editor('include'); };
this.buttons.ignores.onclick = () => Array.from(get('.ignored:not(.blocklisted)',true)).forEach(v => v.classList.toggle('hidden'));
this.buttons.settings.onclick = () => { this.toggleOverflow('on'); Settings.draw().init(); };
get('#hideBlock').addEventListener('change', () => Array.from(get('.blocklisted',true)).forEach(v => v.classList.toggle('hidden')));
window.onblur = () => this.focused = false;
window.onfocus = () => { this.focused = true; this.resetTitle(); };
}//}}} Interface::init
},//}}} Interface
Editor = function(type) {//{{{
Interface.toggleOverflow('on');
this.node = document.body.appendChild(document.createElement('DIV'));
this.node.classList.add('pop');
this.die = () => {Interface.toggleOverflow('off'); this.node.remove();};
this.type = type;
this.caller = arguments[1] || null;
switch(type) {
case 'include':
case 'ignore':
if (type === 'ignore' && !localStorage.getItem('scraper_ignore_list')) // set default blocklist
localStorage.setItem('scraper_ignore_list',
'oscar smith^diamond tip research llc^jonathan weber^jerry torres^' +
'crowdsource^we-pay-you-fast^turk experiment^jon brelig^p9r');
var titleText = type === 'ignore' ?
'BLOCKLIST - Edit the blocklist with what you want to ignore/hide. Separate requester names and HIT titles with the ' +
'^ character. After clicking "Save", you\'ll need to scrape again to apply the changes.'
: 'INCLUDELIST - Focus the results on your favorite requesters. Separate requester names and HIT titles with the ' +
'^ character. When the "Restrict to includelist" option is selected, ' +
'HIT Scraper only shows results matching the includelist.';
this.node.innerHTML = titleText +
'' +
''+
'';
this.node.querySelector('#edSave').onclick = () => {
localStorage.setItem(`scraper_${type}_list`, this.node.querySelector('textarea').value.trim()); this.die();
}; break;
case 'theme':
var dlbody = [], _th = Settings.user.themes, split = obj => {
var a = []; for (var k in obj) if (obj.hasOwnProperty(k)) a.push({k:k, v:obj[k]});
return a.sort((a,b) => a.k < b.k ? -1 : 1);
}, _colors = split(_th.colors[_th.name]),
define = k => '
' + _dd[k] + '
',
_dd = {//{{{
highlight:'Distinguishes between active and inactive states in the control panel',
background:'Background color',
accent:'Color of spacer text (and control panel buttons on themes other than \'classic\')',
bodytable:'Default color of text elements in the results table (this is ignored if HIT coloring is set to \'cell\')',
cpBackground:'Background color of the control panel',
toHigh:'Color for results with high TO',
toGood:'Color for results with good TO',
toAverage:'Color for results with average TO',
toLow:'Color for results with low TO',
toPoor:'Color for results with poor TO',
toNone:'Color for results with no TO',
hitDB:'Designates that a match was found in your HITdb',
nohitDB:'Designates that a match was not found in your HITdb',
unqualified:'Designates that you do not have the qualifications necessary to work on the HIT',
reqmaster:'Designates HITs that require Masters',
nomaster:'Designates HITs that do not require Masters',
defaultText:'Default text color',
inputText:'Color of input boxes in the control panel',
secondText:'Color for text used on selected control panel items',
link:'Default color of unvisited links',
vlink:'Default color of visited links',
export:'Color of buttons in the results table--export and block buttons',
hover:'Color of control panel options on mouseover',
};//}}}
for (var r of _colors)
dlbody.push(`