// ==UserScript== // @name 4chan x // @namespace aeosynth // @description Adds various features. // @version 1.23.1 // @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, 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; 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'], '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'); return; 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 = ''; } 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)); } 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); } 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); } 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.fav
Mozilla add on,User script,Grease Monkey Script, greasemonkey userscripts, updater userscripts mafia wars userscripts mafia wars autoplayer userscripts mafia wars wall userscripts scripts userscripts travian greasemonkey greasemonkey download greasemonkey facebook greasemonkey tutorial greasemonkey youtube greasemonkey travian greasemonkey chrome greasemonkey mafia wars greasemonkey mafia wars autoplayer
Saturday, January 22, 2011
4chan X
Subscribe to:
Post Comments (Atom)
0 comments:
Post a Comment