4chan-x/foltor/foltor.js
2010-05-31 11:34:16 -07:00

531 lines
16 KiB
JavaScript

(function(){
var $, $$, _a, _b, _c, _d, _e, _f, _g, _h, a, addClass, autoHide, bar, board, box, cancel, defaultValue, del, div, f, field, fields, filterAll, filterReply, filterThread, filters, inBefore, input, keydown, klass, label, loadFilters, mousedown, mousemove, mouseup, move, name, option, optionKeydown, options, position, remove, reset, sBoard, sKlass, save, saveFilters, tag, text, x;
var __hasProp = Object.prototype.hasOwnProperty;
x = function(path, root) {
root = root || document.body;
return document.evaluate(path, root, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue;
};
$ = function(selector, root) {
root = root || document.body;
return root.querySelector(selector);
};
$$ = function(selector, root) {
var _a, _b, _c, _d, node, result;
root = root || document.body;
result = root.querySelectorAll(selector);
//magic that turns the results object into an array:
_a = []; _c = result;
for (_b = 0, _d = _c.length; _b < _d; _b++) {
node = _c[_b];
_a.push(node);
}
return _a;
};
inBefore = function(root, el) {
return root.parentNode.insertBefore(el, root);
};
tag = function(el) {
return document.createElement(el);
};
text = function(s) {
return document.createTextNode(s);
};
remove = function(root) {
return root.parentNode.removeChild(root);
};
position = function(el) {
var id, left, top;
id = el.id;
(left = GM_getValue(("" + (id) + "Left"), '0px')) ? (el.style.left = left) : (el.style.right = '0px');
if ((top = GM_getValue(("" + (id) + "Top"), '0px'))) {
el.style.top = top;
return el.style.top;
} else {
el.style.bottom = '0px';
return el.style.bottom;
}
};
move = {};
mousedown = function(e) {
var div;
div = this.parentNode;
move.div = div;
move.divX = parseInt(div.style.left);
move.divY = parseInt(div.style.top);
move.clientX = e.clientX;
move.clientY = e.clientY;
move.bodyX = document.body.clientWidth;
move.bodyY = document.body.clientHeight;
window.addEventListener('mousemove', mousemove, true);
return window.addEventListener('mouseup', mouseup, true);
};
mousemove = function(e) {
var div, left, realX, realY, top;
div = move.div;
realX = move.divX + (e.clientX - move.clientX);
// x + dx
left = realX < 20 ? 0 : realX;
if (move.bodyX - div.offsetWidth - realX < 20) {
div.style.left = '';
div.style.right = '0px';
} else {
div.style.left = left + 'px';
div.style.right = '';
}
realY = move.divY + (e.clientY - move.clientY);
// y + dy
top = realY < 20 ? 0 : realY;
if (move.bodyY - div.offsetHeight - realY < 20) {
div.style.top = '';
div.style.bottom = '0px';
return div.style.bottom;
} else {
div.style.top = top + 'px';
div.style.bottom = '';
return div.style.bottom;
}
};
mouseup = function() {
var id;
id = move.div.id;
GM_setValue(("" + (id) + "Left"), move.div.style.left);
GM_setValue(("" + (id) + "Top"), move.div.style.top);
window.removeEventListener('mousemove', mousemove, true);
return window.removeEventListener('mouseup', mouseup, true);
};
//x-browser
if (typeof GM_deleteValue === 'undefined') {
this.GM_setValue = function(name, value) {
value = (typeof value)[0] + value;
return localStorage.setItem(name, value);
};
this.GM_getValue = function(name, defaultValue) {
var type, value;
if (!(value = localStorage.getItem(name))) {
return defaultValue;
}
type = value[0];
value = value.substring(1);
if (type === 'b') {
return value === 'true';
} else if (type === 'n') {
return Number(value);
} else {
return value;
}
};
this.GM_addStyle = function(css) {
var style;
style = tag('style');
style.type = 'text/css';
style.textContent = css;
return $('head', document).appendChild(style);
};
}
GM_addStyle(' \
#box_options input { \
width: 100px; \
} \
#box, #box_options { \
position: fixed; \
text-align: right; \
border: 1px solid; \
} \
#box.autohide:not(:hover) { \
background: rgba(0,0,0,0); \
border: none; \
} \
#box.autohide:not(:hover):not(:active) > *:not(.top) { \
display: none; \
} \
#box.autohide a:last-child { \
font-weight: bold; \
} \
#box > div { \
padding: 0 5px 0 5px; \
} \
#box > .top { \
padding: 5px 5px 0 5px; \
} \
#box > .bottom { \
padding: 0 5px 5px 5px; \
} \
.move { \
cursor: move; \
} \
#box a, #box_options a { \
cursor: pointer; \
} \
.hide { \
display: none; \
} \
div.hide + hr { \
display: none; \
} \
');
//duplicated code. sigh.
// we could try threading the op, but that might affect other scripts.
// also, I really want to try out *gasp* eval().
filterThread = function(thread, fields) {
var _a, _b, _c, _d, _e, _f, _g, _h, field, regex, s;
_a = fields;
for (field in _a) { if (__hasProp.call(_a, field)) {
if (field === 'Name') {
s = $('span.postername', thread).textContent;
} else if (field === 'Tripcode') {
s = (typeof (_b = (x('./span[@class="postertrip"]', thread))) === "undefined" || _b == undefined ? undefined : _b.textContent) || '';
} else if (field === 'Email') {
s = (typeof (_c = (x('./a[@class="linkmail"]', thread))) === "undefined" || _c == undefined ? undefined : _c.href.slice(7)) || '';
} else if (field === 'Subject') {
s = (typeof (_d = (x('./span[@class="filetitle"]', thread))) === "undefined" || _d == undefined ? undefined : _d.textContent) || '';
} else if (field === 'Comment') {
s = $('blockquote', thread).textContent;
} else if (field === 'File') {
s = (typeof (_e = (x('./span[@class="filesize"]', thread))) === "undefined" || _e == undefined ? undefined : _e.textContent) || '';
}
_g = fields[field].op;
for (_f = 0, _h = _g.length; _f < _h; _f++) {
regex = _g[_f];
if (regex.test(s)) {
return true;
}
}
}}
};
filterReply = function(table, fields) {
var _a, _b, _c, _d, _e, _f, _g, _h, field, regex, s;
_a = fields;
for (field in _a) { if (__hasProp.call(_a, field)) {
if (field === 'Name') {
s = $('span.commentpostername', table).textContent;
} else if (field === 'Tripcode') {
s = (typeof (_b = ($('span.postertrip', table))) === "undefined" || _b == undefined ? undefined : _b.textContent) || '';
} else if (field === 'Email') {
s = (typeof (_c = ($('a.linkmail', table))) === "undefined" || _c == undefined ? undefined : _c.href.slice(7)) || '';
} else if (field === 'Subject') {
s = (typeof (_d = ($('span.filetitle', table))) === "undefined" || _d == undefined ? undefined : _d.textContent) || '';
} else if (field === 'Comment') {
s = $('blockquote', table).textContent;
} else if (field === 'File') {
s = (typeof (_e = ($('span.filesize', table))) === "undefined" || _e == undefined ? undefined : _e.textContent) || '';
}
_g = fields[field].reply;
for (_f = 0, _h = _g.length; _f < _h; _f++) {
regex = _g[_f];
if (regex.test(s)) {
return true;
}
}
}}
};
filterAll = function() {
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, boards, compiled, el, field, filtered, imageCount, key, klass, match, nop, num, obj, regex, replies, reply, s, split, thread, threads, trimmed;
saveFilters();
compiled = {};
_a = filters;
for (klass in _a) { if (__hasProp.call(_a, klass)) {
compiled[klass] = {};
boards = filters[klass];
//for ['global', BOARD] of boards
_b = boards['global'];
for (field in _b) { if (__hasProp.call(_b, field)) {
s = boards['global'][field];
split = s.split(';');
trimmed = (function() {
_c = []; _e = split;
for (_d = 0, _f = _e.length; _d < _f; _d++) {
el = _e[_d];
_c.push(el.trimLeft());
}
return _c;
})();
filtered = (function() {
_g = []; _i = trimmed;
for (_h = 0, _j = _i.length; _h < _j; _h++) {
el = _i[_h];
el.length ? _g.push(el) : null;
}
return _g;
})();
if (filtered.length) {
obj = {
op: [],
reply: []
};
_l = filtered;
for (_k = 0, _m = _l.length; _k < _m; _k++) {
el = _l[_k];
if (/\ -\w+$/.test(el)) {
_n = el.match(/(.+) -(\w+)$/);
nop = _n[0];
el = _n[1];
match = _n[2];
if (match === 'o') {
key = 'op';
} else if (match === 'O') {
key = 'reply';
}
}
regex = new RegExp(el, 'i');
if (key) {
obj[key].push(regex);
} else {
obj['op'].push(regex);
obj['reply'].push(regex);
}
}
compiled[klass][field] = obj;
}
}}
}}
_o = reset();
replies = _o[0];
threads = _o[1];
num = threads.length ? replies.length + threads.length : $$('blockquote').length;
//these loops look combinable
_q = replies;
for (_p = 0, _r = _q.length; _p < _r; _p++) {
reply = _q[_p];
_s = compiled;
for (klass in _s) { if (__hasProp.call(_s, klass)) {
filterReply(reply, compiled[klass]) ? reply.className += ' ' + klass : null;
}}
}
_u = threads;
for (_t = 0, _v = _u.length; _t < _v; _t++) {
thread = _u[_t];
_w = compiled;
for (klass in _w) { if (__hasProp.call(_w, klass)) {
filterThread(thread, compiled[klass]) ? thread.className += ' ' + klass : null;
}}
}
imageCount = $$('img[md5]').length;
box.firstChild.textContent = ("Images: " + imageCount + " Posts: " + num);
return box.firstChild.textContent;
};
keydown = function(e) {
if (e.keyCode === 13) {
//enter
return filterAll();
}
};
reset = function() {
var _a, _b, _c, _d, _e, _f, form, table, tables, thread, threads;
form = $('form[name="delform"]');
tables = $$('table', form);
tables.pop();
tables.pop();
_b = tables;
for (_a = 0, _c = _b.length; _a < _c; _a++) {
table = _b[_a];
table.className = '';
}
threads = $$('div', form);
threads.pop();
_e = threads;
for (_d = 0, _f = _e.length; _d < _f; _d++) {
thread = _e[_d];
thread.className = '';
}
return [tables, threads];
};
autoHide = function() {
box.className === 'reply' ? (box.className = 'reply autohide') : (box.className = 'reply');
return GM_setValue('className', box.className);
};
save = function() {
var _a, _b, _c, div, input, inputs, option, value;
div = this.parentNode.parentNode;
inputs = $$('input:enabled', div);
_b = inputs;
for (_a = 0, _c = _b.length; _a < _c; _a++) {
input = _b[_a];
if ((value = input.value)) {
filters[value] = {};
option = tag('option');
option.textContent = value;
sKlass.appendChild(option);
}
}
typeof option === "undefined" || option == undefined ? undefined : option.selected = true;
loadFilters();
GM_setValue('filters', JSON.stringify(filters));
return remove(div);
};
cancel = function() {
var div;
div = this.parentNode.parentNode;
return remove(div);
};
optionKeydown = function(e) {
if (e.keyCode === 13) {
//enter
return save.call(this.parentNode);
}
};
addClass = function() {
var div, input;
div = tag('div');
input = tag('input');
input.addEventListener('keydown', optionKeydown, true);
div.appendChild(input);
inBefore(this, div);
return input.focus();
};
del = function() {
var _a, _b, _c, option, value;
value = this.nextElementSibling.value;
delete filters[value];
GM_setValue('filters', JSON.stringify(filters));
remove(this.parentNode);
_b = sKlass.options;
for (_a = 0, _c = _b.length; _a < _c; _a++) {
option = _b[_a];
option.value === value ? remove(option) : null;
}
return loadFilters();
};
options = function() {
var _a, a, bar, div, filter, filters, input, opt;
if ((opt = $('#box_options'))) {
return remove(opt);
} else {
opt = tag('div');
opt.id = 'box_options';
opt.className = 'reply';
position(opt);
bar = tag('div');
bar.textContent = 'Options';
bar.className = 'move';
bar.addEventListener('mousedown', mousedown, true);
opt.appendChild(bar);
filters = JSON.parse(GM_getValue('filters', '{ "hide": {} }'));
_a = filters;
for (filter in _a) { if (__hasProp.call(_a, filter)) {
div = tag('div');
a = tag('a');
a.textContent = 'delete';
a.addEventListener('click', del, true);
div.appendChild(a);
div.appendChild(text(' '));
input = tag('input');
input.value = filter;
input.disabled = true;
div.appendChild(input);
opt.appendChild(div);
}}
div = tag('div');
a = tag('a');
a.textContent = 'Add Class';
a.addEventListener('click', addClass, true);
div.appendChild(a);
opt.appendChild(div);
div = tag('div');
a = tag('a');
a.textContent = 'save';
a.addEventListener('click', save, true);
div.appendChild(a);
div.appendChild(text(' '));
a = tag('a');
a.textContent = 'cancel';
a.addEventListener('click', cancel, true);
div.appendChild(a);
opt.appendChild(div);
return document.body.appendChild(opt);
}
};
loadFilters = function() {
var _a, _b, _c, _d, filter, input, inputs;
filter = filters[sKlass.value][sBoard.value];
inputs = $$('input', box);
_a = []; _c = inputs;
for (_b = 0, _d = _c.length; _b < _d; _b++) {
input = _c[_b];
_a.push((input.value = filter[input.name] || ''));
}
return _a;
};
saveFilters = function() {
var _a, _b, _c, filter, input, inputs, value;
filter = {};
inputs = $$('input', box);
_b = inputs;
for (_a = 0, _c = _b.length; _a < _c; _a++) {
input = _b[_a];
(value = input.value) ? (filter[input.name] = value) : null;
}
filters[sKlass.value][sBoard.value] = filter;
return GM_setValue('filters', JSON.stringify(filters));
};
box = tag('div');
box.id = 'box';
box.className = GM_getValue('className', 'reply');
position(box);
bar = tag('div');
bar.className = 'move top';
bar.addEventListener('mousedown', mousedown, true);
box.appendChild(bar);
sKlass = tag('select');
sKlass.addEventListener('mousedown', saveFilters, true);
sKlass.addEventListener('mouseup', loadFilters, true);
defaultValue = JSON.stringify({
'hide': {
'global': []
}
});
filters = JSON.parse(GM_getValue('filters', defaultValue));
_a = filters;
for (klass in _a) { if (__hasProp.call(_a, klass)) {
option = tag('option');
option.textContent = klass;
sKlass.appendChild(option);
}}
box.appendChild(sKlass);
sBoard = tag('select');
_b = filters[klass];
for (board in _b) { if (__hasProp.call(_b, board)) {
option = tag('option');
option.textContent = board;
sBoard.appendChild(option);
}}
box.appendChild(sBoard);
fields = ['Name', 'Tripcode', 'Email', 'Subject', 'Comment', 'File'];
_d = fields;
for (_c = 0, _e = _d.length; _c < _e; _c++) {
field = _d[_c];
div = tag('div');
label = tag('label');
label.textContent = field;
input = tag('input');
input.name = field;
input.addEventListener('keydown', keydown, true);
label.appendChild(input);
div.appendChild(label);
box.appendChild(div);
}
loadFilters();
div = tag('div');
div.className = 'bottom';
_g = ['apply', 'reset', 'options', 'autohide'];
for (_f = 0, _h = _g.length; _f < _h; _f++) {
name = _g[_f];
a = tag('a');
a.textContent = name;
if (name === 'apply') {
f = filterAll;
} else if (name === 'reset') {
f = reset;
} else if (name === 'options') {
f = options;
} else if (name === 'autohide') {
f = autoHide;
}
a.addEventListener('click', f, true);
div.appendChild(a);
div.appendChild(text(' '));
}
box.appendChild(div);
document.body.appendChild(box);
filterAll();
})();