1909 lines
59 KiB
JavaScript
1909 lines
59 KiB
JavaScript
// ==UserScript==
|
|
// @name 4chan x
|
|
// @namespace aeosynth
|
|
// @description Adds various features.
|
|
// @version 1.24.0
|
|
// @copyright 2009-2011 James Campos <james.r.campos@gmail.com>
|
|
// @license MIT; http://en.wikipedia.org/wiki/Mit_license
|
|
// @include http://boards.4chan.org/*
|
|
// @include http://sys.4chan.org/*
|
|
// ==/UserScript==
|
|
|
|
/* LICENSE
|
|
*
|
|
* Copyright (c) 2009-2011 James Campos <james.r.campos@gmail.com>
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person
|
|
* obtaining a copy of this software and associated documentation
|
|
* files (the "Software"), to deal in the Software without
|
|
* restriction, including without limitation the rights to use,
|
|
* copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following
|
|
* conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be
|
|
* included in all copies or substantial portions of the Software.
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
|
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
|
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
|
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
* OTHER DEALINGS IN THE SOFTWARE.
|
|
*/
|
|
|
|
/* HACKING
|
|
*
|
|
* 4chan x is written in CoffeeScript[1], and developed on github[2].
|
|
*
|
|
* [1]: http://jashkenas.github.com/coffee-script/
|
|
* [2]: http://github.com/aeosynth/4chan-x
|
|
*/
|
|
|
|
/* CONTRIBUTORS
|
|
*
|
|
* Ongpot - sfw favicon
|
|
* thisisanon - nsfw + 404 favicons
|
|
* Anonymous - empty favicon
|
|
* Seiba - chrome quick reply focusing
|
|
* herpaderpderp - recaptcha fixes
|
|
* wakimoko - recaptcha tab order http://userscripts.org/scripts/show/82657
|
|
* All the people who've taken the time to write bug reports.
|
|
*
|
|
* Thank you.
|
|
*/
|
|
|
|
(function() {
|
|
var $, $$, DAY, Dialog, a, arr, as, autoWatch, autohide, b, board, callback, changeCheckbox, changeValue, clearHidden, closeQR, config, cooldown, cutoff, d, delform, down, editSauce, el, expand, expandComment, expandThread, formSubmit, g, getConfig, getThread, getTime, hide, hideReply, hideThread, href, html, i, id, iframe, iframeLoad, imageClick, imageExpand, imageExpandClick, imageResize, imageThumb, imageToggle, imageType, imageTypeChange, img, inAfter, inBefore, input, inputs, keyModeInsert, keyModeNormal, keydown, keypress, l1, lastChecked, log, m, mv, n, navbotr, navtopr, nodeInserted, now, omitted, onloadComment, onloadThread, option, options, parseResponse, pathname, qrListener, qrText, quickReply, recaptcha, recaptchaListener, recaptchaReload, redirect, replace, replyNav, report, request, rm, scroll, scrollThread, show, showReply, showThread, slice, span, src, start, stopPropagation, temp, text, textContent, thread, threadF, threads, tn, tzOffset, up, updateAuto, updateCallback, updateFavicon, updateInterval, updateNow, updateTime, updateTitle, updateVerbose, updaterMake, watch, watchX, watcher, watcherUpdate, x, zeroPad, _, _base, _i, _j, _k, _l, _len, _len2, _len3, _len4, _len5, _len6, _len7, _m, _n, _ref, _ref2, _ref3, _ref4, _ref5, _ref6;
|
|
var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, __slice = Array.prototype.slice;
|
|
if (typeof console != "undefined" && console !== null) {
|
|
log = console.log;
|
|
}
|
|
config = {
|
|
'404 Redirect': [true, 'Redirect dead threads'],
|
|
'Anonymize': [false, 'Make everybody anonymous'],
|
|
'Auto Watch': [true, 'Automatically watch threads that you start (Firefox only)'],
|
|
'Comment Expansion': [true, 'Expand too long comments'],
|
|
'Image Expansion': [true, 'Expand images'],
|
|
'Image Preloading': [false, 'Preload Images'],
|
|
'Keybinds': [false, 'Binds actions to keys'],
|
|
'Localize Time': [true, 'Show times based on your timezone'],
|
|
'Persistent QR': [false, 'Quick reply won\'t disappear after posting. Only in replies.'],
|
|
'Post in Title': [true, 'Show the op\'s post in the tab title'],
|
|
'Quick Reply': [true, 'Reply without leaving the page'],
|
|
'Quick Report': [true, 'Add quick report buttons'],
|
|
'Reply Hiding': [true, 'Hide single replies'],
|
|
'Reply Navigation': [true, 'Navigate to the beginning / end of a thread'],
|
|
'Restore IDs': [true, 'Check \'em'],
|
|
'Sauce': [true, 'Add sauce to images'],
|
|
'Show Stubs': [true, 'Of hidden threads / replies'],
|
|
'Thread Expansion': [true, 'View all replies'],
|
|
'Thread Hiding': [true, 'Hide entire threads'],
|
|
'Thread Navigation': [true, 'Navigate to previous / next thread'],
|
|
'Thread Updater': [true, 'Update threads'],
|
|
'Thread Watcher': [true, 'Bookmark threads'],
|
|
'Unread Count': [true, 'Show unread post count in tab title']
|
|
};
|
|
if (typeof GM_deleteValue === 'undefined') {
|
|
window.GM_setValue = function(name, value) {
|
|
value = (typeof value)[0] + value;
|
|
return localStorage.setItem(name, value);
|
|
};
|
|
window.GM_getValue = function(name, defaultValue) {
|
|
var type, value;
|
|
if (!(value = localStorage.getItem(name))) {
|
|
return defaultValue;
|
|
}
|
|
type = value[0];
|
|
value = value.slice(1);
|
|
switch (type) {
|
|
case 'b':
|
|
return value === 'true';
|
|
case 'n':
|
|
return Number(value);
|
|
default:
|
|
return value;
|
|
}
|
|
};
|
|
window.GM_addStyle = function(css) {
|
|
var style;
|
|
style = document.createElement('style');
|
|
style.type = 'text/css';
|
|
style.textContent = css;
|
|
return document.getElementsByTagName('head')[0].appendChild(style);
|
|
};
|
|
window.GM_openInTab = function(url) {
|
|
return window.open(url, "_blank");
|
|
};
|
|
}
|
|
GM_addStyle('\
|
|
div.dialog {\
|
|
border: 1px solid;\
|
|
}\
|
|
div.dialog > div.move {\
|
|
cursor: move;\
|
|
}\
|
|
label, a {\
|
|
cursor: pointer;\
|
|
}\
|
|
');
|
|
Dialog = (function() {
|
|
function Dialog(id, position, html) {
|
|
this.moveEnd = __bind(this.moveEnd, this);;
|
|
this.moveMove = __bind(this.moveMove, this);;
|
|
this.move = __bind(this.move, this);; var el, left, top, _ref;
|
|
this.el = el = document.createElement('div');
|
|
el.className = 'reply dialog';
|
|
el.innerHTML = html;
|
|
el.id = id;
|
|
switch (position) {
|
|
case 'topleft':
|
|
left = '0px';
|
|
top = '0px';
|
|
break;
|
|
case 'topright':
|
|
left = null;
|
|
top = '0px';
|
|
break;
|
|
case 'bottomleft':
|
|
left = '0px';
|
|
top = null;
|
|
break;
|
|
case 'bottomright':
|
|
left = null;
|
|
top = null;
|
|
break;
|
|
case 'center':
|
|
left = '50%';
|
|
top = '25%';
|
|
}
|
|
left = GM_getValue("" + id + "Left", left);
|
|
top = GM_getValue("" + id + "Top", top);
|
|
if (left) {
|
|
el.style.left = left;
|
|
} else {
|
|
el.style.right = '0px';
|
|
}
|
|
if (top) {
|
|
el.style.top = top;
|
|
} else {
|
|
el.style.bottom = '0px';
|
|
}
|
|
$('div.move', el).addEventListener('mousedown', this.move, true);
|
|
if ((_ref = $('div.move a[name=close]', el)) != null) {
|
|
_ref.addEventListener('click', (function() {
|
|
return rm(el);
|
|
}), true);
|
|
}
|
|
}
|
|
Dialog.prototype.move = function(e) {
|
|
var el;
|
|
el = this.el;
|
|
this.dx = e.clientX - el.offsetLeft;
|
|
this.dy = e.clientY - el.offsetTop;
|
|
this.width = document.body.clientWidth - el.offsetWidth;
|
|
this.height = document.body.clientHeight - el.offsetHeight;
|
|
document.addEventListener('mousemove', this.moveMove, true);
|
|
return document.addEventListener('mouseup', this.moveEnd, true);
|
|
};
|
|
Dialog.prototype.moveMove = function(e) {
|
|
var bottom, el, left, right, top;
|
|
el = this.el;
|
|
left = e.clientX - this.dx;
|
|
if (left < 20) {
|
|
left = '0px';
|
|
} else if (this.width - left < 20) {
|
|
left = '';
|
|
}
|
|
right = left ? '' : '0px';
|
|
el.style.left = left;
|
|
el.style.right = right;
|
|
top = e.clientY - this.dy;
|
|
if (top < 20) {
|
|
top = '0px';
|
|
} else if (this.height - top < 20) {
|
|
top = '';
|
|
}
|
|
bottom = top ? '' : '0px';
|
|
el.style.top = top;
|
|
return el.style.bottom = bottom;
|
|
};
|
|
Dialog.prototype.moveEnd = function() {
|
|
var el, id;
|
|
document.removeEventListener('mousemove', this.moveMove, true);
|
|
document.removeEventListener('mouseup', this.moveEnd, true);
|
|
el = this.el;
|
|
id = el.id;
|
|
GM_setValue("" + id + "Left", el.style.left);
|
|
return GM_setValue("" + id + "Top", el.style.top);
|
|
};
|
|
return Dialog;
|
|
})();
|
|
d = document;
|
|
g = null;
|
|
$ = function(selector, root) {
|
|
if (root == null) {
|
|
root = d.body;
|
|
}
|
|
return root.querySelector(selector);
|
|
};
|
|
$$ = function(selector, root) {
|
|
var node, result, _i, _len, _results;
|
|
if (root == null) {
|
|
root = d.body;
|
|
}
|
|
result = root.querySelectorAll(selector);
|
|
_results = [];
|
|
for (_i = 0, _len = result.length; _i < _len; _i++) {
|
|
node = result[_i];
|
|
_results.push(node);
|
|
}
|
|
return _results;
|
|
};
|
|
mv = function() {
|
|
var child, children, parent, _i, _j, _len, _results;
|
|
children = 2 <= arguments.length ? __slice.call(arguments, 0, _i = arguments.length - 1) : (_i = 0, []), parent = arguments[_i++];
|
|
_results = [];
|
|
for (_j = 0, _len = children.length; _j < _len; _j++) {
|
|
child = children[_j];
|
|
_results.push(parent.appendChild(child));
|
|
}
|
|
return _results;
|
|
};
|
|
getConfig = function(name) {
|
|
return GM_getValue(name, config[name][0]);
|
|
};
|
|
getTime = function() {
|
|
return Math.floor(new Date().getTime() / 1000);
|
|
};
|
|
hide = function(el) {
|
|
return el.style.display = 'none';
|
|
};
|
|
inAfter = function(root, el) {
|
|
return root.parentNode.insertBefore(el, root.nextSibling);
|
|
};
|
|
inBefore = function(root, el) {
|
|
return root.parentNode.insertBefore(el, root);
|
|
};
|
|
m = function(el, props) {
|
|
var event, funk, key, l, val;
|
|
if (l = props.listener) {
|
|
delete props.listener;
|
|
event = l[0], funk = l[1];
|
|
el.addEventListener(event, funk, true);
|
|
}
|
|
for (key in props) {
|
|
val = props[key];
|
|
el[key] = val;
|
|
}
|
|
return el;
|
|
};
|
|
n = function(tag, props) {
|
|
var el;
|
|
el = d.createElement(tag);
|
|
if (props) {
|
|
m(el, props);
|
|
}
|
|
return el;
|
|
};
|
|
rm = function(el) {
|
|
return el.parentNode.removeChild(el);
|
|
};
|
|
replace = function(root, el) {
|
|
return root.parentNode.replaceChild(el, root);
|
|
};
|
|
show = function(el) {
|
|
return el.style.display = '';
|
|
};
|
|
slice = function(arr, id) {
|
|
var i, l, _results;
|
|
i = 0;
|
|
l = arr.length;
|
|
_results = [];
|
|
while (i < l) {
|
|
if (id === arr[i].id) {
|
|
arr.splice(i, 1);
|
|
return arr;
|
|
}
|
|
_results.push(i++);
|
|
}
|
|
return _results;
|
|
};
|
|
tn = function(s) {
|
|
return d.createTextNode(s);
|
|
};
|
|
x = function(path, root) {
|
|
if (root == null) {
|
|
root = d.body;
|
|
}
|
|
return d.evaluate(path, root, null, XPathResult.ANY_UNORDERED_NODE_TYPE, null).singleNodeValue;
|
|
};
|
|
zeroPad = function(n) {
|
|
if (n < 10) {
|
|
return '0' + n;
|
|
} else {
|
|
return n;
|
|
}
|
|
};
|
|
autohide = function() {
|
|
var klass, qr;
|
|
qr = $('#qr');
|
|
klass = qr.className;
|
|
if (klass.indexOf('auto') === -1) {
|
|
klass += ' auto';
|
|
} else {
|
|
klass = klass.replace(' auto', '');
|
|
}
|
|
return qr.className = klass;
|
|
};
|
|
autoWatch = function() {
|
|
var autoText;
|
|
autoText = $('textarea', this).value.slice(0, 25);
|
|
return GM_setValue('autoText', "/" + g.BOARD + "/ - " + autoText);
|
|
};
|
|
closeQR = function() {
|
|
var div;
|
|
div = this.parentNode.parentNode;
|
|
return rm(div);
|
|
};
|
|
clearHidden = function() {
|
|
GM_deleteValue("hiddenReplies/" + g.BOARD + "/");
|
|
GM_deleteValue("hiddenThreads/" + g.BOARD + "/");
|
|
this.value = "hidden: 0";
|
|
g.hiddenReplies = [];
|
|
return g.hiddenThreads = [];
|
|
};
|
|
cooldown = function() {
|
|
var auto, seconds, submit;
|
|
submit = $('#qr input[type=submit]');
|
|
seconds = parseInt(submit.value);
|
|
if (seconds === 0) {
|
|
submit.disabled = false;
|
|
submit.value = 'Submit';
|
|
auto = submit.previousSibling.lastChild;
|
|
if (auto.checked) {
|
|
return $('#qr form').submit();
|
|
}
|
|
} else {
|
|
submit.value = seconds - 1;
|
|
return window.setTimeout(cooldown, 1000);
|
|
}
|
|
};
|
|
editSauce = function() {
|
|
var ta;
|
|
ta = $('#options textarea');
|
|
if (ta.style.display) {
|
|
return show(ta);
|
|
} else {
|
|
return hide(ta);
|
|
}
|
|
};
|
|
expandComment = function(e) {
|
|
var a, href, r;
|
|
e.preventDefault();
|
|
a = this;
|
|
href = a.getAttribute('href');
|
|
r = new XMLHttpRequest();
|
|
r.onload = function() {
|
|
return onloadComment(this.responseText, a, href);
|
|
};
|
|
r.open('GET', href, true);
|
|
r.send();
|
|
return g.xhrs.push({
|
|
r: r,
|
|
id: href.match(/\d+/)[0]
|
|
});
|
|
};
|
|
expandThread = function() {
|
|
var id, num, prev, r, span, table, xhr, _i, _len, _ref;
|
|
id = x('preceding-sibling::input[1]', this).name;
|
|
span = this;
|
|
if (span.textContent[0] === '-') {
|
|
num = board === 'b' ? 3 : 5;
|
|
table = x("following::br[@clear][1]/preceding::table[" + num + "]", span);
|
|
while ((prev = table.previousSibling) && (prev.nodeName === 'TABLE')) {
|
|
rm(prev);
|
|
}
|
|
span.textContent = span.textContent.replace('-', '+');
|
|
return;
|
|
}
|
|
span.textContent = span.textContent.replace('+', 'X Loading...');
|
|
_ref = g.xhrs;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
xhr = _ref[_i];
|
|
if (xhr.id === id) {
|
|
onloadThread(xhr.r.responseText, span);
|
|
return;
|
|
}
|
|
}
|
|
r = new XMLHttpRequest();
|
|
r.onload = function() {
|
|
return onloadThread(this.responseText, span);
|
|
};
|
|
r.open('GET', "res/" + id, true);
|
|
r.send();
|
|
return g.xhrs.push({
|
|
r: r,
|
|
id: id
|
|
});
|
|
};
|
|
getThread = function() {
|
|
var bottom, i, thread, threads, _len;
|
|
threads = $$('div.thread');
|
|
for (i = 0, _len = threads.length; i < _len; i++) {
|
|
thread = threads[i];
|
|
bottom = thread.getBoundingClientRect().bottom;
|
|
if (bottom > 0) {
|
|
return [thread, i];
|
|
}
|
|
}
|
|
};
|
|
formSubmit = function(e) {
|
|
var recaptcha, span, _ref;
|
|
if (span = this.nextSibling) {
|
|
rm(span);
|
|
}
|
|
recaptcha = $('input[name=recaptcha_response_field]', this);
|
|
if (recaptcha.value) {
|
|
return (_ref = $('#qr input[title=autohide]:not(:checked)')) != null ? _ref.click() : void 0;
|
|
} else {
|
|
e.preventDefault();
|
|
span = n('span', {
|
|
className: 'error',
|
|
textContent: 'You forgot to type in the verification.'
|
|
});
|
|
mv(span, this.parentNode);
|
|
alert('You forgot to type in the verification.');
|
|
return recaptcha.focus();
|
|
}
|
|
};
|
|
hideReply = function(reply) {
|
|
var a, div, name, p, table, trip, _ref;
|
|
if (p = this.parentNode) {
|
|
reply = p.nextSibling;
|
|
g.hiddenReplies.push({
|
|
id: reply.id,
|
|
timestamp: getTime()
|
|
});
|
|
GM_setValue("hiddenReplies/" + g.BOARD + "/", JSON.stringify(g.hiddenReplies));
|
|
}
|
|
name = $('span.commentpostername', reply).textContent;
|
|
trip = ((_ref = $('span.postertrip', reply)) != null ? _ref.textContent : void 0) || '';
|
|
table = x('ancestor::table', reply);
|
|
hide(table);
|
|
if (getConfig('Show Stubs')) {
|
|
a = n('a', {
|
|
textContent: "[ + ] " + name + " " + trip,
|
|
className: 'pointer',
|
|
listener: ['click', showReply]
|
|
});
|
|
div = n('div');
|
|
mv(a, div);
|
|
return inBefore(table, div);
|
|
}
|
|
};
|
|
hideThread = function(div) {
|
|
var a, name, num, p, span, text, trip, _ref;
|
|
if (p = this.parentNode) {
|
|
div = p;
|
|
g.hiddenThreads.push({
|
|
id: div.id,
|
|
timestamp: getTime()
|
|
});
|
|
GM_setValue("hiddenThreads/" + g.BOARD + "/", JSON.stringify(g.hiddenThreads));
|
|
}
|
|
hide(div);
|
|
if (getConfig('Show Stubs')) {
|
|
if (span = $('.omittedposts', div)) {
|
|
num = Number(span.textContent.match(/\d+/)[0]);
|
|
} else {
|
|
num = 0;
|
|
}
|
|
num += $$('table', div).length;
|
|
text = num === 1 ? "1 reply" : "" + num + " replies";
|
|
name = $('span.postername', div).textContent;
|
|
trip = ((_ref = $('span.postername + span.postertrip', div)) != null ? _ref.textContent : void 0) || '';
|
|
a = n('a', {
|
|
textContent: "[ + ] " + name + trip + " (" + text + ")",
|
|
className: 'pointer',
|
|
listener: ['click', showThread]
|
|
});
|
|
return inBefore(div, a);
|
|
}
|
|
};
|
|
iframeLoad = function() {
|
|
var auto, error, qr, span, submit, _ref, _ref2;
|
|
if (g.iframe = !g.iframe) {
|
|
return;
|
|
}
|
|
$('iframe').src = 'about:blank';
|
|
qr = $('#qr');
|
|
if (error = GM_getValue('error')) {
|
|
span = n('span', {
|
|
textContent: error,
|
|
className: 'error'
|
|
});
|
|
mv(span, qr);
|
|
if ((_ref = $('input[title=autohide]:checked', qr)) != null) {
|
|
_ref.click();
|
|
}
|
|
} else if (g.REPLY && getConfig('Persistent QR')) {
|
|
$('textarea', qr).value = '';
|
|
$('input[name=recaptcha_response_field]', qr).value = '';
|
|
submit = $('input[type=submit]', qr);
|
|
submit.value = 30;
|
|
submit.disabled = true;
|
|
window.setTimeout(cooldown, 1000);
|
|
auto = submit.previousSibling.lastChild;
|
|
if (auto.checked) {
|
|
if ((_ref2 = $('input[title=autohide]:checked', qr)) != null) {
|
|
_ref2.click();
|
|
}
|
|
}
|
|
} else {
|
|
rm(qr);
|
|
}
|
|
return recaptchaReload();
|
|
};
|
|
imageClick = function(e) {
|
|
if (e.shiftKey || e.altKey || e.ctrlKey) {
|
|
return;
|
|
}
|
|
e.preventDefault();
|
|
return imageToggle(this);
|
|
};
|
|
imageToggle = function(image) {
|
|
var ch, cw, imageType, thumb;
|
|
thumb = image.firstChild;
|
|
cw = d.body.clientWidth;
|
|
ch = d.body.clientHeight;
|
|
imageType = $("#imageType").value;
|
|
if (thumb.className === 'hide') {
|
|
return imageThumb(thumb);
|
|
} else {
|
|
return imageExpand(thumb, cw, ch, imageType);
|
|
}
|
|
};
|
|
imageTypeChange = function() {
|
|
var ch, cw, image, imageType, images, _i, _len, _results;
|
|
images = $$('img[md5] + img');
|
|
cw = d.body.clientWidth;
|
|
ch = d.body.clientHeight;
|
|
imageType = this.value;
|
|
_results = [];
|
|
for (_i = 0, _len = images.length; _i < _len; _i++) {
|
|
image = images[_i];
|
|
_results.push(imageResize(cw, ch, imageType, image));
|
|
}
|
|
return _results;
|
|
};
|
|
imageExpandClick = function() {
|
|
var ch, cw, imageType, thumb, thumbs, _i, _j, _len, _len2, _results, _results2;
|
|
thumbs = $$('img[md5]');
|
|
g.expand = this.checked;
|
|
cw = d.body.clientWidth;
|
|
ch = d.body.clientHeight;
|
|
imageType = $("#imageType").value;
|
|
if (this.checked) {
|
|
_results = [];
|
|
for (_i = 0, _len = thumbs.length; _i < _len; _i++) {
|
|
thumb = thumbs[_i];
|
|
_results.push(thumb.className !== 'hide' ? imageExpand(thumb, cw, ch, imageType) : void 0);
|
|
}
|
|
return _results;
|
|
} else {
|
|
_results2 = [];
|
|
for (_j = 0, _len2 = thumbs.length; _j < _len2; _j++) {
|
|
thumb = thumbs[_j];
|
|
_results2.push(thumb.className === 'hide' ? imageThumb(thumb) : void 0);
|
|
}
|
|
return _results2;
|
|
}
|
|
};
|
|
imageExpand = function(thumb, cw, ch, imageType) {
|
|
var image, link;
|
|
thumb.className = 'hide';
|
|
link = thumb.parentNode;
|
|
image = n('img', {
|
|
src: link.href
|
|
});
|
|
link.appendChild(image);
|
|
return imageResize(cw, ch, imageType, image);
|
|
};
|
|
imageResize = function(cw, ch, imageType, image) {
|
|
var ih, iw, ratio, _, _ref;
|
|
_ref = x("preceding::span[@class][1]/text()[2]", image).textContent.match(/(\d+)x(\d+)/), _ = _ref[0], iw = _ref[1], ih = _ref[2];
|
|
iw = Number(iw);
|
|
ih = Number(ih);
|
|
switch (imageType) {
|
|
case 'full':
|
|
image.removeAttribute('style');
|
|
break;
|
|
case 'fit width':
|
|
if (iw > cw) {
|
|
image.style.width = '100%';
|
|
image.style.margin = '0px';
|
|
}
|
|
break;
|
|
case 'fit screen':
|
|
ratio = Math.min(cw / iw, ch / ih);
|
|
if (ratio < 1) {
|
|
image.style.width = Math.floor(ratio * iw);
|
|
return image.style.margin = '0px';
|
|
}
|
|
}
|
|
};
|
|
imageThumb = function(thumb) {
|
|
thumb.className = '';
|
|
return rm(thumb.nextSibling);
|
|
};
|
|
keydown = function(e) {
|
|
var kc;
|
|
kc = e.keyCode;
|
|
g.keyCode = kc;
|
|
return g.char = String.fromCharCode(kc);
|
|
};
|
|
keypress = function(e) {
|
|
var _ref;
|
|
if ((_ref = d.activeElement.nodeName) === 'TEXTAREA' || _ref === 'INPUT') {
|
|
return keyModeInsert(e);
|
|
} else {
|
|
return keyModeNormal(e);
|
|
}
|
|
};
|
|
keyModeInsert = function(e) {
|
|
var char, kc, range, selEnd, selStart, ta, valEnd, valMid, valStart, value;
|
|
kc = g.keyCode;
|
|
char = g.char;
|
|
if (kc === 27) {
|
|
rm($('#qr'));
|
|
return e.preventDefault();
|
|
} else if (e.ctrlKey && char === "S") {
|
|
ta = d.activeElement;
|
|
if (ta.nodeName !== 'TEXTAREA') {
|
|
return;
|
|
}
|
|
value = ta.value;
|
|
selStart = ta.selectionStart;
|
|
selEnd = ta.selectionEnd;
|
|
valStart = value.slice(0, selStart) + '[spoiler]';
|
|
valMid = value.slice(selStart, selEnd);
|
|
valEnd = '[/spoiler]' + value.slice(selEnd);
|
|
ta.value = valStart + valMid + valEnd;
|
|
range = valStart.length + valMid.length;
|
|
ta.setSelectionRange(range, range);
|
|
return e.preventDefault();
|
|
}
|
|
};
|
|
keyModeNormal = function(e) {
|
|
var bot, char, hash, height, href, image, next, prev, qrLink, rect, replies, reply, root, sign, td, thread, top, watchButton, _i, _j, _len, _len2;
|
|
if (e.ctrlKey || e.altKey) {
|
|
return;
|
|
}
|
|
char = g.char;
|
|
hash = location.hash;
|
|
switch (char) {
|
|
case "0":
|
|
return location.pathname = "/" + g.BOARD;
|
|
case "G":
|
|
if (e.shiftKey) {
|
|
return window.scrollTo(0, 99999);
|
|
} else {
|
|
window.scrollTo(0, 0);
|
|
return location.hash = '';
|
|
}
|
|
break;
|
|
case "I":
|
|
if (g.REPLY) {
|
|
if (!(qrLink = $('td.replyhl span[id] a:not(:first-child)'))) {
|
|
qrLink = $("span[id^=nothread] a:not(:first-child)");
|
|
}
|
|
} else {
|
|
thread = getThread()[0];
|
|
if (!(qrLink = $('td.replyhl span[id] a:not(:first-child)', thread))) {
|
|
qrLink = $("span#nothread" + thread.id + " a:not(:first-child)", thread);
|
|
}
|
|
}
|
|
if (e.shiftKey) {
|
|
return quickReply(qrLink);
|
|
} else {
|
|
return quickReply(qrLink, qrText(qrLink));
|
|
}
|
|
break;
|
|
case "J":
|
|
if (e.shiftKey) {
|
|
if (!g.REPLY) {
|
|
root = getThread()[0];
|
|
}
|
|
if (td = $('td.replyhl', root)) {
|
|
td.className = 'reply';
|
|
rect = td.getBoundingClientRect();
|
|
if (rect.top > 0 && rect.bottom < d.body.clientHeight) {
|
|
next = x('following::td[@class="reply"]', td);
|
|
rect = next.getBoundingClientRect();
|
|
if (rect.top > 0 && rect.bottom < d.body.clientHeight) {
|
|
next.className = 'replyhl';
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
replies = $$('td.reply', root);
|
|
for (_i = 0, _len = replies.length; _i < _len; _i++) {
|
|
reply = replies[_i];
|
|
top = reply.getBoundingClientRect().top;
|
|
if (top > 0) {
|
|
reply.className = 'replyhl';
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case "K":
|
|
if (e.shiftKey) {
|
|
if (!g.REPLY) {
|
|
root = getThread()[0];
|
|
}
|
|
if (td = $('td.replyhl', root)) {
|
|
td.className = 'reply';
|
|
rect = td.getBoundingClientRect();
|
|
if (rect.top > 0 && rect.bottom < d.body.clientHeight) {
|
|
prev = x('preceding::td[@class="reply"][1]', td);
|
|
rect = prev.getBoundingClientRect();
|
|
if (rect.top > 0 && rect.bottom < d.body.clientHeight) {
|
|
prev.className = 'replyhl';
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
replies = $$('td.reply', root);
|
|
replies.reverse();
|
|
height = d.body.clientHeight;
|
|
for (_j = 0, _len2 = replies.length; _j < _len2; _j++) {
|
|
reply = replies[_j];
|
|
bot = reply.getBoundingClientRect().bottom;
|
|
if (bot < height) {
|
|
reply.className = 'replyhl';
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case "M":
|
|
if (e.shiftKey) {
|
|
return $("#imageExpand").click();
|
|
} else {
|
|
if (!g.REPLY) {
|
|
root = getThread()[0];
|
|
}
|
|
if (!(image = $('td.replyhl span.filesize ~ a[target]', root))) {
|
|
image = $('span.filesize ~ a[target]', root);
|
|
}
|
|
return imageToggle(image);
|
|
}
|
|
break;
|
|
case "N":
|
|
sign = e.shiftKey ? -1 : 1;
|
|
return scrollThread(sign);
|
|
case "O":
|
|
href = $("" + hash + " ~ span[id] a:last-of-type").href;
|
|
if (e.shiftKey) {
|
|
return location.href = href;
|
|
} else {
|
|
return GM_openInTab(href);
|
|
}
|
|
break;
|
|
case "U":
|
|
return updateNow();
|
|
case "W":
|
|
root = g.REPLY ? null : getThread()[0];
|
|
watchButton = $("span.filesize ~ img", root);
|
|
return watch.call(watchButton);
|
|
}
|
|
};
|
|
nodeInserted = function(e) {
|
|
var callback, qr, target, _i, _len, _ref, _results;
|
|
target = e.target;
|
|
if (target.nodeName === 'TABLE') {
|
|
_ref = g.callbacks;
|
|
_results = [];
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
callback = _ref[_i];
|
|
_results.push(callback(target));
|
|
}
|
|
return _results;
|
|
} else if (target.id === 'recaptcha_challenge_field' && (qr = $('#qr'))) {
|
|
$('#recaptcha_image img', qr).src = "http://www.google.com/recaptcha/api/image?c=" + target.value;
|
|
return $('#recaptcha_challenge_field', qr).value = target.value;
|
|
}
|
|
};
|
|
onloadComment = function(responseText, a, href) {
|
|
var bq, html, id, op, opbq, replies, reply, _, _i, _len, _ref, _ref2;
|
|
_ref = href.match(/(\d+)#(\d+)/), _ = _ref[0], op = _ref[1], id = _ref[2];
|
|
_ref2 = parseResponse(responseText), replies = _ref2[0], opbq = _ref2[1];
|
|
if (id === op) {
|
|
html = opbq.innerHTML;
|
|
} else {
|
|
for (_i = 0, _len = replies.length; _i < _len; _i++) {
|
|
reply = replies[_i];
|
|
if (reply.id === id) {
|
|
html = $('blockquote', reply).innerHTML;
|
|
}
|
|
}
|
|
}
|
|
bq = x('ancestor::blockquote', a);
|
|
return bq.innerHTML = html;
|
|
};
|
|
onloadThread = function(responseText, span) {
|
|
var div, next, opbq, replies, reply, _i, _j, _len, _len2, _ref, _results, _results2;
|
|
_ref = parseResponse(responseText), replies = _ref[0], opbq = _ref[1];
|
|
span.textContent = span.textContent.replace('X Loading...', '- ');
|
|
span.previousSibling.innerHTML = opbq.innerHTML;
|
|
while ((next = span.nextSibling) && !next.clear) {
|
|
rm(next);
|
|
}
|
|
if (next) {
|
|
_results = [];
|
|
for (_i = 0, _len = replies.length; _i < _len; _i++) {
|
|
reply = replies[_i];
|
|
_results.push(inBefore(next, x('ancestor::table', reply)));
|
|
}
|
|
return _results;
|
|
} else {
|
|
div = span.parentNode;
|
|
_results2 = [];
|
|
for (_j = 0, _len2 = replies.length; _j < _len2; _j++) {
|
|
reply = replies[_j];
|
|
_results2.push(mv(x('ancestor::table', reply), div));
|
|
}
|
|
return _results2;
|
|
}
|
|
};
|
|
changeCheckbox = function() {
|
|
return GM_setValue(this.name, this.checked);
|
|
};
|
|
changeValue = function() {
|
|
return GM_setValue(this.name, this.value);
|
|
};
|
|
options = function() {
|
|
var checked, description, div, hiddenNum, html, input, option, value, _i, _len, _ref;
|
|
if (div = $('#options')) {
|
|
rm(div);
|
|
return;
|
|
}
|
|
hiddenNum = g.hiddenReplies.length + g.hiddenThreads.length;
|
|
html = '<div class="move">Options <a name=close>X</a></div><div>';
|
|
for (option in config) {
|
|
value = config[option];
|
|
description = value[1];
|
|
checked = getConfig(option) ? "checked" : "";
|
|
html += "<label title=\"" + description + "\">" + option + "<input " + checked + " name=\"" + option + "\" type=\"checkbox\"></label><br>";
|
|
}
|
|
html += "<div><a class=sauce>Flavors</a></div>";
|
|
html += "<div><textarea style=\"display: none;\" name=flavors>" + (GM_getValue('flavors', g.flavors)) + "</textarea></div>";
|
|
html += "<input type=\"button\" value=\"hidden: " + hiddenNum + "\"><br>";
|
|
div = new Dialog('options', 'center', html).el;
|
|
_ref = $$('input[type="checkbox"]', div);
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
input = _ref[_i];
|
|
input.addEventListener('change', changeCheckbox, true);
|
|
}
|
|
$('a.sauce', div).addEventListener('click', editSauce, true);
|
|
$('textarea', div).addEventListener('change', changeValue, true);
|
|
$('input[type="button"]', div).addEventListener('click', clearHidden, true);
|
|
return mv(div, d.body);
|
|
};
|
|
parseResponse = function(responseText) {
|
|
var body, opbq, replies;
|
|
body = n('body', {
|
|
innerHTML: responseText
|
|
});
|
|
replies = $$('td.reply', body);
|
|
opbq = $('blockquote', body);
|
|
return [replies, opbq];
|
|
};
|
|
qrListener = function(e) {
|
|
var link, text;
|
|
e.preventDefault();
|
|
link = e.target;
|
|
text = qrText(link);
|
|
return quickReply(link, text);
|
|
};
|
|
qrText = function(link) {
|
|
var id, s, selection, text, _ref;
|
|
text = '>>' + link.parentNode.id.match(/\d+$/)[0] + '\n';
|
|
selection = window.getSelection();
|
|
id = (_ref = x('preceding::span[@id][1]', selection.anchorNode)) != null ? _ref.id : void 0;
|
|
if ((s = selection.toString()) && (id === link.parentNode.id)) {
|
|
text += ">" + s;
|
|
}
|
|
return text;
|
|
};
|
|
quickReply = function(link, text) {
|
|
var auto, autoBox, clone, form, html, input, qr, script, submit, textarea, xpath, _i, _len, _ref, _ref2;
|
|
if (!(qr = $('#qr'))) {
|
|
html = "<div class=move>Quick Reply <input type=checkbox title=autohide><a name=close title=close>X</a></div>";
|
|
qr = new Dialog('qr', 'topleft', html).el;
|
|
form = $('form[name=post]');
|
|
clone = form.cloneNode(true);
|
|
_ref = $$('script', clone);
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
script = _ref[_i];
|
|
rm(script);
|
|
}
|
|
m($('input[name=recaptcha_response_field]', clone), {
|
|
listener: ['keydown', recaptchaListener]
|
|
});
|
|
m(clone, {
|
|
listener: ['submit', formSubmit],
|
|
target: 'iframe'
|
|
});
|
|
if (!g.REPLY) {
|
|
xpath = 'preceding::span[@class="postername"][1]/preceding::input[1]';
|
|
input = n('input', {
|
|
type: 'hidden',
|
|
name: 'resto',
|
|
value: x(xpath, link).name
|
|
});
|
|
mv(input, clone);
|
|
} else if (getConfig('Persistent QR')) {
|
|
submit = $('input[type=submit]', clone);
|
|
auto = n('label', {
|
|
textContent: 'Auto'
|
|
});
|
|
autoBox = n('input', {
|
|
type: 'checkbox'
|
|
});
|
|
mv(autoBox, auto);
|
|
inBefore(submit, auto);
|
|
}
|
|
mv(clone, qr);
|
|
mv(qr, d.body);
|
|
}
|
|
if ((_ref2 = $('input[title=autohide]:checked', qr)) != null) {
|
|
_ref2.click();
|
|
}
|
|
textarea = $('textarea', qr);
|
|
textarea.focus();
|
|
if (text) {
|
|
return textarea.value += text;
|
|
}
|
|
};
|
|
recaptchaListener = function(e) {
|
|
if (e.keyCode === 8 && this.value === '') {
|
|
return recaptchaReload();
|
|
}
|
|
};
|
|
recaptchaReload = function() {
|
|
return window.location = 'javascript:Recaptcha.reload()';
|
|
};
|
|
redirect = function() {
|
|
var url;
|
|
switch (g.BOARD) {
|
|
case 'a':
|
|
case 'g':
|
|
case 'lit':
|
|
case 'sci':
|
|
case 'tv':
|
|
url = "http://green-oval.net/cgi-board.pl/" + g.BOARD + "/thread/" + g.THREAD_ID;
|
|
break;
|
|
case 'cgl':
|
|
case 'jp':
|
|
case 'm':
|
|
case 'tg':
|
|
url = "http://archive.easymodo.net/cgi-board.pl/" + g.BOARD + "/thread/" + g.THREAD_ID;
|
|
break;
|
|
case '3':
|
|
case 'adv':
|
|
case 'an':
|
|
case 'c':
|
|
case 'ck':
|
|
case 'co':
|
|
case 'fa':
|
|
case 'fit':
|
|
case 'int':
|
|
case 'k':
|
|
case 'mu':
|
|
case 'n':
|
|
case 'o':
|
|
case 'p':
|
|
case 'po':
|
|
case 'soc':
|
|
case 'sp':
|
|
case 'toy':
|
|
case 'trv':
|
|
case 'v':
|
|
case 'vp':
|
|
case 'x':
|
|
url = "http://archive.no-ip.org/" + g.BOARD + "/thread/" + g.THREAD_ID;
|
|
break;
|
|
default:
|
|
url = "http://boards.4chan.org/" + g.BOARD;
|
|
}
|
|
return location.href = url;
|
|
};
|
|
replyNav = function() {
|
|
var direction, op;
|
|
if (g.REPLY) {
|
|
return window.location = this.textContent === '▲' ? '#navtop' : '#navbot';
|
|
} else {
|
|
direction = this.textContent === '▲' ? 'preceding' : 'following';
|
|
op = x("" + direction + "::span[starts-with(@id, 'nothread')][1]", this).id;
|
|
return window.location = "#" + op;
|
|
}
|
|
};
|
|
report = function() {
|
|
var input;
|
|
input = x('preceding-sibling::input[1]', this);
|
|
input.click();
|
|
$('input[value="Report"]').click();
|
|
return input.click();
|
|
};
|
|
scrollThread = function(count) {
|
|
var hash, idx, temp, thread, top, _ref;
|
|
_ref = getThread(), thread = _ref[0], idx = _ref[1];
|
|
top = thread.getBoundingClientRect().top;
|
|
if (idx === 0 && top > 1) {
|
|
idx = -1;
|
|
}
|
|
if (count < 0 && top < -1) {
|
|
count++;
|
|
}
|
|
temp = idx + count;
|
|
if (temp < 0) {
|
|
hash = '';
|
|
} else if (temp > 9) {
|
|
hash = 'p9';
|
|
} else {
|
|
hash = "p" + temp;
|
|
}
|
|
return location.hash = hash;
|
|
};
|
|
showReply = function() {
|
|
var div, id, table;
|
|
div = this.parentNode;
|
|
table = div.nextSibling;
|
|
show(table);
|
|
rm(div);
|
|
id = $('td.reply, td.replyhl', table).id;
|
|
slice(g.hiddenReplies, id);
|
|
return GM_setValue("hiddenReplies/" + g.BOARD + "/", JSON.stringify(g.hiddenReplies));
|
|
};
|
|
showThread = function() {
|
|
var div, id;
|
|
div = this.nextSibling;
|
|
show(div);
|
|
hide(this);
|
|
id = div.id;
|
|
slice(g.hiddenThreads, id);
|
|
return GM_setValue("hiddenThreads/" + g.BOARD + "/", JSON.stringify(g.hiddenThreads));
|
|
};
|
|
stopPropagation = function(e) {
|
|
return e.stopPropagation();
|
|
};
|
|
threadF = function(current) {
|
|
var a, div, hidden, id, _i, _len, _ref;
|
|
div = n('div', {
|
|
className: 'thread'
|
|
});
|
|
a = n('a', {
|
|
textContent: '[ - ]',
|
|
className: 'pointer',
|
|
listener: ['click', hideThread]
|
|
});
|
|
mv(a, div);
|
|
inBefore(current, div);
|
|
while (!current.clear) {
|
|
mv(current, div);
|
|
current = div.nextSibling;
|
|
}
|
|
mv(current, div);
|
|
current = div.nextSibling;
|
|
id = $('input[value="delete"]', div).name;
|
|
div.id = id;
|
|
_ref = g.hiddenThreads;
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
hidden = _ref[_i];
|
|
if (id === hidden.id) {
|
|
hideThread(div);
|
|
}
|
|
}
|
|
current = current.nextSibling.nextSibling;
|
|
if (current.nodeName !== 'CENTER') {
|
|
return threadF(current);
|
|
}
|
|
};
|
|
request = function(url, callback) {
|
|
var r;
|
|
r = new XMLHttpRequest();
|
|
r.onload = callback;
|
|
r.open('get', url, true);
|
|
r.send();
|
|
return r;
|
|
};
|
|
updateCallback = function() {
|
|
var arr, body, count, id, input, l, replies, reply, root, s, table, timer, _i, _len, _ref;
|
|
count = $('#updater #count');
|
|
timer = $('#updater #timer');
|
|
if (this.status === 404) {
|
|
count.textContent = 404;
|
|
count.className = 'error';
|
|
timer.textContent = '';
|
|
clearInterval(g.interval);
|
|
_ref = $$('input[type=submit]');
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
input = _ref[_i];
|
|
input.disabled = true;
|
|
input.value = 404;
|
|
}
|
|
s = '';
|
|
if (getConfig('Unread Count')) {
|
|
s += "(" + g.replies.length + ") ";
|
|
}
|
|
s += "/" + g.BOARD + "/ - 404";
|
|
d.title = s;
|
|
g.dead = true;
|
|
updateFavicon();
|
|
return;
|
|
}
|
|
body = n('body', {
|
|
innerHTML: this.responseText
|
|
});
|
|
replies = $$('td.reply', body);
|
|
root = $('br[clear]');
|
|
if (reply = $('td.reply, td.replyhl', root.previousElementSibling)) {
|
|
id = Number(reply.id);
|
|
} else {
|
|
id = 0;
|
|
}
|
|
arr = [];
|
|
while ((reply = replies.pop()) && (Number(reply.id > id))) {
|
|
arr.push(reply);
|
|
}
|
|
if (g.verbose) {
|
|
l = arr.length;
|
|
count.textContent = "+" + l;
|
|
count.className = l > 0 ? 'new' : '';
|
|
}
|
|
while (reply = arr.pop()) {
|
|
table = x('ancestor::table', reply);
|
|
inBefore(root, table);
|
|
}
|
|
return timer.textContent = -1 * GM_getValue('Interval', 10);
|
|
};
|
|
updateFavicon = function() {
|
|
var clone, favicon, href, len;
|
|
len = g.replies.length;
|
|
if (g.dead) {
|
|
if (len > 0) {
|
|
href = g.favDeadHalo;
|
|
} else {
|
|
href = g.favDead;
|
|
}
|
|
} else {
|
|
if (len > 0) {
|
|
href = g.favHalo;
|
|
} else {
|
|
href = g.favDefault;
|
|
}
|
|
}
|
|
favicon = $('link[rel="shortcut icon"]', d);
|
|
clone = favicon.cloneNode(true);
|
|
clone.href = href;
|
|
return replace(favicon, clone);
|
|
};
|
|
updateTime = function() {
|
|
var count, span, time;
|
|
span = $('#updater #timer');
|
|
time = Number(span.textContent);
|
|
if (++time === 0) {
|
|
return updateNow();
|
|
} else if (time > 10) {
|
|
time = 0;
|
|
g.req.abort();
|
|
updateNow();
|
|
if (g.verbose) {
|
|
count = $('#updater #count');
|
|
count.textContent = 'retry';
|
|
return count.className = '';
|
|
}
|
|
} else {
|
|
return span.textContent = time;
|
|
}
|
|
};
|
|
updateTitle = function() {
|
|
var len;
|
|
len = g.replies.length;
|
|
d.title = d.title.replace(/\d+/, len);
|
|
return updateFavicon();
|
|
};
|
|
updateAuto = function() {
|
|
var span;
|
|
span = $('#updater #timer');
|
|
if (this.checked) {
|
|
span.textContent = -1 * GM_getValue('Interval', 10);
|
|
return g.interval = window.setInterval(updateTime, 1000);
|
|
} else {
|
|
span.textContent = 'Thread Updater';
|
|
return clearInterval(g.interval);
|
|
}
|
|
};
|
|
updateInterval = function() {
|
|
var num, span;
|
|
if (!(num = Number(this.value))) {
|
|
num = 10;
|
|
}
|
|
this.value = num;
|
|
GM_setValue('Interval', num);
|
|
span = $('#updater #timer');
|
|
if (0 > Number(span.textContent)) {
|
|
return span.textContent = -1 * num;
|
|
}
|
|
};
|
|
updateNow = function() {
|
|
var url;
|
|
url = location.href + '?' + new Date().getTime();
|
|
g.req = request(url, updateCallback);
|
|
return $("#updater #timer").textContent = 0;
|
|
};
|
|
updateVerbose = function() {
|
|
var timer;
|
|
g.verbose = this.checked;
|
|
timer = $('#updater #timer');
|
|
if (this.checked) {
|
|
return timer.hidden = false;
|
|
} else {
|
|
timer.hidden = true;
|
|
return $("#updater #count").textContent = 'Thread Updater';
|
|
}
|
|
};
|
|
updaterMake = function() {
|
|
var div, html, input, interval, name, _i, _len, _ref;
|
|
html = "<div class=move><span id=count>Thread Updater</span> <span id=timer></span></div>";
|
|
html += "<div><label>Verbose<input type=checkbox name=verbose></label></div>";
|
|
html += "<div><label title=\"Make all threads auto update\">Auto Update Global<input type=checkbox name=autoG></label></div>";
|
|
html += "<div><label title=\"Make this thread auto update\">Auto Update Local<input type=checkbox name=autoL></label></div>";
|
|
html += "<div><label>Interval (s)<input type=text name=interval></label></div>";
|
|
html += "<div><input type=button value='Update Now'></div>";
|
|
div = new Dialog('updater', 'topright', html).el;
|
|
_ref = $$('input[type=checkbox]', div);
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
input = _ref[_i];
|
|
input.addEventListener('click', changeCheckbox, true);
|
|
name = input.name;
|
|
if (name === 'autoL') {
|
|
input.checked = GM_getValue('autoG', true);
|
|
} else {
|
|
input.checked = GM_getValue(name, true);
|
|
}
|
|
switch (name) {
|
|
case 'autoL':
|
|
input.addEventListener('click', updateAuto, true);
|
|
break;
|
|
case 'verbose':
|
|
input.addEventListener('click', updateVerbose, true);
|
|
}
|
|
}
|
|
if (!(g.verbose = GM_getValue('verbose', true))) {
|
|
$("#timer", div).hidden = true;
|
|
}
|
|
interval = $('input[name=interval]', div);
|
|
interval.value = GM_getValue('Interval', 10);
|
|
interval.addEventListener('change', updateInterval, true);
|
|
$('input[type=button]', div).addEventListener('click', updateNow, true);
|
|
d.body.appendChild(div);
|
|
if (GM_getValue('autoG')) {
|
|
return updateAuto.call($("input[name=autoL]", div));
|
|
}
|
|
};
|
|
watch = function() {
|
|
var id, text, _base, _name;
|
|
id = this.nextSibling.name;
|
|
if (this.src === g.favEmpty) {
|
|
this.src = g.favDefault;
|
|
text = ("/" + g.BOARD + "/ - ") + x('following-sibling::blockquote', this).textContent.slice(0, 25);
|
|
(_base = g.watched)[_name = g.BOARD] || (_base[_name] = []);
|
|
g.watched[g.BOARD].push({
|
|
id: id,
|
|
text: text
|
|
});
|
|
} else {
|
|
this.src = g.favEmpty;
|
|
g.watched[g.BOARD] = slice(g.watched[g.BOARD], id);
|
|
}
|
|
GM_setValue('watched', JSON.stringify(g.watched));
|
|
return watcherUpdate();
|
|
};
|
|
watcherUpdate = function() {
|
|
var a, board, div, link, old, thread, _i, _len, _ref;
|
|
div = n('div');
|
|
for (board in g.watched) {
|
|
_ref = g.watched[board];
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
thread = _ref[_i];
|
|
a = n('a', {
|
|
textContent: 'X',
|
|
className: 'pointer',
|
|
listener: ['click', watchX]
|
|
});
|
|
link = n('a', {
|
|
textContent: thread.text,
|
|
href: "/" + board + "/res/" + thread.id
|
|
});
|
|
mv(a, tn(' '), link, n('br'), div);
|
|
}
|
|
}
|
|
old = $('#watcher div:last-child');
|
|
return replace(old, div);
|
|
};
|
|
watchX = function() {
|
|
var board, favicon, id, input, _, _ref;
|
|
_ref = this.nextElementSibling.getAttribute('href').substring(1).split('/'), board = _ref[0], _ = _ref[1], id = _ref[2];
|
|
g.watched[board] = slice(g.watched[board], id);
|
|
GM_setValue('watched', JSON.stringify(g.watched));
|
|
watcherUpdate();
|
|
if (input = $("input[name=\"" + id + "\"]")) {
|
|
favicon = input.previousSibling;
|
|
return favicon.src = g.favEmpty;
|
|
}
|
|
};
|
|
g = {
|
|
callbacks: [],
|
|
expand: false,
|
|
favDead: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAACVBMVEUAAAAAAAD/AAA9+90tAAAAAXRSTlMAQObYZgAAADtJREFUCB0FwUERxEAIALDszMG730PNSkBEBSECoU0AEPe0mly5NWprRUcDQAdn68qtkVsj3/84z++CD5u7CsnoBJoaAAAAAElFTkSuQmCC',
|
|
favDeadHalo: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAWUlEQVR4XrWSAQoAIAgD/f+njSApsTqjGoTQ5oGWPJMOOs60CzsWwIwz1I4PUIYh+WYEMGQ6I/txw91kP4oA9BdwhKp1My4xQq6e8Q9ANgDJjOErewFiNesV2uGSfGv1/HYAAAAASUVORK5CYII=',
|
|
favDefault: ((_ref = $('link[rel="shortcut icon"]', d)) != null ? _ref.href : void 0) || '',
|
|
favEmpty: 'http://static.4chan.org/image/favicon-dis.ico',
|
|
flavors: ['http://regex.info/exif.cgi?url=', 'http://iqdb.org/?url=', 'http://saucenao.com/search.php?db=999&url=', 'http://tineye.com/search?url='].join('\n'),
|
|
iframe: false,
|
|
watched: JSON.parse(GM_getValue('watched', '{}')),
|
|
xhrs: []
|
|
};
|
|
g.favHalo = /ws/.test(g.favDefault) ? 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAZklEQVR4XrWRQQoAIQwD+6L97j7Ih9WTQQxhDqJQCk4Mranuvqod6LgwawSqSuUmWSPw/UNlJlnDAmA2ARjABLYj8ZyCzJHHqOg+GdAKZmKPIQUzuYrxicHqEgHzP9g7M0+hj45sAnRWxtPj3zSPAAAAAElFTkSuQmCC' : 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQAgMAAABinRfyAAAADFBMVEUAAABmzDP///8AAABet0i+AAAAAXRSTlMAQObYZgAAAExJREFUeF4tyrENgDAMAMFXKuQswQLBG3mOlBnFS1gwDfIYLpEivvjq2MlqjmYvYg5jWEzCwtDSQlwcXKCVLrpFbvLvvSf9uZJ2HusDtJAY7Tkn1oYAAAAASUVORK5CYII=';
|
|
pathname = location.pathname.substring(1).split('/');
|
|
g.BOARD = pathname[0], temp = pathname[1];
|
|
if (temp === 'res') {
|
|
g.REPLY = temp;
|
|
g.THREAD_ID = pathname[2];
|
|
} else {
|
|
g.PAGENUM = parseInt(temp) || 0;
|
|
}
|
|
g.hiddenThreads = JSON.parse(GM_getValue("hiddenThreads/" + g.BOARD + "/", '[]'));
|
|
g.hiddenReplies = JSON.parse(GM_getValue("hiddenReplies/" + g.BOARD + "/", '[]'));
|
|
tzOffset = (new Date()).getTimezoneOffset() / 60;
|
|
g.chanOffset = 5 - tzOffset;
|
|
if (location.hostname.split('.')[0] === 'sys') {
|
|
if (recaptcha = $('#recaptcha_response_field')) {
|
|
m(recaptcha, {
|
|
listener: ['keydown', recaptchaListener]
|
|
});
|
|
} else if (b = $('table font b')) {
|
|
GM_setValue('error', b.firstChild.textContent);
|
|
} else {
|
|
GM_setValue('error', '');
|
|
if (getConfig('Auto Watch')) {
|
|
html = $('b').innerHTML;
|
|
_ref2 = html.match(/<!-- thread:(\d+),no:(\d+) -->/), _ = _ref2[0], thread = _ref2[1], id = _ref2[2];
|
|
if (thread === '0') {
|
|
board = $('meta', d).content.match(/4chan.org\/(\w+)\//)[1];
|
|
(_base = g.watched)[board] || (_base[board] = []);
|
|
g.watched[board].push({
|
|
id: id,
|
|
text: GM_getValue('autoText')
|
|
});
|
|
GM_setValue('watched', JSON.stringify(g.watched));
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
lastChecked = GM_getValue('lastChecked', 0);
|
|
now = getTime();
|
|
DAY = 24 * 60 * 60;
|
|
if (lastChecked < now - 1 * DAY) {
|
|
cutoff = now - 7 * DAY;
|
|
while (g.hiddenThreads.length) {
|
|
if (g.hiddenThreads[0].timestamp > cutoff) {
|
|
break;
|
|
}
|
|
g.hiddenThreads.shift();
|
|
}
|
|
while (g.hiddenReplies.length) {
|
|
if (g.hiddenReplies[0].timestamp > cutoff) {
|
|
break;
|
|
}
|
|
g.hiddenReplies.shift();
|
|
}
|
|
GM_setValue("hiddenThreads/" + g.BOARD + "/", JSON.stringify(g.hiddenThreads));
|
|
GM_setValue("hiddenReplies/" + g.BOARD + "/", JSON.stringify(g.hiddenReplies));
|
|
GM_setValue('lastChecked', now);
|
|
}
|
|
GM_addStyle('\
|
|
#options textarea {\
|
|
height: 100px;\
|
|
width: 500px;\
|
|
}\
|
|
#updater {\
|
|
position: fixed;\
|
|
text-align: right;\
|
|
}\
|
|
#updater input[type=text] {\
|
|
width: 50px;\
|
|
}\
|
|
#updater:not(:hover) {\
|
|
border: none;\
|
|
background: transparent;\
|
|
}\
|
|
#updater:not(:hover) > div:not(.move) {\
|
|
display: none;\
|
|
}\
|
|
#watcher {\
|
|
position: absolute;\
|
|
}\
|
|
#watcher > div.move {\
|
|
text-decoration: underline;\
|
|
padding: 5px 5px 0 5px;\
|
|
}\
|
|
#watcher > div:last-child {\
|
|
padding: 0 5px 5px 5px;\
|
|
}\
|
|
span.error {\
|
|
color: red;\
|
|
}\
|
|
#qr.auto:not(:hover) form {\
|
|
visibility: collapse;\
|
|
}\
|
|
#qr span.error {\
|
|
position: absolute;\
|
|
bottom: 0;\
|
|
left: 0;\
|
|
}\
|
|
#qr {\
|
|
position: fixed;\
|
|
}\
|
|
#qr > div {\
|
|
text-align: right;\
|
|
}\
|
|
#qr > form > div, /* ad */\
|
|
#qr td.rules {\
|
|
display: none;\
|
|
}\
|
|
#options {\
|
|
position: fixed;\
|
|
padding: 5px;\
|
|
text-align: right;\
|
|
}\
|
|
form[name=delform] a img {\
|
|
border: 0px;\
|
|
float: left;\
|
|
margin: 0px 20px;\
|
|
}\
|
|
span.navlinks {\
|
|
position: absolute;\
|
|
right: 5px;\
|
|
}\
|
|
span.navlinks > a {\
|
|
font-size: 16px;\
|
|
text-decoration: none;\
|
|
}\
|
|
.hide {\
|
|
display: none;\
|
|
}\
|
|
.new {\
|
|
background: lime;\
|
|
}\
|
|
');
|
|
if (navtopr = $('#navtopr a')) {
|
|
text = navtopr.nextSibling;
|
|
a = n('a', {
|
|
textContent: 'X',
|
|
className: 'pointer',
|
|
listener: ['click', options]
|
|
});
|
|
inBefore(text, tn(' / '));
|
|
inBefore(text, a);
|
|
navbotr = $('#navbotr a');
|
|
text = navbotr.nextSibling;
|
|
a = n('a', {
|
|
textContent: 'X',
|
|
className: 'pointer',
|
|
listener: ['click', options]
|
|
});
|
|
inBefore(text, tn(' / '));
|
|
inBefore(text, a);
|
|
} else if (getConfig('404 Redirect') && d.title === '4chan - 404') {
|
|
redirect();
|
|
} else {
|
|
return;
|
|
}
|
|
_ref3 = $$('#recaptcha_table a');
|
|
for (_i = 0, _len = _ref3.length; _i < _len; _i++) {
|
|
el = _ref3[_i];
|
|
el.tabIndex = 1;
|
|
}
|
|
recaptcha = $('#recaptcha_response_field');
|
|
recaptcha.addEventListener('keydown', recaptchaListener, true);
|
|
scroll = function() {
|
|
var bottom, height, i, reply, _len, _ref;
|
|
height = d.body.clientHeight;
|
|
_ref = g.replies;
|
|
for (i = 0, _len = _ref.length; i < _len; i++) {
|
|
reply = _ref[i];
|
|
bottom = reply.getBoundingClientRect().bottom;
|
|
if (bottom > height) {
|
|
break;
|
|
}
|
|
}
|
|
if (i === 0) {
|
|
return;
|
|
}
|
|
g.replies = g.replies.slice(i);
|
|
return updateTitle();
|
|
};
|
|
if ((getConfig('Restore IDs')) && ((_ref4 = g.BOARD) === 'b' || _ref4 === 'v')) {
|
|
g.callbacks.push(function(root) {
|
|
var quote, quotes, _i, _len, _results;
|
|
quotes = $$('a.quotejs:not(:first-child)', root);
|
|
_results = [];
|
|
for (_i = 0, _len = quotes.length; _i < _len; _i++) {
|
|
quote = quotes[_i];
|
|
_results.push(quote.textContent = quote.parentNode.id.match(/\d+$/)[0]);
|
|
}
|
|
return _results;
|
|
});
|
|
}
|
|
if (getConfig('Image Expansion')) {
|
|
delform = $('form[name=delform]');
|
|
expand = n('div', {
|
|
innerHTML: "<select id=imageType name=imageType><option>full</option><option>fit width</option><option>fit screen</option></select> <label>Expand Images<input type=checkbox id=imageExpand></label>"
|
|
});
|
|
imageType = GM_getValue('imageType', 'full');
|
|
_ref5 = $$("option", expand);
|
|
for (_j = 0, _len2 = _ref5.length; _j < _len2; _j++) {
|
|
option = _ref5[_j];
|
|
if (option.textContent === imageType) {
|
|
option.selected = true;
|
|
break;
|
|
}
|
|
}
|
|
$("select", expand).addEventListener('change', changeValue, true);
|
|
$("select", expand).addEventListener('change', imageTypeChange, true);
|
|
$("input", expand).addEventListener('click', imageExpandClick, true);
|
|
inBefore(delform.firstChild, expand);
|
|
g.callbacks.push(function(root) {
|
|
var thumb, thumbs, _i, _len, _results;
|
|
thumbs = $$('img[md5]', root);
|
|
_results = [];
|
|
for (_i = 0, _len = thumbs.length; _i < _len; _i++) {
|
|
thumb = thumbs[_i];
|
|
thumb.parentNode.addEventListener('click', imageClick, true);
|
|
_results.push(g.expand ? imageToggle(thumb.parentNode) : void 0);
|
|
}
|
|
return _results;
|
|
});
|
|
}
|
|
if (getConfig('Image Preloading')) {
|
|
g.callbacks.push(function(root) {
|
|
var parent, thumb, thumbs, _i, _len, _results;
|
|
thumbs = $$('img[md5]', root);
|
|
_results = [];
|
|
for (_i = 0, _len = thumbs.length; _i < _len; _i++) {
|
|
thumb = thumbs[_i];
|
|
parent = thumb.parentNode;
|
|
_results.push(el = n('img', {
|
|
src: parent.href
|
|
}));
|
|
}
|
|
return _results;
|
|
});
|
|
}
|
|
if (getConfig('Localize Time')) {
|
|
g.callbacks.push(function(root) {
|
|
var date, day, dotw, hour, min_sec, month, s, span, spans, year, _i, _len, _ref, _results;
|
|
spans = $$('span[id^=no]', root);
|
|
_results = [];
|
|
for (_i = 0, _len = spans.length; _i < _len; _i++) {
|
|
span = spans[_i];
|
|
s = span.previousSibling;
|
|
_ref = s.textContent.match(/(\d+)\/(\d+)\/(\d+)\(\w+\)(\d+):(\S+)/), _ = _ref[0], month = _ref[1], day = _ref[2], year = _ref[3], hour = _ref[4], min_sec = _ref[5];
|
|
year = "20" + year;
|
|
month -= 1;
|
|
hour = g.chanOffset + Number(hour);
|
|
date = new Date(year, month, day, hour);
|
|
year = date.getFullYear() - 2000;
|
|
month = zeroPad(date.getMonth() + 1);
|
|
day = zeroPad(date.getDate());
|
|
hour = zeroPad(date.getHours());
|
|
dotw = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'][date.getDay()];
|
|
_results.push(s.textContent = " " + month + "/" + day + "/" + year + "(" + dotw + ")" + hour + ":" + min_sec + " ");
|
|
}
|
|
return _results;
|
|
});
|
|
}
|
|
if (getConfig('Sauce')) {
|
|
g.callbacks.push(function(root) {
|
|
var i, l, link, names, prefix, prefixes, span, spans, suffix, _i, _len, _results;
|
|
spans = $$('span.filesize', root);
|
|
prefixes = GM_getValue('flavors', g.flavors).split('\n');
|
|
names = (function() {
|
|
var _i, _len, _results;
|
|
_results = [];
|
|
for (_i = 0, _len = prefixes.length; _i < _len; _i++) {
|
|
prefix = prefixes[_i];
|
|
_results.push(prefix.match(/(\w+)\./)[1]);
|
|
}
|
|
return _results;
|
|
})();
|
|
_results = [];
|
|
for (_i = 0, _len = spans.length; _i < _len; _i++) {
|
|
span = spans[_i];
|
|
suffix = $('a', span).href;
|
|
i = 0;
|
|
l = names.length;
|
|
_results.push((function() {
|
|
var _results;
|
|
_results = [];
|
|
while (i < l) {
|
|
link = n('a', {
|
|
textContent: names[i],
|
|
href: prefixes[i] + suffix
|
|
});
|
|
mv(tn(' '), link, span);
|
|
_results.push(i++);
|
|
}
|
|
return _results;
|
|
})());
|
|
}
|
|
return _results;
|
|
});
|
|
}
|
|
if (getConfig('Reply Hiding')) {
|
|
g.callbacks.push(function(root) {
|
|
var next, obj, td, tds, _i, _len, _results;
|
|
tds = $$('td.doubledash', root);
|
|
_results = [];
|
|
for (_i = 0, _len = tds.length; _i < _len; _i++) {
|
|
td = tds[_i];
|
|
a = n('a', {
|
|
textContent: '[ - ]',
|
|
className: 'pointer',
|
|
listener: ['click', hideReply]
|
|
});
|
|
replace(td.firstChild, a);
|
|
next = td.nextSibling;
|
|
id = next.id;
|
|
_results.push((function() {
|
|
var _i, _len, _ref, _results;
|
|
_ref = g.hiddenReplies;
|
|
_results = [];
|
|
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
|
obj = _ref[_i];
|
|
_results.push(obj.id === id ? hideReply(next) : void 0);
|
|
}
|
|
return _results;
|
|
})());
|
|
}
|
|
return _results;
|
|
});
|
|
}
|
|
if (getConfig('Quick Reply')) {
|
|
iframe = n('iframe', {
|
|
name: 'iframe',
|
|
listener: ['load', iframeLoad]
|
|
});
|
|
hide(iframe);
|
|
mv(iframe, d.body);
|
|
g.callbacks.push(function(root) {
|
|
var quote, quotes, _i, _len, _results;
|
|
quotes = $$('a.quotejs:not(:first-child)', root);
|
|
_results = [];
|
|
for (_i = 0, _len = quotes.length; _i < _len; _i++) {
|
|
quote = quotes[_i];
|
|
_results.push(quote.addEventListener('click', qrListener, true));
|
|
}
|
|
return _results;
|
|
});
|
|
recaptcha.id = '';
|
|
}
|
|
if (getConfig('Quick Report')) {
|
|
g.callbacks.push(function(root) {
|
|
var arr, el, _i, _len, _results;
|
|
arr = $$('span[id^=no]', root);
|
|
_results = [];
|
|
for (_i = 0, _len = arr.length; _i < _len; _i++) {
|
|
el = arr[_i];
|
|
a = n('a', {
|
|
textContent: '[ ! ]',
|
|
className: 'pointer',
|
|
listener: ['click', report]
|
|
});
|
|
inAfter(el, a);
|
|
_results.push(inAfter(el, tn(' ')));
|
|
}
|
|
return _results;
|
|
});
|
|
}
|
|
if (getConfig('Thread Watcher')) {
|
|
html = '<div class="move">Thread Watcher</div><div></div>';
|
|
watcher = new Dialog('watcher', 'topleft', html).el;
|
|
mv(watcher, d.body);
|
|
watcherUpdate();
|
|
threads = g.watched[g.BOARD] || [];
|
|
inputs = $$('form > input[value="delete"], div > input[value="delete"]');
|
|
for (_k = 0, _len3 = inputs.length; _k < _len3; _k++) {
|
|
input = inputs[_k];
|
|
id = input.name;
|
|
src = (function() {
|
|
var thread, _i, _len;
|
|
for (_i = 0, _len = threads.length; _i < _len; _i++) {
|
|
thread = threads[_i];
|
|
if (id === thread.id) {
|
|
return g.favDefault;
|
|
}
|
|
}
|
|
return g.favEmpty;
|
|
})();
|
|
img = n('img', {
|
|
src: src,
|
|
className: 'pointer',
|
|
listener: ['click', watch]
|
|
});
|
|
inBefore(input, img);
|
|
}
|
|
}
|
|
if (getConfig('Anonymize')) {
|
|
g.callbacks.push(function(root) {
|
|
var name, names, trip, trips, _i, _j, _len, _len2, _results;
|
|
names = $$('span.postername, span.commentpostername', root);
|
|
for (_i = 0, _len = names.length; _i < _len; _i++) {
|
|
name = names[_i];
|
|
name.innerHTML = 'Anonymous';
|
|
}
|
|
trips = $$('span.postertrip', root);
|
|
_results = [];
|
|
for (_j = 0, _len2 = trips.length; _j < _len2; _j++) {
|
|
trip = trips[_j];
|
|
_results.push(trip.parentNode.nodeName === 'A' ? rm(trip.parentNode) : rm(trip));
|
|
}
|
|
return _results;
|
|
});
|
|
}
|
|
if (getConfig('Reply Navigation')) {
|
|
g.callbacks.push(function(root) {
|
|
var arr, down, el, span, up, _i, _len, _results;
|
|
arr = $$('span[id^=norep]', root);
|
|
_results = [];
|
|
for (_i = 0, _len = arr.length; _i < _len; _i++) {
|
|
el = arr[_i];
|
|
span = n('span');
|
|
up = n('a', {
|
|
textContent: '▲',
|
|
className: 'pointer',
|
|
listener: ['click', replyNav]
|
|
});
|
|
down = n('a', {
|
|
textContent: '▼',
|
|
className: 'pointer',
|
|
listener: ['click', replyNav]
|
|
});
|
|
mv(tn(' '), up, tn(' '), down, span);
|
|
_results.push(inAfter(el, span));
|
|
}
|
|
return _results;
|
|
});
|
|
}
|
|
if (getConfig('Keybinds')) {
|
|
d.addEventListener('keydown', keydown, true);
|
|
d.addEventListener('keypress', keypress, true);
|
|
}
|
|
if (g.REPLY) {
|
|
if (getConfig('Thread Updater')) {
|
|
updaterMake();
|
|
}
|
|
if (getConfig('Quick Reply') && getConfig('Persistent QR')) {
|
|
quickReply();
|
|
$('#qr input[title=autohide]').click();
|
|
}
|
|
if (getConfig('Post in Title')) {
|
|
if (!(text = $('span.filetitle').textContent)) {
|
|
text = $('blockquote').textContent;
|
|
}
|
|
if (text) {
|
|
d.title = "/" + g.BOARD + "/ - " + text;
|
|
}
|
|
}
|
|
if (getConfig('Unread Count')) {
|
|
g.replies = [];
|
|
d.title = '(0) ' + d.title;
|
|
d.addEventListener('scroll', scroll, true);
|
|
g.callbacks.push(function(root) {
|
|
g.replies = g.replies.concat($$('td.reply, td.replyhl', root));
|
|
return updateTitle();
|
|
});
|
|
}
|
|
} else {
|
|
if (getConfig('Thread Hiding')) {
|
|
delform = $('form[name=delform]');
|
|
start = $('form[name=delform] > *');
|
|
if (getConfig('Image Expansion')) {
|
|
start = start.nextSibling;
|
|
}
|
|
d.addEventListener('DOMNodeInserted', stopPropagation, true);
|
|
threadF(start);
|
|
d.removeEventListener('DOMNodeInserted', stopPropagation, true);
|
|
}
|
|
if (getConfig('Auto Watch')) {
|
|
$('form[name="post"]').addEventListener('submit', autoWatch, true);
|
|
}
|
|
if (getConfig('Thread Navigation')) {
|
|
arr = $$('div > span.filesize, form > span.filesize');
|
|
l1 = arr.length - 1;
|
|
for (i = 0, _len4 = arr.length; i < _len4; i++) {
|
|
el = arr[i];
|
|
span = n('span', {
|
|
className: 'navlinks',
|
|
id: 'p' + i
|
|
});
|
|
if (i) {
|
|
textContent = '▲';
|
|
href = "#p" + (i - 1);
|
|
} else if (g.PAGENUM) {
|
|
textContent = '◀';
|
|
href = "" + (g.PAGENUM - 1) + "#p0";
|
|
} else {
|
|
textContent = '▲';
|
|
href = "#navtop";
|
|
}
|
|
up = n('a', {
|
|
className: 'pointer',
|
|
textContent: textContent,
|
|
href: href
|
|
});
|
|
if (i < l1) {
|
|
textContent = '▼';
|
|
href = "#p" + (i + 1);
|
|
} else {
|
|
textContent = '▶';
|
|
href = "" + (g.PAGENUM + 1) + "#p0";
|
|
}
|
|
down = n('a', {
|
|
className: 'pointer',
|
|
textContent: textContent,
|
|
href: href
|
|
});
|
|
mv(up, tn(' '), down, span);
|
|
inBefore(el, span);
|
|
}
|
|
if (location.hash === '#p0') {
|
|
window.location = window.location;
|
|
}
|
|
}
|
|
if (getConfig('Thread Expansion')) {
|
|
omitted = $$('span.omittedposts');
|
|
for (_l = 0, _len5 = omitted.length; _l < _len5; _l++) {
|
|
span = omitted[_l];
|
|
a = n('a', {
|
|
className: 'pointer omittedposts',
|
|
textContent: "+ " + span.textContent,
|
|
listener: ['click', expandThread]
|
|
});
|
|
replace(span, a);
|
|
}
|
|
}
|
|
if (getConfig('Comment Expansion')) {
|
|
as = $$('span.abbr a');
|
|
for (_m = 0, _len6 = as.length; _m < _len6; _m++) {
|
|
a = as[_m];
|
|
a.addEventListener('click', expandComment, true);
|
|
}
|
|
}
|
|
}
|
|
_ref6 = g.callbacks;
|
|
for (_n = 0, _len7 = _ref6.length; _n < _len7; _n++) {
|
|
callback = _ref6[_n];
|
|
callback();
|
|
}
|
|
d.body.addEventListener('DOMNodeInserted', nodeInserted, true);
|
|
}).call(this);
|