undo d -> $.d

This commit is contained in:
James Campos 2012-03-16 04:11:56 -07:00
parent 128dd341f7
commit 5dafc95c5d
2 changed files with 164 additions and 162 deletions

View File

@ -73,7 +73,7 @@
*/ */
(function() { (function() {
var $, $$, Anonymize, AutoGif, Config, ExpandComment, ExpandThread, Favicon, FileInfo, Filter, GetTitle, ImageExpand, ImageHover, Keybinds, Main, Nav, Options, QR, QuoteBacklink, QuoteCT, QuoteInline, QuoteOP, QuotePreview, Quotify, Redirect, ReplyHiding, ReportButton, RevealSpoilers, Sauce, StrikethroughQuotes, ThreadHiding, ThreadStats, Threading, Time, TitlePost, UI, Unread, Updater, Watcher, _base; var $, $$, Anonymize, AutoGif, Config, ExpandComment, ExpandThread, Favicon, FileInfo, Filter, GetTitle, ImageExpand, ImageHover, Keybinds, Main, Nav, Options, QR, QuoteBacklink, QuoteCT, QuoteInline, QuoteOP, QuotePreview, Quotify, Redirect, ReplyHiding, ReportButton, RevealSpoilers, Sauce, StrikethroughQuotes, ThreadHiding, ThreadStats, Threading, Time, TitlePost, UI, Unread, Updater, Watcher, d, _base;
Config = { Config = {
main: { main: {
@ -195,7 +195,7 @@
UI = { UI = {
dialog: function(id, position, html) { dialog: function(id, position, html) {
var el, saved; var el, saved;
el = $.d.createElement('div'); el = d.createElement('div');
el.className = 'reply dialog'; el.className = 'reply dialog';
el.innerHTML = html; el.innerHTML = html;
el.id = id; el.id = id;
@ -207,13 +207,13 @@
var el, rect; var el, rect;
e.preventDefault(); e.preventDefault();
UI.el = el = this.parentNode; UI.el = el = this.parentNode;
$.d.addEventListener('mousemove', UI.drag, false); d.addEventListener('mousemove', UI.drag, false);
$.d.addEventListener('mouseup', UI.dragend, false); d.addEventListener('mouseup', UI.dragend, false);
rect = el.getBoundingClientRect(); rect = el.getBoundingClientRect();
UI.dx = e.clientX - rect.left; UI.dx = e.clientX - rect.left;
UI.dy = e.clientY - rect.top; UI.dy = e.clientY - rect.top;
UI.width = $.d.body.clientWidth - el.offsetWidth; UI.width = d.body.clientWidth - el.offsetWidth;
return UI.height = $.d.body.clientHeight - el.offsetHeight; return UI.height = d.body.clientHeight - el.offsetHeight;
}, },
drag: function(e) { drag: function(e) {
var bottom, left, right, style, top; var bottom, left, right, style, top;
@ -233,15 +233,15 @@
var el; var el;
el = UI.el; el = UI.el;
localStorage["" + Main.namespace + el.id + ".position"] = el.style.cssText; localStorage["" + Main.namespace + el.id + ".position"] = el.style.cssText;
$.d.removeEventListener('mousemove', UI.drag, false); d.removeEventListener('mousemove', UI.drag, false);
return $.d.removeEventListener('mouseup', UI.dragend, false); return d.removeEventListener('mouseup', UI.dragend, false);
}, },
hover: function(e) { hover: function(e) {
var clientHeight, clientWidth, clientX, clientY, el, height, style, top, _ref; var clientHeight, clientWidth, clientX, clientY, el, height, style, top, _ref;
clientX = e.clientX, clientY = e.clientY; clientX = e.clientX, clientY = e.clientY;
el = UI.el; el = UI.el;
style = el.style; style = el.style;
_ref = $.d.body, clientHeight = _ref.clientHeight, clientWidth = _ref.clientWidth; _ref = d.body, clientHeight = _ref.clientHeight, clientWidth = _ref.clientWidth;
height = el.offsetHeight; height = el.offsetHeight;
top = clientY - 120; top = clientY - 120;
style.top = clientHeight <= height || top <= 0 ? 0 : top + height >= clientHeight ? clientHeight - height : top; style.top = clientHeight <= height || top <= 0 ? 0 : top + height >= clientHeight ? clientHeight - height : top;
@ -259,6 +259,8 @@
} }
}; };
d = document;
/* /*
loosely follows the jquery api: loosely follows the jquery api:
http://api.jquery.com/ http://api.jquery.com/
@ -266,7 +268,7 @@
*/ */
$ = function(selector, root) { $ = function(selector, root) {
if (root == null) root = $.d.body; if (root == null) root = d.body;
return root.querySelector(selector); return root.querySelector(selector);
}; };
@ -284,16 +286,15 @@
HOUR: 1000 * 60 * 60, HOUR: 1000 * 60 * 60,
DAY: 1000 * 60 * 60 * 24, DAY: 1000 * 60 * 60 * 24,
log: typeof (_base = console.log).bind === "function" ? _base.bind(console) : void 0, log: typeof (_base = console.log).bind === "function" ? _base.bind(console) : void 0,
d: document,
engine: /WebKit|Presto|Gecko/.exec(navigator.userAgent)[0].toLowerCase(), engine: /WebKit|Presto|Gecko/.exec(navigator.userAgent)[0].toLowerCase(),
ready: function(fc) { ready: function(fc) {
var cb; var cb;
if (/interactive|complete/.test($.d.readyState)) return setTimeout(fc); if (/interactive|complete/.test(d.readyState)) return setTimeout(fc);
cb = function() { cb = function() {
$.off($.d, 'DOMContentLoaded', cb); $.off(d, 'DOMContentLoaded', cb);
return fc(); return fc();
}; };
return $.on($.d, 'DOMContentLoaded', cb); return $.on(d, 'DOMContentLoaded', cb);
}, },
sync: function(key, cb) { sync: function(key, cb) {
return $.on(window, 'storage', function(e) { return $.on(window, 'storage', function(e) {
@ -303,7 +304,7 @@
}); });
}, },
id: function(id) { id: function(id) {
return $.d.getElementById(id); return d.getElementById(id);
}, },
ajax: function(url, callbacks, opts) { ajax: function(url, callbacks, opts) {
var form, headers, key, r, type, upCallbacks, val; var form, headers, key, r, type, upCallbacks, val;
@ -367,12 +368,12 @@
style = $.el('style', { style = $.el('style', {
textContent: css textContent: css
}); });
$.add($.d.head, style); $.add(d.head, style);
return style; return style;
}, },
x: function(path, root) { x: function(path, root) {
if (root == null) root = $.d.body; if (root == null) root = d.body;
return $.d.evaluate(path, root, null, 8, null).singleNodeValue; return d.evaluate(path, root, null, 8, null).singleNodeValue;
}, },
addClass: function(el, className) { addClass: function(el, className) {
return el.classList.add(className); return el.classList.add(className);
@ -384,12 +385,12 @@
return el.parentNode.removeChild(el); return el.parentNode.removeChild(el);
}, },
tn: function(s) { tn: function(s) {
return $.d.createTextNode(s); return d.createTextNode(s);
}, },
nodes: function(nodes) { nodes: function(nodes) {
var frag, node, _i, _len; var frag, node, _i, _len;
if (nodes instanceof Node) return nodes; if (nodes instanceof Node) return nodes;
frag = $.d.createDocumentFragment(); frag = d.createDocumentFragment();
for (_i = 0, _len = nodes.length; _i < _len; _i++) { for (_i = 0, _len = nodes.length; _i < _len; _i++) {
node = nodes[_i]; node = nodes[_i];
frag.appendChild(node); frag.appendChild(node);
@ -413,7 +414,7 @@
}, },
el: function(tag, properties) { el: function(tag, properties) {
var el; var el;
el = $.d.createElement(tag); el = d.createElement(tag);
if (properties) $.extend(el, properties); if (properties) $.extend(el, properties);
return el; return el;
}, },
@ -439,7 +440,7 @@
0200 EST (UTC-05) = 0700 UTC 0200 EST (UTC-05) = 0700 UTC
0200 EDT (UTC-04) = 0600 UTC 0200 EDT (UTC-04) = 0600 UTC
*/ */
var d, date, day, hours, month, sunday; var date, day, hours, month, sunday;
d = new Date(); d = new Date();
date = d.getUTCDate(); date = d.getUTCDate();
day = d.getUTCDay(); day = d.getUTCDay();
@ -507,7 +508,7 @@
}); });
$$ = function(selector, root) { $$ = function(selector, root) {
if (root == null) root = $.d.body; if (root == null) root = d.body;
return Array.prototype.slice.call(root.querySelectorAll(selector)); return Array.prototype.slice.call(root.querySelectorAll(selector));
}; };
@ -635,7 +636,7 @@
comment: function(post) { comment: function(post) {
var data, i, nodes, text, _ref; var data, i, nodes, text, _ref;
text = []; text = [];
nodes = $.d.evaluate('.//br|.//text()', post.el.lastChild, null, 7, null); nodes = d.evaluate('.//br|.//text()', post.el.lastChild, null, 7, null);
for (i = 0, _ref = nodes.snapshotLength; 0 <= _ref ? i < _ref : i > _ref; 0 <= _ref ? i++ : i--) { for (i = 0, _ref = nodes.snapshotLength; 0 <= _ref ? i < _ref : i > _ref; 0 <= _ref ? i++ : i--) {
text.push((data = nodes.snapshotItem(i).data) ? data : '\n'); text.push((data = nodes.snapshotItem(i).data) ? data : '\n');
} }
@ -713,10 +714,10 @@
a.textContent = "" + req.status + " " + req.statusText; a.textContent = "" + req.status + " " + req.statusText;
return; return;
} }
doc = $.d.implementation.createHTMLDocument(null); doc = d.implementation.createHTMLDocument(null);
doc.documentElement.innerHTML = req.responseText; doc.documentElement.innerHTML = req.responseText;
Threading.op($('body > form', doc).firstChild); Threading.op($('body > form', doc).firstChild);
node = $.d.importNode(doc.getElementById(replyID)); node = d.importNode(doc.getElementById(replyID));
quotes = node.getElementsByClassName('quotelink'); quotes = node.getElementsByClassName('quotelink');
for (_i = 0, _len = quotes.length; _i < _len; _i++) { for (_i = 0, _len = quotes.length; _i < _len; _i++) {
quote = quotes[_i]; quote = quotes[_i];
@ -816,13 +817,13 @@
return; return;
} }
a.textContent = a.textContent.replace('\u00d7 Loading...', '-'); a.textContent = a.textContent.replace('\u00d7 Loading...', '-');
doc = $.d.implementation.createHTMLDocument(null); doc = d.implementation.createHTMLDocument(null);
doc.documentElement.innerHTML = req.responseText; doc.documentElement.innerHTML = req.responseText;
nodes = []; nodes = [];
_ref = $$('.reply', doc); _ref = $$('.reply', doc);
for (_i = 0, _len = _ref.length; _i < _len; _i++) { for (_i = 0, _len = _ref.length; _i < _len; _i++) {
reply = _ref[_i]; reply = _ref[_i];
table = $.d.importNode(reply.parentNode.parentNode.parentNode); table = d.importNode(reply.parentNode.parentNode.parentNode);
_ref2 = $$('.quotelink', table); _ref2 = $$('.quotelink', table);
for (_j = 0, _len2 = _ref2.length; _j < _len2; _j++) { for (_j = 0, _len2 = _ref2.length; _j < _len2; _j++) {
quote = _ref2[_j]; quote = _ref2[_j];
@ -912,7 +913,7 @@
node = _ref[_i]; node = _ref[_i];
node.removeAttribute('accesskey'); node.removeAttribute('accesskey');
} }
return $.on($.d, 'keydown', Keybinds.keydown); return $.on(d, 'keydown', Keybinds.keydown);
}, },
keydown: function(e) { keydown: function(e) {
var key, o, range, selEnd, selStart, ta, thread, value, _ref, _ref2; var key, o, range, selEnd, selStart, ta, thread, value, _ref, _ref2;
@ -1108,7 +1109,7 @@
td.className = 'reply'; td.className = 'reply';
td.removeAttribute('tabindex'); td.removeAttribute('tabindex');
rect = td.getBoundingClientRect(); rect = td.getBoundingClientRect();
if (rect.bottom >= 0 && rect.top <= $.d.body.clientHeight) { if (rect.bottom >= 0 && rect.top <= d.body.clientHeight) {
next = delta === +1 ? $.x('following::td[@class="reply"]', td) : $.x('preceding::td[@class="reply"]', td); next = delta === +1 ? $.x('following::td[@class="reply"]', td) : $.x('preceding::td[@class="reply"]', td);
if (!next) { if (!next) {
td.className = 'replyhl'; td.className = 'replyhl';
@ -1120,7 +1121,7 @@
return; return;
} }
rect = next.getBoundingClientRect(); rect = next.getBoundingClientRect();
if (rect.top < 0 || rect.bottom > $.d.body.clientHeight) { if (rect.top < 0 || rect.bottom > d.body.clientHeight) {
next.scrollIntoView(delta === -1); next.scrollIntoView(delta === -1);
} }
next.className = 'replyhl'; next.className = 'replyhl';
@ -1134,7 +1135,7 @@
for (_i = 0, _len = replies.length; _i < _len; _i++) { for (_i = 0, _len = replies.length; _i < _len; _i++) {
reply = replies[_i]; reply = replies[_i];
rect = reply.getBoundingClientRect(); rect = reply.getBoundingClientRect();
if (delta === +1 && rect.top >= 0 || delta === -1 && rect.bottom <= $.d.body.clientHeight) { if (delta === +1 && rect.top >= 0 || delta === -1 && rect.bottom <= d.body.clientHeight) {
reply.className = 'replyhl'; reply.className = 'replyhl';
reply.tabIndex = 0; reply.tabIndex = 0;
reply.focus(); reply.focus();
@ -1161,7 +1162,7 @@
$.on(prev, 'click', this.prev); $.on(prev, 'click', this.prev);
$.on(next, 'click', this.next); $.on(next, 'click', this.next);
$.add(span, [prev, $.tn(' '), next]); $.add(span, [prev, $.tn(' '), next]);
return $.add($.d.body, span); return $.add(d.body, span);
}, },
prev: function() { prev: function() {
if (Main.REPLY) { if (Main.REPLY) {
@ -1172,7 +1173,7 @@
}, },
next: function() { next: function() {
if (Main.REPLY) { if (Main.REPLY) {
return window.scrollTo(0, $.d.body.scrollHeight); return window.scrollTo(0, d.body.scrollHeight);
} else { } else {
return Nav.scroll(+1); return Nav.scroll(+1);
} }
@ -1221,7 +1222,7 @@
if (!Main.REPLY) $('select', QR.el).value = 'new'; if (!Main.REPLY) $('select', QR.el).value = 'new';
return $('textarea', QR.el).focus(); return $('textarea', QR.el).focus();
}); });
form = $.d.forms[0]; form = d.forms[0];
$.before(form, link); $.before(form, link);
} }
if (/chrome/i.test(navigator.userAgent)) { if (/chrome/i.test(navigator.userAgent)) {
@ -1249,21 +1250,21 @@
return setTimeout(loadChecking, 500, this); return setTimeout(loadChecking, 500, this);
} }
}); });
$.add($.d.head, iframe); $.add(d.head, iframe);
} }
script = $.el('script', { script = $.el('script', {
textContent: 'Recaptcha.focus_response_field=function(){}' textContent: 'Recaptcha.focus_response_field=function(){}'
}); });
$.add($.d.head, script); $.add(d.head, script);
$.rm(script); $.rm(script);
if (Conf['Persistent QR']) { if (Conf['Persistent QR']) {
QR.dialog(); QR.dialog();
if (Conf['Auto Hide QR']) QR.hide(); if (Conf['Auto Hide QR']) QR.hide();
} }
$.on($.d, 'dragover', QR.dragOver); $.on(d, 'dragover', QR.dragOver);
$.on($.d, 'drop', QR.dropFile); $.on(d, 'drop', QR.dropFile);
$.on($.d, 'dragstart', QR.drag); $.on(d, 'dragstart', QR.drag);
return $.on($.d, 'dragend', QR.drag); return $.on(d, 'dragend', QR.drag);
}, },
node: function(post) { node: function(post) {
return $.on($('.quotejs + .quotejs', post.el), 'click', QR.quote); return $.on($('.quotejs + .quotejs', post.el), 'click', QR.quote);
@ -1282,7 +1283,7 @@
QR.message.send({ QR.message.send({
req: 'abort' req: 'abort'
}); });
$.d.activeElement.blur(); d.activeElement.blur();
$.removeClass(QR.el, 'dump'); $.removeClass(QR.el, 'dump');
_ref = QR.replies; _ref = QR.replies;
for (_i = 0, _len = _ref.length; _i < _len; _i++) { for (_i = 0, _len = _ref.length; _i < _len; _i++) {
@ -1298,7 +1299,7 @@
return QR.cleanError(); return QR.cleanError();
}, },
hide: function() { hide: function() {
$.d.activeElement.blur(); d.activeElement.blur();
$.addClass(QR.el, 'autohide'); $.addClass(QR.el, 'autohide');
return $.id('autohide').checked = true; return $.id('autohide').checked = true;
}, },
@ -1316,7 +1317,7 @@
if (node) $.replace(el.firstChild, node); if (node) $.replace(el.firstChild, node);
QR.open(); QR.open();
if (/captcha|verification/i.test(err)) $('[autocomplete]', QR.el).focus(); if (/captcha|verification/i.test(err)) $('[autocomplete]', QR.el).focus();
if ($.d.hidden || $.d.oHidden || $.d.mozHidden || $.d.webkitHidden) { if (d.hidden || d.oHidden || d.mozHidden || d.webkitHidden) {
return alert(err); return alert(err);
} }
}, },
@ -1400,8 +1401,8 @@
drag: function(e) { drag: function(e) {
var i; var i;
i = e.type === 'dragstart' ? 'off' : 'on'; i = e.type === 'dragstart' ? 'off' : 'on';
$[i]($.d, 'dragover', QR.dragOver); $[i](d, 'dragover', QR.dragOver);
return $[i]($.d, 'drop', QR.dropFile); return $[i](d, 'drop', QR.dropFile);
}, },
dragOver: function(e) { dragOver: function(e) {
e.preventDefault(); e.preventDefault();
@ -1807,8 +1808,8 @@
QR.status(); QR.status();
QR.cooldown.init(); QR.cooldown.init();
QR.captcha.init(); QR.captcha.init();
$.add($.d.body, QR.el); $.add(d.body, QR.el);
e = $.d.createEvent('CustomEvent'); e = d.createEvent('CustomEvent');
e.initEvent('QRDialogCreation', true, false); e.initEvent('QRDialogCreation', true, false);
return QR.el.dispatchEvent(e); return QR.el.dispatchEvent(e);
}, },
@ -1865,7 +1866,7 @@
upfile: reply.file, upfile: reply.file,
spoiler: reply.spoiler, spoiler: reply.spoiler,
mode: 'regist', mode: 'regist',
pwd: (m = $.d.cookie.match(/4chan_pass=([^;]+)/)) ? decodeURIComponent(m[1]) : $('[name=pwd]').value, pwd: (m = d.cookie.match(/4chan_pass=([^;]+)/)) ? decodeURIComponent(m[1]) : $('[name=pwd]').value,
recaptcha_challenge_field: challenge, recaptcha_challenge_field: challenge,
recaptcha_response_field: response + ' ' recaptcha_response_field: response + ' '
}; };
@ -2295,8 +2296,8 @@
return e.stopPropagation(); return e.stopPropagation();
}); });
$.add(overlay, dialog); $.add(overlay, dialog);
$.add($.d.body, overlay); $.add(d.body, overlay);
$.d.body.style.setProperty('overflow', 'hidden', null); d.body.style.setProperty('overflow', 'hidden', null);
Options.backlink.call(back); Options.backlink.call(back);
Options.time.call(time); Options.time.call(time);
Options.fileInfo.call(fileInfoR); Options.fileInfo.call(fileInfoR);
@ -2305,7 +2306,7 @@
}, },
close: function() { close: function() {
$.rm(this); $.rm(this);
return $.d.body.style.removeProperty('overflow'); return d.body.style.removeProperty('overflow');
}, },
clearHidden: function() { clearHidden: function() {
$["delete"]("hiddenReplies/" + Main.BOARD + "/"); $["delete"]("hiddenReplies/" + Main.BOARD + "/");
@ -2501,7 +2502,7 @@
$.on(input, 'click', this.update); $.on(input, 'click', this.update);
} }
} }
$.add($.d.body, dialog); $.add(d.body, dialog);
this.retryCoef = 10; this.retryCoef = 10;
return this.lastModified = 0; return this.lastModified = 0;
}, },
@ -2529,7 +2530,7 @@
return Updater.scrollBG = this.checked ? function() { return Updater.scrollBG = this.checked ? function() {
return true; return true;
} : function() { } : function() {
return !($.d.hidden || $.d.oHidden || $.d.mozHidden || $.d.webkitHidden); return !(d.hidden || d.oHidden || d.mozHidden || d.webkitHidden);
}; };
}, },
update: function() { update: function() {
@ -2543,7 +2544,7 @@
if (Conf['Unread Count']) { if (Conf['Unread Count']) {
Unread.title = Unread.title.match(/^.+-/)[0] + ' 404'; Unread.title = Unread.title.match(/^.+-/)[0] + ' 404';
} else { } else {
$.d.title = $.d.title.match(/^.+-/)[0] + ' 404'; d.title = d.title.match(/^.+-/)[0] + ' 404';
} }
Unread.update(true); Unread.update(true);
QR.message.send({ QR.message.send({
@ -2568,7 +2569,7 @@
return; return;
} }
Updater.lastModified = this.getResponseHeader('Last-Modified'); Updater.lastModified = this.getResponseHeader('Last-Modified');
doc = $.d.implementation.createHTMLDocument(null); doc = d.implementation.createHTMLDocument(null);
doc.documentElement.innerHTML = this.responseText; doc.documentElement.innerHTML = this.responseText;
id = $('input', Updater.br.previousElementSibling).name; id = $('input', Updater.br.previousElementSibling).name;
nodes = []; nodes = [];
@ -2579,7 +2580,7 @@
nodes.push(reply.parentNode.parentNode.parentNode); nodes.push(reply.parentNode.parentNode.parentNode);
} }
newPosts = nodes.length; newPosts = nodes.length;
scroll = Conf['Scrolling'] && Updater.scrollBG() && newPosts && Updater.br.previousElementSibling.getBoundingClientRect().bottom - $.d.body.clientHeight < 25; scroll = Conf['Scrolling'] && Updater.scrollBG() && newPosts && Updater.br.previousElementSibling.getBoundingClientRect().bottom - d.body.clientHeight < 25;
if (Conf['Verbose']) { if (Conf['Verbose']) {
Updater.count.textContent = "+" + newPosts; Updater.count.textContent = "+" + newPosts;
Updater.count.className = newPosts ? 'new' : null; Updater.count.className = newPosts ? 'new' : null;
@ -2626,7 +2627,7 @@
var favicon, html, input, inputs, _i, _len; var favicon, html, input, inputs, _i, _len;
html = '<div class=move>Thread Watcher</div>'; html = '<div class=move>Thread Watcher</div>';
this.dialog = UI.dialog('watcher', 'top: 50px; left: 0px;', html); this.dialog = UI.dialog('watcher', 'top: 50px; left: 0px;', html);
$.add($.d.body, this.dialog); $.add(d.body, this.dialog);
inputs = $$('.op > input'); inputs = $$('.op > input');
for (_i = 0, _len = inputs.length; _i < _len; _i++) { for (_i = 0, _len = inputs.length; _i < _len; _i++) {
input = inputs[_i]; input = inputs[_i];
@ -2753,7 +2754,7 @@
createSauceLink: function(link) { createSauceLink: function(link) {
var domain, el, href; var domain, el, href;
domain = link.match(/(\w+)\.\w+\//)[1]; domain = link.match(/(\w+)\.\w+\//)[1];
href = link.replace(/(\$\d)/g, function(parameter) { href = link.replace(/(\d)/g, function(parameter) {
switch (parameter) { switch (parameter) {
case '$1': case '$1':
return "http://thumbs.4chan.org' + img.pathname.replace(/src(\\/\\d+).+$/, 'thumb$1s.jpg') + '"; return "http://thumbs.4chan.org' + img.pathname.replace(/src(\\/\\d+).+$/, 'thumb$1s.jpg') + '";
@ -3028,7 +3029,7 @@
TitlePost = { TitlePost = {
init: function() { init: function() {
return $.d.title = GetTitle(); return d.title = GetTitle();
} }
}; };
@ -3168,7 +3169,7 @@
inline.textContent = "" + req.status + " " + req.statusText; inline.textContent = "" + req.status + " " + req.statusText;
return; return;
} }
doc = $.d.implementation.createHTMLDocument(null); doc = d.implementation.createHTMLDocument(null);
doc.documentElement.innerHTML = req.responseText; doc.documentElement.innerHTML = req.responseText;
node = id === threadID ? Threading.op($('body > form', doc).firstChild) : doc.getElementById(id); node = id === threadID ? Threading.op($('body > form', doc).firstChild) : doc.getElementById(id);
newInline = QuoteInline.table(id, node.innerHTML); newInline = QuoteInline.table(id, node.innerHTML);
@ -3220,7 +3221,7 @@
id: 'qp', id: 'qp',
className: 'reply dialog' className: 'reply dialog'
}); });
$.add($.d.body, qp); $.add(d.body, qp);
id = this.hash.slice(1); id = this.hash.slice(1);
if (el = $.id(id)) { if (el = $.id(id)) {
qp.innerHTML = el.innerHTML; qp.innerHTML = el.innerHTML;
@ -3260,7 +3261,7 @@
qp.textContent = "" + req.status + " " + req.statusText; qp.textContent = "" + req.status + " " + req.statusText;
return; return;
} }
doc = $.d.implementation.createHTMLDocument(null); doc = d.implementation.createHTMLDocument(null);
doc.documentElement.innerHTML = req.responseText; doc.documentElement.innerHTML = req.responseText;
node = id === threadID ? Threading.op($('body > form', doc).firstChild) : doc.getElementById(id); node = id === threadID ? Threading.op($('body > form', doc).firstChild) : doc.getElementById(id);
qp.innerHTML = node.innerHTML; qp.innerHTML = node.innerHTML;
@ -3318,7 +3319,7 @@
node: function(post) { node: function(post) {
var a, board, data, i, id, index, m, node, nodes, quote, quotes, snapshot, text, _i, _len, _ref; var a, board, data, i, id, index, m, node, nodes, quote, quotes, snapshot, text, _i, _len, _ref;
if (post["class"] === 'inline') return; if (post["class"] === 'inline') return;
snapshot = $.d.evaluate('.//text()[not(parent::a)]', post.el.lastChild, null, 6, null); snapshot = d.evaluate('.//text()[not(parent::a)]', post.el.lastChild, null, 6, null);
for (i = 0, _ref = snapshot.snapshotLength; 0 <= _ref ? i < _ref : i > _ref; 0 <= _ref ? i++ : i--) { for (i = 0, _ref = snapshot.snapshotLength; 0 <= _ref ? i < _ref : i > _ref; 0 <= _ref ? i++ : i--) {
node = snapshot.snapshotItem(i); node = snapshot.snapshotItem(i);
data = node.data; data = node.data;
@ -3381,7 +3382,7 @@
var dialog; var dialog;
dialog = UI.dialog('stats', 'bottom: 0; left: 0;', '<div class=move><span id=postcount>0</span> / <span id=imagecount>0</span></div>'); dialog = UI.dialog('stats', 'bottom: 0; left: 0;', '<div class=move><span id=postcount>0</span> / <span id=imagecount>0</span></div>');
dialog.className = 'dialog'; dialog.className = 'dialog';
$.add($.d.body, dialog); $.add(d.body, dialog);
this.posts = this.images = 0; this.posts = this.images = 0;
this.imgLimit = (function() { this.imgLimit = (function() {
switch (Main.BOARD) { switch (Main.BOARD) {
@ -3412,7 +3413,7 @@
Unread = { Unread = {
init: function() { init: function() {
this.title = $.d.title; this.title = d.title;
this.update(); this.update();
$.on(window, 'scroll', Unread.scroll); $.on(window, 'scroll', Unread.scroll);
return Main.callbacks.push(this.node); return Main.callbacks.push(this.node);
@ -3431,7 +3432,7 @@
}, },
scroll: function() { scroll: function() {
var bottom, height, i, reply, _len, _ref; var bottom, height, i, reply, _len, _ref;
height = $.d.body.clientHeight; height = d.body.clientHeight;
_ref = Unread.replies; _ref = Unread.replies;
for (i = 0, _len = _ref.length; i < _len; i++) { for (i = 0, _len = _ref.length; i < _len; i++) {
reply = _ref[i]; reply = _ref[i];
@ -3450,7 +3451,7 @@
return; return;
} }
return this.scheduled = setTimeout((function() { return this.scheduled = setTimeout((function() {
return $.d.title = "(" + count + ") " + Unread.title; return d.title = "(" + count + ") " + Unread.title;
}), 5); }), 5);
}, },
update: function(forceUpdate) { update: function(forceUpdate) {
@ -3460,14 +3461,14 @@
if (Conf['Unread Count']) this.setTitle(count); if (Conf['Unread Count']) this.setTitle(count);
if (!(Conf['Unread Favicon'] && (count < 2 || forceUpdate))) return; if (!(Conf['Unread Favicon'] && (count < 2 || forceUpdate))) return;
Favicon.el.href = Main.dead ? count ? Favicon.unreadDead : Favicon.dead : count ? Favicon.unread : Favicon["default"]; Favicon.el.href = Main.dead ? count ? Favicon.unreadDead : Favicon.dead : count ? Favicon.unread : Favicon["default"];
return $.add($.d.head, Favicon.el); return $.add(d.head, Favicon.el);
} }
}; };
Favicon = { Favicon = {
init: function() { init: function() {
var href; var href;
this.el = $('link[rel="shortcut icon"]', $.d.head); this.el = $('link[rel="shortcut icon"]', d.head);
this.el.type = 'image/x-icon'; this.el.type = 'image/x-icon';
href = this.el.href; href = this.el.href;
this.SFW = /ws.ico$/.test(href); this.SFW = /ws.ico$/.test(href);
@ -3588,7 +3589,7 @@
id: 'ihover', id: 'ihover',
src: this.parentNode.href src: this.parentNode.href
}); });
$.add($.d.body, UI.el); $.add(d.body, UI.el);
$.on(UI.el, 'load', ImageHover.load); $.on(UI.el, 'load', ImageHover.load);
$.on(this, 'mousemove', UI.hover); $.on(this, 'mousemove', UI.hover);
return $.on(this, 'mouseout', ImageHover.mouseout); return $.on(this, 'mouseout', ImageHover.mouseout);
@ -3703,8 +3704,8 @@
thumb = a.firstChild; thumb = a.firstChild;
if (thumb.hidden) { if (thumb.hidden) {
rect = a.getBoundingClientRect(); rect = a.getBoundingClientRect();
if (rect.top < 0) $.d.body.scrollTop += rect.top - 42; if (rect.top < 0) d.body.scrollTop += rect.top - 42;
if (rect.left < 0) $.d.body.scrollLeft += rect.left; if (rect.left < 0) d.body.scrollLeft += rect.left;
return ImageExpand.contract(thumb); return ImageExpand.contract(thumb);
} else { } else {
return ImageExpand.expand(thumb); return ImageExpand.expand(thumb);
@ -3768,7 +3769,7 @@
return $.prepend(form, controls); return $.prepend(form, controls);
}, },
resize: function() { resize: function() {
return ImageExpand.style.textContent = ".fitheight img[md5] + img {max-height:" + $.d.body.clientHeight + "px;}"; return ImageExpand.style.textContent = ".fitheight img[md5] + img {max-height:" + d.body.clientHeight + "px;}";
} }
}; };
@ -3831,7 +3832,7 @@
return; return;
case 'images.4chan.org': case 'images.4chan.org':
$.ready(function() { $.ready(function() {
if ($.d.title === '4chan - 404') return Redirect.init(); if (d.title === '4chan - 404') return Redirect.init();
}); });
return; return;
} }
@ -3843,7 +3844,7 @@
now = Date.now(); now = Date.now();
if (Conf['Check for Updates'] && $.get('lastUpdate', 0) < now - 6 * $.HOUR) { if (Conf['Check for Updates'] && $.get('lastUpdate', 0) < now - 6 * $.HOUR) {
$.ready(function() { $.ready(function() {
return $.add($.d.head, $.el('script', { return $.add(d.head, $.el('script', {
src: 'https://raw.github.com/mayhemydg/4chan-x/master/latest.js' src: 'https://raw.github.com/mayhemydg/4chan-x/master/latest.js'
})); }));
}); });
@ -3887,13 +3888,13 @@
}, },
ready: function() { ready: function() {
var MutationObserver, form, nav, node, nodes, observer, _i, _j, _len, _len2, _ref, _ref2; var MutationObserver, form, nav, node, nodes, observer, _i, _j, _len, _len2, _ref, _ref2;
if ($.d.title === '4chan - 404') { if (d.title === '4chan - 404') {
Redirect.init(); Redirect.init();
return; return;
} }
if (!$.id('navtopr')) return; if (!$.id('navtopr')) return;
$.addClass($.d.body, "chanx_" + (Main.version.split('.')[1])); $.addClass(d.body, "chanx_" + (Main.version.split('.')[1]));
$.addClass($.d.body, $.engine); $.addClass(d.body, $.engine);
_ref = ['navtop', 'navbot']; _ref = ['navtop', 'navbot'];
for (_i = 0, _len = _ref.length; _i < _len; _i++) { for (_i = 0, _len = _ref.length; _i < _len; _i++) {
nav = _ref[_i]; nav = _ref[_i];
@ -3968,11 +3969,11 @@
} }
}, },
addStyle: function() { addStyle: function() {
$.off($.d, 'DOMNodeInserted', Main.addStyle); $.off(d, 'DOMNodeInserted', Main.addStyle);
if ($.d.head) { if (d.head) {
return $.addStyle(Main.css); return $.addStyle(Main.css);
} else { } else {
return $.on($.d, 'DOMNodeInserted', Main.addStyle); return $.on(d, 'DOMNodeInserted', Main.addStyle);
} }
}, },
message: function(e) { message: function(e) {

View File

@ -154,9 +154,11 @@ Config =
'Auto Update': [true, 'Automatically fetch new posts'] 'Auto Update': [true, 'Automatically fetch new posts']
'Interval': 30 'Interval': 30
d = document
UI = UI =
dialog: (id, position, html) -> dialog: (id, position, html) ->
el = $.d.createElement 'div' el = d.createElement 'div'
el.className = 'reply dialog' el.className = 'reply dialog'
el.innerHTML = html el.innerHTML = html
el.id = id el.id = id
@ -167,16 +169,16 @@ UI =
#prevent text selection #prevent text selection
e.preventDefault() e.preventDefault()
UI.el = el = @parentNode UI.el = el = @parentNode
$.d.addEventListener 'mousemove', UI.drag, false d.addEventListener 'mousemove', UI.drag, false
$.d.addEventListener 'mouseup', UI.dragend, false d.addEventListener 'mouseup', UI.dragend, false
#distance from pointer to el edge is constant; calculate it here. #distance from pointer to el edge is constant; calculate it here.
# XXX opera reports el.offsetLeft / el.offsetTop as 0 # XXX opera reports el.offsetLeft / el.offsetTop as 0
rect = el.getBoundingClientRect() rect = el.getBoundingClientRect()
UI.dx = e.clientX - rect.left UI.dx = e.clientX - rect.left
UI.dy = e.clientY - rect.top UI.dy = e.clientY - rect.top
#factor out el from document dimensions #factor out el from document dimensions
UI.width = $.d.body.clientWidth - el.offsetWidth UI.width = d.body.clientWidth - el.offsetWidth
UI.height = $.d.body.clientHeight - el.offsetHeight UI.height = d.body.clientHeight - el.offsetHeight
drag: (e) -> drag: (e) ->
left = e.clientX - UI.dx left = e.clientX - UI.dx
top = e.clientY - UI.dy top = e.clientY - UI.dy
@ -203,13 +205,13 @@ UI =
#a = (b = c.b, c).a; #a = (b = c.b, c).a;
{el} = UI {el} = UI
localStorage["#{Main.namespace}#{el.id}.position"] = el.style.cssText localStorage["#{Main.namespace}#{el.id}.position"] = el.style.cssText
$.d.removeEventListener 'mousemove', UI.drag, false d.removeEventListener 'mousemove', UI.drag, false
$.d.removeEventListener 'mouseup', UI.dragend, false d.removeEventListener 'mouseup', UI.dragend, false
hover: (e) -> hover: (e) ->
{clientX, clientY} = e {clientX, clientY} = e
{el} = UI {el} = UI
{style} = el {style} = el
{clientHeight, clientWidth} = $.d.body {clientHeight, clientWidth} = d.body
height = el.offsetHeight height = el.offsetHeight
top = clientY - 120 top = clientY - 120
@ -237,7 +239,7 @@ loosely follows the jquery api:
http://api.jquery.com/ http://api.jquery.com/
not chainable not chainable
### ###
$ = (selector, root=$.d.body) -> $ = (selector, root=d.body) ->
root.querySelector selector root.querySelector selector
$.extend = (object, properties) -> $.extend = (object, properties) ->
@ -253,22 +255,21 @@ $.extend $,
log: log:
# XXX GreaseMonkey can't into console.log.bind # XXX GreaseMonkey can't into console.log.bind
console.log.bind? console console.log.bind? console
d: document
engine: /WebKit|Presto|Gecko/.exec(navigator.userAgent)[0].toLowerCase() engine: /WebKit|Presto|Gecko/.exec(navigator.userAgent)[0].toLowerCase()
ready: (fc) -> ready: (fc) ->
if /interactive|complete/.test $.d.readyState if /interactive|complete/.test d.readyState
# Execute the functions in parallel. # Execute the functions in parallel.
# If one fails, do not stop the others. # If one fails, do not stop the others.
return setTimeout fc return setTimeout fc
cb = -> cb = ->
$.off $.d, 'DOMContentLoaded', cb $.off d, 'DOMContentLoaded', cb
fc() fc()
$.on $.d, 'DOMContentLoaded', cb $.on d, 'DOMContentLoaded', cb
sync: (key, cb) -> sync: (key, cb) ->
$.on window, 'storage', (e) -> $.on window, 'storage', (e) ->
cb JSON.parse e.newValue if e.key is "#{Main.namespace}#{key}" cb JSON.parse e.newValue if e.key is "#{Main.namespace}#{key}"
id: (id) -> id: (id) ->
$.d.getElementById id d.getElementById id
ajax: (url, callbacks, opts={}) -> ajax: (url, callbacks, opts={}) ->
{type, headers, upCallbacks, form} = opts {type, headers, upCallbacks, form} = opts
r = new XMLHttpRequest() r = new XMLHttpRequest()
@ -301,11 +302,11 @@ $.extend $,
addStyle: (css) -> addStyle: (css) ->
style = $.el 'style', style = $.el 'style',
textContent: css textContent: css
$.add $.d.head, style $.add d.head, style
style style
x: (path, root=$.d.body) -> x: (path, root=d.body) ->
# XPathResult.ANY_UNORDERED_NODE_TYPE is 8 # XPathResult.ANY_UNORDERED_NODE_TYPE is 8
$.d.evaluate(path, root, null, 8, null). d.evaluate(path, root, null, 8, null).
singleNodeValue singleNodeValue
addClass: (el, className) -> addClass: (el, className) ->
el.classList.add className el.classList.add className
@ -314,11 +315,11 @@ $.extend $,
rm: (el) -> rm: (el) ->
el.parentNode.removeChild el el.parentNode.removeChild el
tn: (s) -> tn: (s) ->
$.d.createTextNode s d.createTextNode s
nodes: (nodes) -> nodes: (nodes) ->
if nodes instanceof Node if nodes instanceof Node
return nodes return nodes
frag = $.d.createDocumentFragment() frag = d.createDocumentFragment()
for node in nodes for node in nodes
frag.appendChild node frag.appendChild node
frag frag
@ -333,7 +334,7 @@ $.extend $,
replace: (root, el) -> replace: (root, el) ->
root.parentNode.replaceChild $.nodes(el), root root.parentNode.replaceChild $.nodes(el), root
el: (tag, properties) -> el: (tag, properties) ->
el = $.d.createElement tag el = d.createElement tag
$.extend el, properties if properties $.extend el, properties if properties
el el
on: (el, eventType, handler) -> on: (el, eventType, handler) ->
@ -432,7 +433,7 @@ $.extend $,
name = Main.namespace + name name = Main.namespace + name
localStorage[name] = JSON.stringify value localStorage[name] = JSON.stringify value
$$ = (selector, root=$.d.body) -> $$ = (selector, root=d.body) ->
Array::slice.call root.querySelectorAll selector Array::slice.call root.querySelectorAll selector
Filter = Filter =
@ -567,7 +568,7 @@ Filter =
comment: (post) -> comment: (post) ->
text = [] text = []
# XPathResult.ORDERED_NODE_SNAPSHOT_TYPE is 7 # XPathResult.ORDERED_NODE_SNAPSHOT_TYPE is 7
nodes = $.d.evaluate './/br|.//text()', post.el.lastChild, null, 7, null nodes = d.evaluate './/br|.//text()', post.el.lastChild, null, 7, null
for i in [0...nodes.snapshotLength] for i in [0...nodes.snapshotLength]
text.push if data = nodes.snapshotItem(i).data then data else '\n' text.push if data = nodes.snapshotItem(i).data then data else '\n'
text.join '' text.join ''
@ -620,13 +621,13 @@ ExpandComment =
a.textContent = "#{req.status} #{req.statusText}" a.textContent = "#{req.status} #{req.statusText}"
return return
doc = $.d.implementation.createHTMLDocument null doc = d.implementation.createHTMLDocument null
doc.documentElement.innerHTML = req.responseText doc.documentElement.innerHTML = req.responseText
Threading.op $('body > form', doc).firstChild Threading.op $('body > form', doc).firstChild
# Import the node to fix quote.hashes # Import the node to fix quote.hashes
# as they're empty when in a different document. # as they're empty when in a different document.
node = $.d.importNode doc.getElementById replyID node = d.importNode doc.getElementById replyID
quotes = node.getElementsByClassName 'quotelink' quotes = node.getElementsByClassName 'quotelink'
for quote in quotes for quote in quotes
@ -703,12 +704,12 @@ ExpandThread =
a.textContent = a.textContent.replace '\u00d7 Loading...', '-' a.textContent = a.textContent.replace '\u00d7 Loading...', '-'
doc = $.d.implementation.createHTMLDocument null doc = d.implementation.createHTMLDocument null
doc.documentElement.innerHTML = req.responseText doc.documentElement.innerHTML = req.responseText
nodes = [] nodes = []
for reply in $$ '.reply', doc for reply in $$ '.reply', doc
table = $.d.importNode reply.parentNode.parentNode.parentNode table = d.importNode reply.parentNode.parentNode.parentNode
for quote in $$ '.quotelink', table for quote in $$ '.quotelink', table
if (href = quote.getAttribute 'href') is quote.hash #add pathname to normal quotes if (href = quote.getAttribute 'href') is quote.hash #add pathname to normal quotes
quote.pathname = pathname quote.pathname = pathname
@ -779,7 +780,7 @@ Keybinds =
init: -> init: ->
for node in $$ '[accesskey]' for node in $$ '[accesskey]'
node.removeAttribute 'accesskey' node.removeAttribute 'accesskey'
$.on $.d, 'keydown', Keybinds.keydown $.on d, 'keydown', Keybinds.keydown
keydown: (e) -> keydown: (e) ->
if not (key = Keybinds.keyCode(e)) or /TEXTAREA|INPUT/.test(e.target.nodeName) and not (e.altKey or e.ctrlKey or e.keyCode is 27) if not (key = Keybinds.keyCode(e)) or /TEXTAREA|INPUT/.test(e.target.nodeName) and not (e.altKey or e.ctrlKey or e.keyCode is 27)
@ -912,7 +913,7 @@ Keybinds =
td.className = 'reply' td.className = 'reply'
td.removeAttribute 'tabindex' td.removeAttribute 'tabindex'
rect = td.getBoundingClientRect() rect = td.getBoundingClientRect()
if rect.bottom >= 0 and rect.top <= $.d.body.clientHeight # We're at least partially visible if rect.bottom >= 0 and rect.top <= d.body.clientHeight # We're at least partially visible
next = next =
if delta is +1 if delta is +1
$.x 'following::td[@class="reply"]', td $.x 'following::td[@class="reply"]', td
@ -925,7 +926,7 @@ Keybinds =
return return
return unless Main.REPLY or $.x('ancestor::div[@class="thread"]', next) is thread return unless Main.REPLY or $.x('ancestor::div[@class="thread"]', next) is thread
rect = next.getBoundingClientRect() rect = next.getBoundingClientRect()
if rect.top < 0 or rect.bottom > $.d.body.clientHeight if rect.top < 0 or rect.bottom > d.body.clientHeight
next.scrollIntoView delta is -1 next.scrollIntoView delta is -1
next.className = 'replyhl' next.className = 'replyhl'
next.tabIndex = 0 next.tabIndex = 0
@ -936,7 +937,7 @@ Keybinds =
replies.reverse() if delta is -1 replies.reverse() if delta is -1
for reply in replies for reply in replies
rect = reply.getBoundingClientRect() rect = reply.getBoundingClientRect()
if delta is +1 and rect.top >= 0 or delta is -1 and rect.bottom <= $.d.body.clientHeight if delta is +1 and rect.top >= 0 or delta is -1 and rect.bottom <= d.body.clientHeight
reply.className = 'replyhl' reply.className = 'replyhl'
reply.tabIndex = 0 reply.tabIndex = 0
reply.focus() reply.focus()
@ -958,7 +959,7 @@ Nav =
$.on next, 'click', @next $.on next, 'click', @next
$.add span, [prev, $.tn(' '), next] $.add span, [prev, $.tn(' '), next]
$.add $.d.body, span $.add d.body, span
prev: -> prev: ->
if Main.REPLY if Main.REPLY
@ -968,7 +969,7 @@ Nav =
next: -> next: ->
if Main.REPLY if Main.REPLY
window.scrollTo 0, $.d.body.scrollHeight window.scrollTo 0, d.body.scrollHeight
else else
Nav.scroll +1 Nav.scroll +1
@ -1009,7 +1010,7 @@ QR =
QR.open() QR.open()
$('select', QR.el).value = 'new' unless Main.REPLY $('select', QR.el).value = 'new' unless Main.REPLY
$('textarea', QR.el).focus() $('textarea', QR.el).focus()
form = $.d.forms[0] form = d.forms[0]
$.before form, link $.before form, link
# CORS is ignored for content script on Chrome, but not Safari/Oprah/Firefox. # CORS is ignored for content script on Chrome, but not Safari/Oprah/Firefox.
@ -1026,20 +1027,20 @@ QR =
iframe.src = 'about:blank' iframe.src = 'about:blank'
setTimeout (-> iframe.src = 'https://sys.4chan.org/robots.txt'), 100 setTimeout (-> iframe.src = 'https://sys.4chan.org/robots.txt'), 100
$.on iframe, 'load', -> if @src isnt 'about:blank' then setTimeout loadChecking, 500, @ $.on iframe, 'load', -> if @src isnt 'about:blank' then setTimeout loadChecking, 500, @
$.add $.d.head, iframe $.add d.head, iframe
# Prevent original captcha input from being focused on reload. # Prevent original captcha input from being focused on reload.
script = $.el 'script', textContent: 'Recaptcha.focus_response_field=function(){}' script = $.el 'script', textContent: 'Recaptcha.focus_response_field=function(){}'
$.add $.d.head, script $.add d.head, script
$.rm script $.rm script
if Conf['Persistent QR'] if Conf['Persistent QR']
QR.dialog() QR.dialog()
QR.hide() if Conf['Auto Hide QR'] QR.hide() if Conf['Auto Hide QR']
$.on $.d, 'dragover', QR.dragOver $.on d, 'dragover', QR.dragOver
$.on $.d, 'drop', QR.dropFile $.on d, 'drop', QR.dropFile
$.on $.d, 'dragstart', QR.drag $.on d, 'dragstart', QR.drag
$.on $.d, 'dragend', QR.drag $.on d, 'dragend', QR.drag
node: (post) -> node: (post) ->
$.on $('.quotejs + .quotejs', post.el), 'click', QR.quote $.on $('.quotejs + .quotejs', post.el), 'click', QR.quote
@ -1053,7 +1054,7 @@ QR =
close: -> close: ->
QR.el.hidden = true QR.el.hidden = true
QR.message.send req: 'abort' QR.message.send req: 'abort'
$.d.activeElement.blur() d.activeElement.blur()
$.removeClass QR.el, 'dump' $.removeClass QR.el, 'dump'
for i in QR.replies for i in QR.replies
QR.replies[0].rm() QR.replies[0].rm()
@ -1064,7 +1065,7 @@ QR =
spoiler.click() spoiler.click()
QR.cleanError() QR.cleanError()
hide: -> hide: ->
$.d.activeElement.blur() d.activeElement.blur()
$.addClass QR.el, 'autohide' $.addClass QR.el, 'autohide'
$.id('autohide').checked = true $.id('autohide').checked = true
unhide: -> unhide: ->
@ -1081,7 +1082,7 @@ QR =
if /captcha|verification/i.test err if /captcha|verification/i.test err
# Focus the captcha input on captcha error. # Focus the captcha input on captcha error.
$('[autocomplete]', QR.el).focus() $('[autocomplete]', QR.el).focus()
alert err if $.d.hidden or $.d.oHidden or $.d.mozHidden or $.d.webkitHidden alert err if d.hidden or d.oHidden or d.mozHidden or d.webkitHidden
cleanError: -> cleanError: ->
$('.warning', QR.el).textContent = null $('.warning', QR.el).textContent = null
@ -1164,8 +1165,8 @@ QR =
drag: (e) -> drag: (e) ->
# Let it drag anything from the page. # Let it drag anything from the page.
i = if e.type is 'dragstart' then 'off' else 'on' i = if e.type is 'dragstart' then 'off' else 'on'
$[i] $.d, 'dragover', QR.dragOver $[i] d, 'dragover', QR.dragOver
$[i] $.d, 'drop', QR.dropFile $[i] d, 'drop', QR.dropFile
dragOver: (e) -> dragOver: (e) ->
e.preventDefault() e.preventDefault()
e.dataTransfer.dropEffect = 'copy' # cursor feedback e.dataTransfer.dropEffect = 'copy' # cursor feedback
@ -1490,11 +1491,11 @@ QR =
QR.status() QR.status()
QR.cooldown.init() QR.cooldown.init()
QR.captcha.init() QR.captcha.init()
$.add $.d.body, QR.el $.add d.body, QR.el
# Create a custom event when the QR dialog is first initialized. # Create a custom event when the QR dialog is first initialized.
# Use it to extend the QR's functionalities, or for XTRM RICE. # Use it to extend the QR's functionalities, or for XTRM RICE.
e = $.d.createEvent 'CustomEvent' e = d.createEvent 'CustomEvent'
e.initEvent 'QRDialogCreation', true, false e.initEvent 'QRDialogCreation', true, false
QR.el.dispatchEvent e QR.el.dispatchEvent e
@ -1554,7 +1555,7 @@ QR =
upfile: reply.file upfile: reply.file
spoiler: reply.spoiler spoiler: reply.spoiler
mode: 'regist' mode: 'regist'
pwd: if m = $.d.cookie.match(/4chan_pass=([^;]+)/) then decodeURIComponent m[1] else $('[name=pwd]').value pwd: if m = d.cookie.match(/4chan_pass=([^;]+)/) then decodeURIComponent m[1] else $('[name=pwd]').value
recaptcha_challenge_field: challenge recaptcha_challenge_field: challenge
recaptcha_response_field: response + ' ' recaptcha_response_field: response + ' '
@ -1938,8 +1939,8 @@ Options =
$.on overlay, 'click', Options.close $.on overlay, 'click', Options.close
$.on dialog, 'click', (e) -> e.stopPropagation() $.on dialog, 'click', (e) -> e.stopPropagation()
$.add overlay, dialog $.add overlay, dialog
$.add $.d.body, overlay $.add d.body, overlay
$.d.body.style.setProperty 'overflow', 'hidden', null d.body.style.setProperty 'overflow', 'hidden', null
Options.backlink.call back Options.backlink.call back
Options.time.call time Options.time.call time
@ -1949,7 +1950,7 @@ Options =
close: -> close: ->
$.rm this $.rm this
$.d.body.style.removeProperty 'overflow' d.body.style.removeProperty 'overflow'
clearHidden: -> clearHidden: ->
#'hidden' might be misleading; it's the number of IDs we're *looking* for, #'hidden' might be misleading; it's the number of IDs we're *looking* for,
@ -2125,7 +2126,7 @@ Updater =
else if input.type is 'button' else if input.type is 'button'
$.on input, 'click', @update $.on input, 'click', @update
$.add $.d.body, dialog $.add d.body, dialog
@retryCoef = 10 @retryCoef = 10
@lastModified = 0 @lastModified = 0
@ -2150,7 +2151,7 @@ Updater =
if @checked if @checked
-> true -> true
else else
-> !($.d.hidden or $.d.oHidden or $.d.mozHidden or $.d.webkitHidden) -> !(d.hidden or d.oHidden or d.mozHidden or d.webkitHidden)
update: -> update: ->
if @status is 404 if @status is 404
Updater.timer.textContent = '' Updater.timer.textContent = ''
@ -2161,7 +2162,7 @@ Updater =
if Conf['Unread Count'] if Conf['Unread Count']
Unread.title = Unread.title.match(/^.+-/)[0] + ' 404' Unread.title = Unread.title.match(/^.+-/)[0] + ' 404'
else else
$.d.title = $.d.title.match(/^.+-/)[0] + ' 404' d.title = d.title.match(/^.+-/)[0] + ' 404'
Unread.update true Unread.update true
QR.message.send req: 'abort' QR.message.send req: 'abort'
QR.status() QR.status()
@ -2183,7 +2184,7 @@ Updater =
return return
Updater.lastModified = @getResponseHeader 'Last-Modified' Updater.lastModified = @getResponseHeader 'Last-Modified'
doc = $.d.implementation.createHTMLDocument null doc = d.implementation.createHTMLDocument null
doc.documentElement.innerHTML = @responseText doc.documentElement.innerHTML = @responseText
id = $('input', Updater.br.previousElementSibling).name id = $('input', Updater.br.previousElementSibling).name
@ -2194,7 +2195,7 @@ Updater =
newPosts = nodes.length newPosts = nodes.length
scroll = Conf['Scrolling'] && Updater.scrollBG() && newPosts && scroll = Conf['Scrolling'] && Updater.scrollBG() && newPosts &&
Updater.br.previousElementSibling.getBoundingClientRect().bottom - $.d.body.clientHeight < 25 Updater.br.previousElementSibling.getBoundingClientRect().bottom - d.body.clientHeight < 25
if Conf['Verbose'] if Conf['Verbose']
Updater.count.textContent = "+#{newPosts}" Updater.count.textContent = "+#{newPosts}"
Updater.count.className = if newPosts then 'new' else null Updater.count.className = if newPosts then 'new' else null
@ -2232,7 +2233,7 @@ Watcher =
init: -> init: ->
html = '<div class=move>Thread Watcher</div>' html = '<div class=move>Thread Watcher</div>'
@dialog = UI.dialog 'watcher', 'top: 50px; left: 0px;', html @dialog = UI.dialog 'watcher', 'top: 50px; left: 0px;', html
$.add $.d.body, @dialog $.add d.body, @dialog
#add watch buttons #add watch buttons
inputs = $$ '.op > input' inputs = $$ '.op > input'
@ -2334,7 +2335,7 @@ Sauce =
createSauceLink: (link) -> createSauceLink: (link) ->
domain = link.match(/(\w+)\.\w+\//)[1] domain = link.match(/(\w+)\.\w+\//)[1]
href = link.replace /(\$\d)/g, (parameter) -> href = link.replace /(\d)/g, (parameter) ->
switch parameter switch parameter
when '$1' when '$1'
"http://thumbs.4chan.org' + img.pathname.replace(/src(\\/\\d+).+$/, 'thumb$1s.jpg') + '" "http://thumbs.4chan.org' + img.pathname.replace(/src(\\/\\d+).+$/, 'thumb$1s.jpg') + '"
@ -2531,7 +2532,7 @@ GetTitle = (thread) ->
TitlePost = TitlePost =
init: -> init: ->
$.d.title = GetTitle() d.title = GetTitle()
QuoteBacklink = QuoteBacklink =
init: -> init: ->
@ -2636,7 +2637,7 @@ QuoteInline =
inline.textContent = "#{req.status} #{req.statusText}" inline.textContent = "#{req.status} #{req.statusText}"
return return
doc = $.d.implementation.createHTMLDocument null doc = d.implementation.createHTMLDocument null
doc.documentElement.innerHTML = req.responseText doc.documentElement.innerHTML = req.responseText
node = node =
@ -2675,7 +2676,7 @@ QuotePreview =
qp = UI.el = $.el 'div', qp = UI.el = $.el 'div',
id: 'qp' id: 'qp'
className: 'reply dialog' className: 'reply dialog'
$.add $.d.body, qp $.add d.body, qp
id = @hash[1..] id = @hash[1..]
if el = $.id id if el = $.id id
@ -2708,7 +2709,7 @@ QuotePreview =
qp.textContent = "#{req.status} #{req.statusText}" qp.textContent = "#{req.status} #{req.statusText}"
return return
doc = $.d.implementation.createHTMLDocument null doc = d.implementation.createHTMLDocument null
doc.documentElement.innerHTML = req.responseText doc.documentElement.innerHTML = req.responseText
node = node =
@ -2763,7 +2764,7 @@ Quotify =
# XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE is 6 # XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE is 6
# Get all the text nodes that are not inside an anchor. # Get all the text nodes that are not inside an anchor.
snapshot = $.d.evaluate './/text()[not(parent::a)]', post.el.lastChild, null, 6, null snapshot = d.evaluate './/text()[not(parent::a)]', post.el.lastChild, null, 6, null
for i in [0...snapshot.snapshotLength] for i in [0...snapshot.snapshotLength]
node = snapshot.snapshotItem i node = snapshot.snapshotItem i
@ -2833,7 +2834,7 @@ ThreadStats =
init: -> init: ->
dialog = UI.dialog 'stats', 'bottom: 0; left: 0;', '<div class=move><span id=postcount>0</span> / <span id=imagecount>0</span></div>' dialog = UI.dialog 'stats', 'bottom: 0; left: 0;', '<div class=move><span id=postcount>0</span> / <span id=imagecount>0</span></div>'
dialog.className = 'dialog' dialog.className = 'dialog'
$.add $.d.body, dialog $.add d.body, dialog
@posts = @images = 0 @posts = @images = 0
@imgLimit = @imgLimit =
switch Main.BOARD switch Main.BOARD
@ -2855,7 +2856,7 @@ ThreadStats =
Unread = Unread =
init: -> init: ->
@title = $.d.title @title = d.title
@update() @update()
$.on window, 'scroll', Unread.scroll $.on window, 'scroll', Unread.scroll
Main.callbacks.push @node Main.callbacks.push @node
@ -2872,7 +2873,7 @@ Unread =
Unread.update() Unread.update()
scroll: -> scroll: ->
height = $.d.body.clientHeight height = d.body.clientHeight
for reply, i in Unread.replies for reply, i in Unread.replies
{bottom} = reply.getBoundingClientRect() {bottom} = reply.getBoundingClientRect()
if bottom > height #post is not completely read if bottom > height #post is not completely read
@ -2889,7 +2890,7 @@ Unread =
@setTitle count @setTitle count
return return
@scheduled = setTimeout (-> @scheduled = setTimeout (->
$.d.title = "(#{count}) #{Unread.title}" d.title = "(#{count}) #{Unread.title}"
), 5 ), 5
update: (forceUpdate) -> update: (forceUpdate) ->
@ -2918,11 +2919,11 @@ Unread =
#`favicon.href = href` doesn't work on Firefox #`favicon.href = href` doesn't work on Firefox
#`favicon.href = href` isn't enough on Opera #`favicon.href = href` isn't enough on Opera
#Opera won't always update the favicon if the href didn't not change #Opera won't always update the favicon if the href didn't not change
$.add $.d.head, Favicon.el $.add d.head, Favicon.el
Favicon = Favicon =
init: -> init: ->
@el = $ 'link[rel="shortcut icon"]', $.d.head @el = $ 'link[rel="shortcut icon"]', d.head
@el.type = 'image/x-icon' @el.type = 'image/x-icon'
{href} = @el {href} = @el
@SFW = /ws.ico$/.test href @SFW = /ws.ico$/.test href
@ -2994,7 +2995,7 @@ ImageHover =
UI.el = $.el 'img' UI.el = $.el 'img'
id: 'ihover' id: 'ihover'
src: @parentNode.href src: @parentNode.href
$.add $.d.body, UI.el $.add d.body, UI.el
$.on UI.el, 'load', ImageHover.load $.on UI.el, 'load', ImageHover.load
$.on @, 'mousemove', UI.hover $.on @, 'mousemove', UI.hover
$.on @, 'mouseout', ImageHover.mouseout $.on @, 'mouseout', ImageHover.mouseout
@ -3077,8 +3078,8 @@ ImageExpand =
thumb = a.firstChild thumb = a.firstChild
if thumb.hidden if thumb.hidden
rect = a.getBoundingClientRect() rect = a.getBoundingClientRect()
$.d.body.scrollTop += rect.top - 42 if rect.top < 0 d.body.scrollTop += rect.top - 42 if rect.top < 0
$.d.body.scrollLeft += rect.left if rect.left < 0 d.body.scrollLeft += rect.left if rect.left < 0
ImageExpand.contract thumb ImageExpand.contract thumb
else else
ImageExpand.expand thumb ImageExpand.expand thumb
@ -3136,7 +3137,7 @@ ImageExpand =
$.prepend form, controls $.prepend form, controls
resize: -> resize: ->
ImageExpand.style.textContent = ".fitheight img[md5] + img {max-height:#{$.d.body.clientHeight}px;}" ImageExpand.style.textContent = ".fitheight img[md5] + img {max-height:#{d.body.clientHeight}px;}"
Main = Main =
init: -> init: ->
@ -3182,7 +3183,7 @@ Main =
QR.message.send req: 'status', ready: true, banned: true QR.message.send req: 'status', ready: true, banned: true
return return
when 'images.4chan.org' when 'images.4chan.org'
$.ready -> Redirect.init() if $.d.title is '4chan - 404' $.ready -> Redirect.init() if d.title is '4chan - 404'
return return
$.ready Options.init $.ready Options.init
@ -3194,7 +3195,7 @@ Main =
now = Date.now() now = Date.now()
if Conf['Check for Updates'] and $.get('lastUpdate', 0) < now - 6*$.HOUR if Conf['Check for Updates'] and $.get('lastUpdate', 0) < now - 6*$.HOUR
$.ready -> $.add $.d.head, $.el 'script', src: 'https://raw.github.com/mayhemydg/4chan-x/master/latest.js' $.ready -> $.add d.head, $.el 'script', src: 'https://raw.github.com/mayhemydg/4chan-x/master/latest.js'
$.set 'lastUpdate', now $.set 'lastUpdate', now
Main.hiddenReplies = $.get "hiddenReplies/#{Main.BOARD}/", {} Main.hiddenReplies = $.get "hiddenReplies/#{Main.BOARD}/", {}
@ -3271,13 +3272,13 @@ Main =
$.ready Main.ready $.ready Main.ready
ready: -> ready: ->
if $.d.title is '4chan - 404' if d.title is '4chan - 404'
Redirect.init() Redirect.init()
return return
unless $.id 'navtopr' unless $.id 'navtopr'
return return
$.addClass $.d.body, "chanx_#{Main.version.split('.')[1]}" $.addClass d.body, "chanx_#{Main.version.split('.')[1]}"
$.addClass $.d.body, $.engine $.addClass d.body, $.engine
for nav in ['navtop', 'navbot'] for nav in ['navtop', 'navbot']
$.addClass $("a[href$='/#{Main.BOARD}/']", $.id nav), 'current' $.addClass $("a[href$='/#{Main.BOARD}/']", $.id nav), 'current'
form = $ 'form[name=delform]' form = $ 'form[name=delform]'
@ -3340,11 +3341,11 @@ Main =
$.on form, 'DOMNodeInserted', Main.listener $.on form, 'DOMNodeInserted', Main.listener
addStyle: -> addStyle: ->
$.off $.d, 'DOMNodeInserted', Main.addStyle $.off d, 'DOMNodeInserted', Main.addStyle
if $.d.head if d.head
$.addStyle Main.css $.addStyle Main.css
else # XXX fox else # XXX fox
$.on $.d, 'DOMNodeInserted', Main.addStyle $.on d, 'DOMNodeInserted', Main.addStyle
message: (e) -> message: (e) ->
{data} = e {data} = e