Merge branch 'master' of git://github.com/MayhemYDG/4chan-x
This commit is contained in:
commit
b3d6539351
323
4chan_x.user.js
323
4chan_x.user.js
@ -1,6 +1,6 @@
|
||||
// ==UserScript==
|
||||
// @name 4chan x
|
||||
// @version 2.29.1
|
||||
// @version 2.29.3
|
||||
// @namespace aeosynth
|
||||
// @description Adds various features.
|
||||
// @copyright 2009-2011 James Campos <james.r.campos@gmail.com>
|
||||
@ -9,7 +9,6 @@
|
||||
// @include http*://boards.4chan.org/*
|
||||
// @include http*://images.4chan.org/*
|
||||
// @include http*://sys.4chan.org/*
|
||||
// @include http*://www.4chan.org/*
|
||||
// @run-at document-start
|
||||
// @updateURL https://raw.github.com/MayhemYDG/4chan-x/stable/4chan_x.user.js
|
||||
// @icon http://mayhemydg.github.com/4chan-x/favicon.gif
|
||||
@ -20,7 +19,7 @@
|
||||
* Copyright (c) 2009-2011 James Campos <james.r.campos@gmail.com>
|
||||
* Copyright (c) 2012 Nicolas Stepien <stepien.nicolas@gmail.com>
|
||||
* http://mayhemydg.github.com/4chan-x/
|
||||
* 4chan X 2.29.1
|
||||
* 4chan X 2.29.3
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person
|
||||
* obtaining a copy of this software and associated documentation
|
||||
@ -729,7 +728,7 @@
|
||||
a.textContent = "" + req.status + " " + req.statusText;
|
||||
return;
|
||||
}
|
||||
doc = d.implementation.createHTMLDocument(null);
|
||||
doc = d.implementation.createHTMLDocument('');
|
||||
doc.documentElement.innerHTML = req.response;
|
||||
Threading.op($('body > form', doc).firstChild);
|
||||
node = d.importNode(doc.getElementById(replyID));
|
||||
@ -834,7 +833,7 @@
|
||||
return;
|
||||
}
|
||||
a.textContent = a.textContent.replace('\u00d7 Loading...', '-');
|
||||
doc = d.implementation.createHTMLDocument(null);
|
||||
doc = d.implementation.createHTMLDocument('');
|
||||
doc.documentElement.innerHTML = req.response;
|
||||
nodes = [];
|
||||
_ref = $$('.reply', doc);
|
||||
@ -976,7 +975,7 @@
|
||||
break;
|
||||
case Conf.unreadCountTo0:
|
||||
Unread.replies = [];
|
||||
Unread.update();
|
||||
Unread.update(true);
|
||||
break;
|
||||
case Conf.expandImage:
|
||||
Keybinds.img(thread);
|
||||
@ -1229,46 +1228,17 @@
|
||||
return setTimeout(this.asyncInit);
|
||||
},
|
||||
asyncInit: function() {
|
||||
var form, iframe, link, loadChecking, script, src;
|
||||
var link, script;
|
||||
if (Conf['Hide Original Post Form']) {
|
||||
link = $.el('h1', {
|
||||
innerHTML: "<a href=javascript:;>" + (g.REPLY ? 'Quick Reply' : 'New Thread') + "</a>"
|
||||
});
|
||||
$.on($('a', link), 'click', function() {
|
||||
$.on(link.firstChild, 'click', function() {
|
||||
QR.open();
|
||||
if (!g.REPLY) $('select', QR.el).value = 'new';
|
||||
return $('textarea', QR.el).focus();
|
||||
});
|
||||
form = d.forms[0];
|
||||
$.before(form, link);
|
||||
}
|
||||
if (/chrome/i.test(navigator.userAgent)) {
|
||||
QR.status({
|
||||
ready: true
|
||||
});
|
||||
} else {
|
||||
src = "http" + (/^https/.test(form.action) ? 's' : '') + "://sys.4chan.org/robots.txt";
|
||||
iframe = $.el('iframe', {
|
||||
id: 'iframe',
|
||||
src: src
|
||||
});
|
||||
$.on(iframe, 'error', function() {
|
||||
return this.src = this.src;
|
||||
});
|
||||
loadChecking = function(iframe) {
|
||||
if (!QR.status.ready) {
|
||||
iframe.src = 'about:blank';
|
||||
return setTimeout((function() {
|
||||
return iframe.src = src;
|
||||
}), 100);
|
||||
}
|
||||
};
|
||||
$.on(iframe, 'load', function() {
|
||||
if (this.src !== 'about:blank') {
|
||||
return setTimeout(loadChecking, 500, this);
|
||||
}
|
||||
});
|
||||
$.add(d.head, iframe);
|
||||
$.before($('form[name=post]'), link);
|
||||
}
|
||||
script = $.el('script', {
|
||||
textContent: 'Recaptcha.focus_response_field=function(){}'
|
||||
@ -1297,9 +1267,7 @@
|
||||
close: function() {
|
||||
var i, spoiler, _i, _len, _ref;
|
||||
QR.el.hidden = true;
|
||||
QR.message.send({
|
||||
req: 'abort'
|
||||
});
|
||||
QR.abort();
|
||||
d.activeElement.blur();
|
||||
$.removeClass(QR.el, 'dump');
|
||||
_ref = QR.replies;
|
||||
@ -1344,23 +1312,12 @@
|
||||
status: function(data) {
|
||||
var disabled, input, value;
|
||||
if (data == null) data = {};
|
||||
if (data.ready) {
|
||||
QR.status.ready = true;
|
||||
QR.status.banned = data.banned;
|
||||
} else if (!QR.status.ready) {
|
||||
value = 'Loading';
|
||||
disabled = true;
|
||||
}
|
||||
if (g.dead) {
|
||||
value = 404;
|
||||
disabled = true;
|
||||
QR.cooldown.auto = false;
|
||||
} else if (QR.status.banned) {
|
||||
value = 'Banned';
|
||||
disabled = true;
|
||||
} else {
|
||||
value = QR.cooldown.seconds || data.progress || value;
|
||||
}
|
||||
value = QR.cooldown.seconds || data.progress || value;
|
||||
if (!QR.el) return;
|
||||
input = QR.status.input;
|
||||
input.value = QR.cooldown.auto && Conf['Cooldown'] ? value ? "Auto " + value : 'Auto' : value || 'Submit';
|
||||
@ -1826,16 +1783,14 @@
|
||||
return QR.el.dispatchEvent(e);
|
||||
},
|
||||
submit: function(e) {
|
||||
var captcha, captchas, challenge, err, file, m, post, reader, reply, response, threadID;
|
||||
var callbacks, captcha, captchas, challenge, err, form, m, name, opts, post, reply, response, threadID, val;
|
||||
if (e != null) e.preventDefault();
|
||||
if (QR.cooldown.seconds) {
|
||||
QR.cooldown.auto = !QR.cooldown.auto;
|
||||
QR.status();
|
||||
return;
|
||||
}
|
||||
QR.message.send({
|
||||
req: 'abort'
|
||||
});
|
||||
QR.abort();
|
||||
reply = QR.replies[0];
|
||||
if (!(reply.com || reply.file)) {
|
||||
err = 'No file selected.';
|
||||
@ -1868,8 +1823,13 @@
|
||||
if (Conf['Thread Watcher'] && Conf['Auto Watch Reply'] && threadID !== 'new') {
|
||||
Watcher.watch(threadID);
|
||||
}
|
||||
if (!QR.cooldown.auto && $.x('ancestor::div[@id="qr"]', d.activeElement)) {
|
||||
d.activeElement.blur();
|
||||
}
|
||||
QR.status({
|
||||
progress: '...'
|
||||
});
|
||||
post = {
|
||||
postURL: $('form[name=post]').action,
|
||||
resto: threadID,
|
||||
name: reply.name,
|
||||
email: reply.email,
|
||||
@ -1882,37 +1842,51 @@
|
||||
recaptcha_challenge_field: challenge,
|
||||
recaptcha_response_field: response + ' '
|
||||
};
|
||||
QR.status({
|
||||
progress: '...'
|
||||
});
|
||||
if ($.engine === 'gecko' && reply.file) {
|
||||
file = {};
|
||||
reader = new FileReader();
|
||||
reader.onload = function() {
|
||||
file.buffer = this.result;
|
||||
file.name = reply.file.name;
|
||||
file.type = reply.file.type;
|
||||
post.upfile = file;
|
||||
return QR.message.send(post);
|
||||
};
|
||||
reader.readAsBinaryString(reply.file);
|
||||
return;
|
||||
form = new FormData();
|
||||
for (name in post) {
|
||||
val = post[name];
|
||||
if (val) form.append(name, val);
|
||||
}
|
||||
if (/chrome/i.test(navigator.userAgent)) {
|
||||
QR.message.post(post);
|
||||
return;
|
||||
}
|
||||
return QR.message.send(post);
|
||||
callbacks = {
|
||||
onload: function() {
|
||||
return QR.response(this.response);
|
||||
},
|
||||
onerror: function() {
|
||||
return QR.error('_', $.el('a', {
|
||||
href: '//www.4chan.org/banned',
|
||||
target: '_blank',
|
||||
textContent: 'Connection error, or you are banned.'
|
||||
}));
|
||||
}
|
||||
};
|
||||
opts = {
|
||||
form: form,
|
||||
type: 'POST',
|
||||
upCallbacks: {
|
||||
onload: function() {
|
||||
return QR.status({
|
||||
progress: '...'
|
||||
});
|
||||
},
|
||||
onprogress: function(e) {
|
||||
return QR.status({
|
||||
progress: "" + (Math.round(e.loaded / e.total * 100)) + "%"
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
return QR.ajax = $.ajax($('form[name=post]').action, callbacks, opts);
|
||||
},
|
||||
response: function(html) {
|
||||
var b, doc, err, node, persona, postNumber, reply, thread, _, _ref;
|
||||
doc = $.el('a', {
|
||||
innerHTML: html
|
||||
});
|
||||
if ($('title', doc).textContent === '4chan - Banned') {
|
||||
QR.message.receive({
|
||||
req: 'banned'
|
||||
});
|
||||
doc = d.implementation.createHTMLDocument('');
|
||||
doc.documentElement.innerHTML = html;
|
||||
if (doc.title === '4chan - Banned') {
|
||||
QR.error('_', $.el('a', {
|
||||
href: '//www.4chan.org/banned',
|
||||
target: '_blank',
|
||||
textContent: 'You are banned.'
|
||||
}));
|
||||
return;
|
||||
}
|
||||
if (!(b = $('td b', doc))) {
|
||||
@ -1970,140 +1944,10 @@
|
||||
QR.status();
|
||||
return QR.resetFileInput();
|
||||
},
|
||||
message: {
|
||||
send: function(data) {
|
||||
var host, window;
|
||||
if (/chrome/i.test(navigator.userAgent)) {
|
||||
QR.message.receive(data);
|
||||
return;
|
||||
}
|
||||
data.QR = true;
|
||||
host = location.hostname;
|
||||
window = host === 'boards.4chan.org' ? $.id('iframe').contentWindow : parent;
|
||||
return window.postMessage(data, '*');
|
||||
},
|
||||
receive: function(data) {
|
||||
var req, _ref;
|
||||
req = data.req;
|
||||
delete data.req;
|
||||
delete data.QR;
|
||||
switch (req) {
|
||||
case 'abort':
|
||||
if ((_ref = QR.ajax) != null) _ref.abort();
|
||||
return QR.message.send({
|
||||
req: 'status'
|
||||
});
|
||||
case 'response':
|
||||
return QR.response(data.html);
|
||||
case 'status':
|
||||
return QR.status(data);
|
||||
case 'banned':
|
||||
QR.error('You are banned.', $.el('a', {
|
||||
href: 'http://www.4chan.org/banned',
|
||||
target: '_blank',
|
||||
textContent: 'You are banned.'
|
||||
}));
|
||||
return QR.status({
|
||||
ready: true,
|
||||
banned: true
|
||||
});
|
||||
default:
|
||||
return QR.message.post(data);
|
||||
}
|
||||
},
|
||||
post: function(data) {
|
||||
var boundary, callbacks, form, i, name, opts, parts, toBin, url, val;
|
||||
url = data.postURL;
|
||||
delete data.postURL;
|
||||
if ($.engine === 'gecko' && data.upfile) {
|
||||
if (!data.binary) {
|
||||
toBin = function(data, name, val) {
|
||||
var bb, r;
|
||||
bb = new MozBlobBuilder();
|
||||
bb.append(val);
|
||||
r = new FileReader();
|
||||
r.onload = function() {
|
||||
data[name] = r.result;
|
||||
if (!--i) return QR.message.post(data);
|
||||
};
|
||||
return r.readAsBinaryString(bb.getBlob('text/plain'));
|
||||
};
|
||||
i = Object.keys(data).length;
|
||||
for (name in data) {
|
||||
val = data[name];
|
||||
if (typeof val === 'object') {
|
||||
toBin(data.upfile, 'name', data.upfile.name);
|
||||
} else if (typeof val === 'boolean') {
|
||||
if (val) {
|
||||
toBin(data, name, String(val));
|
||||
} else {
|
||||
i--;
|
||||
}
|
||||
} else {
|
||||
toBin(data, name, val);
|
||||
}
|
||||
}
|
||||
data.postURL = url;
|
||||
data.binary = true;
|
||||
return;
|
||||
}
|
||||
delete data.binary;
|
||||
boundary = '-------------SMCD' + Date.now();
|
||||
parts = [];
|
||||
parts.push('Content-Disposition: form-data; name="upfile"; filename="' + data.upfile.name + '"\r\n' + 'Content-Type: ' + data.upfile.type + '\r\n\r\n' + data.upfile.buffer + '\r\n');
|
||||
delete data.upfile;
|
||||
for (name in data) {
|
||||
val = data[name];
|
||||
if (val) {
|
||||
parts.push('Content-Disposition: form-data; name="' + name + '"\r\n\r\n' + val + '\r\n');
|
||||
}
|
||||
}
|
||||
form = '--' + boundary + '\r\n' + parts.join('--' + boundary + '\r\n') + '--' + boundary + '--\r\n';
|
||||
} else {
|
||||
form = new FormData();
|
||||
for (name in data) {
|
||||
val = data[name];
|
||||
if (val) form.append(name, val);
|
||||
}
|
||||
}
|
||||
callbacks = {
|
||||
onload: function() {
|
||||
return QR.message.send({
|
||||
req: 'response',
|
||||
html: this.response
|
||||
});
|
||||
},
|
||||
onerror: function() {
|
||||
return QR.message.send({
|
||||
req: 'banned'
|
||||
});
|
||||
}
|
||||
};
|
||||
opts = {
|
||||
form: form,
|
||||
type: 'post',
|
||||
upCallbacks: {
|
||||
onload: function() {
|
||||
return QR.message.send({
|
||||
req: 'status',
|
||||
progress: '...'
|
||||
});
|
||||
},
|
||||
onprogress: function(e) {
|
||||
return QR.message.send({
|
||||
req: 'status',
|
||||
progress: "" + (Math.round(e.loaded / e.total * 100)) + "%"
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
if (boundary) {
|
||||
opts.headers = {
|
||||
'Content-Type': 'multipart/form-data;boundary=' + boundary
|
||||
};
|
||||
}
|
||||
return QR.ajax = $.ajax(url, callbacks, opts);
|
||||
}
|
||||
abort: function() {
|
||||
var _ref;
|
||||
if ((_ref = QR.ajax) != null) _ref.abort();
|
||||
return QR.status();
|
||||
}
|
||||
};
|
||||
|
||||
@ -2121,6 +1965,7 @@
|
||||
$.replace(home.firstElementChild, a);
|
||||
}
|
||||
if (!$.get('firstrun')) {
|
||||
if (!Favicon.el) Favicon.init();
|
||||
$.set('firstrun', true);
|
||||
return Options.dialog();
|
||||
}
|
||||
@ -2563,10 +2408,7 @@
|
||||
d.title = d.title.match(/^.+-/)[0] + ' 404';
|
||||
}
|
||||
Unread.update(true);
|
||||
QR.message.send({
|
||||
req: 'abort'
|
||||
});
|
||||
QR.status();
|
||||
QR.abort();
|
||||
return;
|
||||
}
|
||||
Updater.retryCoef = 10;
|
||||
@ -2585,7 +2427,7 @@
|
||||
return;
|
||||
}
|
||||
Updater.lastModified = this.getResponseHeader('Last-Modified');
|
||||
doc = d.implementation.createHTMLDocument(null);
|
||||
doc = d.implementation.createHTMLDocument('');
|
||||
doc.documentElement.innerHTML = this.response;
|
||||
id = $('input', Updater.br.previousElementSibling).name;
|
||||
nodes = [];
|
||||
@ -3139,7 +2981,7 @@
|
||||
inline = QuoteInline.table(id, el.innerHTML);
|
||||
if ((i = Unread.replies.indexOf(el.parentNode.parentNode.parentNode)) !== -1) {
|
||||
Unread.replies.splice(i, 1);
|
||||
Unread.update();
|
||||
Unread.update(true);
|
||||
}
|
||||
if (/\bbacklink\b/.test(q.className)) {
|
||||
$.after(q.parentNode, inline);
|
||||
@ -3188,7 +3030,7 @@
|
||||
inline.textContent = "" + req.status + " " + req.statusText;
|
||||
return;
|
||||
}
|
||||
doc = d.implementation.createHTMLDocument(null);
|
||||
doc = d.implementation.createHTMLDocument('');
|
||||
doc.documentElement.innerHTML = req.response;
|
||||
node = id === threadID ? Threading.op($('body > form', doc).firstChild) : doc.getElementById(id);
|
||||
newInline = QuoteInline.table(id, node.innerHTML);
|
||||
@ -3277,7 +3119,7 @@
|
||||
qp.textContent = "" + req.status + " " + req.statusText;
|
||||
return;
|
||||
}
|
||||
doc = d.implementation.createHTMLDocument(null);
|
||||
doc = d.implementation.createHTMLDocument('');
|
||||
doc.documentElement.innerHTML = req.response;
|
||||
node = id === threadID ? Threading.op($('body > form', doc).firstChild) : doc.getElementById(id);
|
||||
qp.innerHTML = node.innerHTML;
|
||||
@ -3485,6 +3327,7 @@
|
||||
Favicon = {
|
||||
init: function() {
|
||||
var href;
|
||||
if (this.el) return;
|
||||
this.el = $('link[rel="shortcut icon"]', d.head);
|
||||
this.el.type = 'image/x-icon';
|
||||
href = this.el.href;
|
||||
@ -3629,6 +3472,7 @@
|
||||
|
||||
AutoGif = {
|
||||
init: function() {
|
||||
if (g.BOARD === 'gif') return;
|
||||
return Main.callbacks.push(this.node);
|
||||
},
|
||||
node: function(post) {
|
||||
@ -3808,12 +3652,7 @@
|
||||
$.on(window, 'message', Main.message);
|
||||
switch (location.hostname) {
|
||||
case 'sys.4chan.org':
|
||||
if (path === '/robots.txt') {
|
||||
QR.message.send({
|
||||
req: 'status',
|
||||
ready: true
|
||||
});
|
||||
} else if (/report/.test(location.search)) {
|
||||
if (/report/.test(location.search)) {
|
||||
$.ready(function() {
|
||||
return $.on($.id('recaptcha_response_field'), 'keydown', function(e) {
|
||||
if (e.keyCode === 8 && !e.target.value) {
|
||||
@ -3823,13 +3662,6 @@
|
||||
});
|
||||
}
|
||||
return;
|
||||
case 'www.4chan.org':
|
||||
if (path === '/banned') {
|
||||
QR.message.send({
|
||||
req: 'banned'
|
||||
});
|
||||
}
|
||||
return;
|
||||
case 'images.4chan.org':
|
||||
$.ready(function() {
|
||||
if (d.title === '4chan - 404') return Redirect.init();
|
||||
@ -3990,13 +3822,8 @@
|
||||
}
|
||||
},
|
||||
message: function(e) {
|
||||
var data, version;
|
||||
data = e.data;
|
||||
if (data.QR) {
|
||||
QR.message.receive(data);
|
||||
return;
|
||||
}
|
||||
version = data.version;
|
||||
var version;
|
||||
version = e.data.version;
|
||||
if (version && version !== Main.version && confirm('An updated version of 4chan X is available, would you like to install it now?')) {
|
||||
return window.location = "https://raw.github.com/mayhemydg/4chan-x/" + version + "/4chan_x.user.js";
|
||||
}
|
||||
@ -4054,7 +3881,7 @@
|
||||
if (target.nodeName === 'TABLE') return Main.node([Main.preParse(target)]);
|
||||
},
|
||||
namespace: '4chan_x.',
|
||||
version: '2.29.1',
|
||||
version: '2.29.3',
|
||||
callbacks: [],
|
||||
css: '\
|
||||
/* dialog styling */\
|
||||
|
||||
3
Cakefile
3
Cakefile
@ -2,7 +2,7 @@
|
||||
{exec} = require 'child_process'
|
||||
fs = require 'fs'
|
||||
|
||||
VERSION = '2.29.1'
|
||||
VERSION = '2.29.3'
|
||||
|
||||
HEADER = """
|
||||
// ==UserScript==
|
||||
@ -16,7 +16,6 @@ HEADER = """
|
||||
// @include http*://boards.4chan.org/*
|
||||
// @include http*://images.4chan.org/*
|
||||
// @include http*://sys.4chan.org/*
|
||||
// @include http*://www.4chan.org/*
|
||||
// @run-at document-start
|
||||
// @updateURL https://raw.github.com/MayhemYDG/4chan-x/stable/4chan_x.user.js
|
||||
// @icon http://mayhemydg.github.com/4chan-x/favicon.gif
|
||||
|
||||
12
changelog
12
changelog
@ -1,6 +1,16 @@
|
||||
master
|
||||
- Mayhem
|
||||
Now works when using https.
|
||||
Auto-GIF will not run in /gif/.
|
||||
|
||||
2.29.3
|
||||
- Mayhem
|
||||
Update Quick Reply posting method, this fixes compatibility for uncommon browsers such as
|
||||
Opera Mobile 12 and Luakit for example.
|
||||
|
||||
2.29.2
|
||||
- Mayhem
|
||||
Add HTTPS support.
|
||||
Ban support improvements and fixes.
|
||||
|
||||
2.29.1
|
||||
- Mayhem
|
||||
|
||||
@ -1 +1 @@
|
||||
postMessage({version:'2.29.1'},'*')
|
||||
postMessage({version:'2.29.3'},'*')
|
||||
257
script.coffee
257
script.coffee
@ -627,7 +627,7 @@ ExpandComment =
|
||||
a.textContent = "#{req.status} #{req.statusText}"
|
||||
return
|
||||
|
||||
doc = d.implementation.createHTMLDocument null
|
||||
doc = d.implementation.createHTMLDocument ''
|
||||
doc.documentElement.innerHTML = req.response
|
||||
|
||||
Threading.op $('body > form', doc).firstChild
|
||||
@ -712,7 +712,7 @@ ExpandThread =
|
||||
|
||||
a.textContent = a.textContent.replace '\u00d7 Loading...', '-'
|
||||
|
||||
doc = d.implementation.createHTMLDocument null
|
||||
doc = d.implementation.createHTMLDocument ''
|
||||
doc.documentElement.innerHTML = req.response
|
||||
|
||||
nodes = []
|
||||
@ -833,7 +833,7 @@ Keybinds =
|
||||
Updater.update()
|
||||
when Conf.unreadCountTo0
|
||||
Unread.replies = []
|
||||
Unread.update()
|
||||
Unread.update true
|
||||
# Images
|
||||
when Conf.expandImage
|
||||
Keybinds.img thread
|
||||
@ -1014,32 +1014,15 @@ QR =
|
||||
asyncInit: ->
|
||||
if Conf['Hide Original Post Form']
|
||||
link = $.el 'h1', innerHTML: "<a href=javascript:;>#{if g.REPLY then 'Quick Reply' else 'New Thread'}</a>"
|
||||
$.on $('a', link), 'click', ->
|
||||
$.on link.firstChild, 'click', ->
|
||||
QR.open()
|
||||
$('select', QR.el).value = 'new' unless g.REPLY
|
||||
$('textarea', QR.el).focus()
|
||||
form = d.forms[0]
|
||||
$.before form, link
|
||||
|
||||
# CORS is ignored for content script on Chrome, but not Safari/Oprah/Firefox.
|
||||
if /chrome/i.test navigator.userAgent
|
||||
QR.status ready: true
|
||||
else
|
||||
src = "http#{if /^https/.test form.action then 's' else ''}://sys.4chan.org/robots.txt"
|
||||
iframe = $.el 'iframe',
|
||||
id: 'iframe'
|
||||
src: src
|
||||
$.on iframe, 'error', -> @src = @src
|
||||
# Greasemonkey ghetto fix
|
||||
loadChecking = (iframe) ->
|
||||
unless QR.status.ready
|
||||
iframe.src = 'about:blank'
|
||||
setTimeout (-> iframe.src = src), 100
|
||||
$.on iframe, 'load', -> if @src isnt 'about:blank' then setTimeout loadChecking, 500, @
|
||||
$.add d.head, iframe
|
||||
$.before $('form[name=post]'), link
|
||||
|
||||
# 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
|
||||
$.rm script
|
||||
|
||||
@ -1061,7 +1044,7 @@ QR =
|
||||
QR.dialog()
|
||||
close: ->
|
||||
QR.el.hidden = true
|
||||
QR.message.send req: 'abort'
|
||||
QR.abort()
|
||||
d.activeElement.blur()
|
||||
$.removeClass QR.el, 'dump'
|
||||
for i in QR.replies
|
||||
@ -1095,22 +1078,11 @@ QR =
|
||||
$('.warning', QR.el).textContent = null
|
||||
|
||||
status: (data={}) ->
|
||||
if data.ready
|
||||
QR.status.ready = true
|
||||
QR.status.banned = data.banned
|
||||
else unless QR.status.ready
|
||||
value = 'Loading'
|
||||
disabled = true
|
||||
if g.dead
|
||||
value = 404
|
||||
disabled = true
|
||||
QR.cooldown.auto = false
|
||||
else if QR.status.banned
|
||||
value = 'Banned'
|
||||
disabled = true
|
||||
else
|
||||
# do not cancel `value = 'Loading'` once the cooldown is over
|
||||
value = QR.cooldown.seconds or data.progress or value
|
||||
value = QR.cooldown.seconds or data.progress or value
|
||||
return unless QR.el
|
||||
{input} = QR.status
|
||||
input.value =
|
||||
@ -1511,7 +1483,7 @@ QR =
|
||||
QR.cooldown.auto = !QR.cooldown.auto
|
||||
QR.status()
|
||||
return
|
||||
QR.message.send req: 'abort'
|
||||
QR.abort()
|
||||
reply = QR.replies[0]
|
||||
|
||||
# prevent errors
|
||||
@ -1550,9 +1522,15 @@ QR =
|
||||
QR.hide()
|
||||
if Conf['Thread Watcher'] and Conf['Auto Watch Reply'] and threadID isnt 'new'
|
||||
Watcher.watch threadID
|
||||
if not QR.cooldown.auto and $.x 'ancestor::div[@id="qr"]', d.activeElement
|
||||
# Unfocus the focused element if it is one within the QR and we're not auto-posting.
|
||||
d.activeElement.blur()
|
||||
|
||||
# Starting to upload might take some time.
|
||||
# Provide some feedback that we're starting to submit.
|
||||
QR.status progress: '...'
|
||||
|
||||
post =
|
||||
postURL: $('form[name=post]').action
|
||||
resto: threadID
|
||||
name: reply.name
|
||||
email: reply.email
|
||||
@ -1565,36 +1543,42 @@ QR =
|
||||
recaptcha_challenge_field: challenge
|
||||
recaptcha_response_field: response + ' '
|
||||
|
||||
# Starting to upload might take some time.
|
||||
# Provide some feedback that we're starting to submit.
|
||||
QR.status progress: '...'
|
||||
form = new FormData()
|
||||
for name, val of post
|
||||
form.append name, val if val
|
||||
|
||||
if $.engine is 'gecko' and reply.file
|
||||
# https://bugzilla.mozilla.org/show_bug.cgi?id=673742
|
||||
# We plan to allow postMessaging Files and FileLists across origins,
|
||||
# that just needs a more in depth security review.
|
||||
file = {}
|
||||
reader = new FileReader()
|
||||
reader.onload = ->
|
||||
file.buffer = @result
|
||||
file.name = reply.file.name
|
||||
file.type = reply.file.type
|
||||
post.upfile = file
|
||||
QR.message.send post
|
||||
reader.readAsBinaryString reply.file
|
||||
return
|
||||
callbacks =
|
||||
onload: ->
|
||||
QR.response @response
|
||||
onerror: ->
|
||||
# Connection error, or
|
||||
# CORS disabled error on www.4chan.org/banned
|
||||
QR.error '_', $.el 'a',
|
||||
href: '//www.4chan.org/banned'
|
||||
target: '_blank'
|
||||
textContent: 'Connection error, or you are banned.'
|
||||
opts =
|
||||
form: form
|
||||
type: 'POST'
|
||||
upCallbacks:
|
||||
onload: ->
|
||||
# Upload done, waiting for response.
|
||||
QR.status progress: '...'
|
||||
onprogress: (e) ->
|
||||
# Uploading...
|
||||
QR.status progress: "#{Math.round e.loaded / e.total * 100}%"
|
||||
|
||||
# CORS is ignored for content script on Chrome, but not Safari/Oprah/Firefox.
|
||||
if /chrome/i.test navigator.userAgent
|
||||
QR.message.post post
|
||||
return
|
||||
QR.message.send post
|
||||
QR.ajax = $.ajax $('form[name=post]').action, callbacks, opts
|
||||
|
||||
response: (html) ->
|
||||
doc = $.el 'a', innerHTML: html
|
||||
doc = d.implementation.createHTMLDocument ''
|
||||
doc.documentElement.innerHTML = html
|
||||
# Check for ban.
|
||||
if $('title', doc).textContent is '4chan - Banned'
|
||||
QR.message.receive req: 'banned'
|
||||
if doc.title is '4chan - Banned'
|
||||
QR.error '_', $.el 'a',
|
||||
href: '//www.4chan.org/banned'
|
||||
target: '_blank'
|
||||
textContent: 'You are banned.'
|
||||
return
|
||||
unless b = $ 'td b', doc
|
||||
err = 'Connection error with sys.4chan.org.'
|
||||
@ -1652,117 +1636,9 @@ QR =
|
||||
QR.status()
|
||||
QR.resetFileInput()
|
||||
|
||||
message:
|
||||
send: (data) ->
|
||||
# CORS is ignored for content script on Chrome, but not Safari/Oprah/Firefox.
|
||||
if /chrome/i.test navigator.userAgent
|
||||
QR.message.receive data
|
||||
return
|
||||
data.QR = true
|
||||
host = location.hostname
|
||||
window =
|
||||
if host is 'boards.4chan.org'
|
||||
$.id('iframe').contentWindow
|
||||
else
|
||||
parent
|
||||
window.postMessage data, '*'
|
||||
receive: (data) ->
|
||||
req = data.req
|
||||
delete data.req
|
||||
delete data.QR
|
||||
switch req
|
||||
when 'abort'
|
||||
QR.ajax?.abort()
|
||||
QR.message.send req: 'status'
|
||||
when 'response' # xhr response
|
||||
QR.response data.html
|
||||
when 'status'
|
||||
QR.status data
|
||||
when 'banned'
|
||||
QR.error 'You are banned.', $.el 'a',
|
||||
href: 'http://www.4chan.org/banned'
|
||||
target: '_blank'
|
||||
textContent: 'You are banned.'
|
||||
# Disable iframe reloading
|
||||
QR.status ready: true, banned: true
|
||||
else
|
||||
QR.message.post data # Reply object: we're posting
|
||||
|
||||
post: (data) ->
|
||||
|
||||
url = data.postURL
|
||||
# Do not append these values to the form.
|
||||
delete data.postURL
|
||||
|
||||
# File with filename upload fix from desuwa
|
||||
if $.engine is 'gecko' and data.upfile
|
||||
# All of this is fucking retarded.
|
||||
unless data.binary
|
||||
toBin = (data, name, val) ->
|
||||
bb = new MozBlobBuilder()
|
||||
bb.append val
|
||||
r = new FileReader()
|
||||
r.onload = ->
|
||||
data[name] = r.result
|
||||
unless --i
|
||||
QR.message.post data
|
||||
r.readAsBinaryString bb.getBlob 'text/plain'
|
||||
i = Object.keys(data).length
|
||||
for name, val of data
|
||||
if typeof val is 'object' # File. toBin the filename.
|
||||
toBin data.upfile, 'name', data.upfile.name
|
||||
else if typeof val is 'boolean'
|
||||
if val
|
||||
toBin data, name, String val
|
||||
else
|
||||
i--
|
||||
else
|
||||
toBin data, name, val
|
||||
data.postURL = url
|
||||
data.binary = true
|
||||
return
|
||||
|
||||
delete data.binary
|
||||
|
||||
boundary = '-------------SMCD' + Date.now();
|
||||
parts = []
|
||||
parts.push 'Content-Disposition: form-data; name="upfile"; filename="' + data.upfile.name + '"\r\n' + 'Content-Type: ' + data.upfile.type + '\r\n\r\n' + data.upfile.buffer + '\r\n'
|
||||
delete data.upfile
|
||||
|
||||
for name, val of data
|
||||
parts.push 'Content-Disposition: form-data; name="' + name + '"\r\n\r\n' + val + '\r\n' if val
|
||||
form = '--' + boundary + '\r\n' + parts.join('--' + boundary + '\r\n') + '--' + boundary + '--\r\n'
|
||||
|
||||
else
|
||||
form = new FormData()
|
||||
for name, val of data
|
||||
form.append name, val if val
|
||||
|
||||
callbacks =
|
||||
onload: ->
|
||||
QR.message.send
|
||||
req: 'response'
|
||||
html: @response
|
||||
onerror: ->
|
||||
# CORS disabled error: redirecting to banned page ;_;
|
||||
QR.message.send req: 'banned'
|
||||
opts =
|
||||
form: form
|
||||
type: 'post'
|
||||
upCallbacks:
|
||||
onload: ->
|
||||
QR.message.send
|
||||
req: 'status'
|
||||
progress: '...'
|
||||
onprogress: (e) ->
|
||||
QR.message.send
|
||||
req: 'status'
|
||||
progress: "#{Math.round e.loaded / e.total * 100}%"
|
||||
if boundary
|
||||
opts.headers =
|
||||
'Content-Type': 'multipart/form-data;boundary=' + boundary
|
||||
|
||||
QR.ajax = $.ajax url, callbacks, opts
|
||||
abort: ->
|
||||
QR.ajax?.abort()
|
||||
QR.status()
|
||||
|
||||
Options =
|
||||
init: ->
|
||||
@ -1773,6 +1649,8 @@ Options =
|
||||
$.on a, 'click', Options.dialog
|
||||
$.replace home.firstElementChild, a
|
||||
unless $.get 'firstrun'
|
||||
# Prevent race conditions
|
||||
Favicon.init() unless Favicon.el
|
||||
$.set 'firstrun', true
|
||||
Options.dialog()
|
||||
|
||||
@ -2175,8 +2053,7 @@ Updater =
|
||||
else
|
||||
d.title = d.title.match(/^.+-/)[0] + ' 404'
|
||||
Unread.update true
|
||||
QR.message.send req: 'abort'
|
||||
QR.status()
|
||||
QR.abort()
|
||||
return
|
||||
|
||||
Updater.retryCoef = 10
|
||||
@ -2195,7 +2072,7 @@ Updater =
|
||||
return
|
||||
Updater.lastModified = @getResponseHeader 'Last-Modified'
|
||||
|
||||
doc = d.implementation.createHTMLDocument null
|
||||
doc = d.implementation.createHTMLDocument ''
|
||||
doc.documentElement.innerHTML = @response
|
||||
|
||||
id = $('input', Updater.br.previousElementSibling).name
|
||||
@ -2608,7 +2485,7 @@ QuoteInline =
|
||||
inline = QuoteInline.table id, el.innerHTML
|
||||
if (i = Unread.replies.indexOf el.parentNode.parentNode.parentNode) isnt -1
|
||||
Unread.replies.splice i, 1
|
||||
Unread.update()
|
||||
Unread.update true
|
||||
if /\bbacklink\b/.test q.className
|
||||
$.after q.parentNode, inline
|
||||
if Conf['Forward Hiding']
|
||||
@ -2647,7 +2524,7 @@ QuoteInline =
|
||||
inline.textContent = "#{req.status} #{req.statusText}"
|
||||
return
|
||||
|
||||
doc = d.implementation.createHTMLDocument null
|
||||
doc = d.implementation.createHTMLDocument ''
|
||||
doc.documentElement.innerHTML = req.response
|
||||
|
||||
node =
|
||||
@ -2721,7 +2598,7 @@ QuotePreview =
|
||||
qp.textContent = "#{req.status} #{req.statusText}"
|
||||
return
|
||||
|
||||
doc = d.implementation.createHTMLDocument null
|
||||
doc = d.implementation.createHTMLDocument ''
|
||||
doc.documentElement.innerHTML = req.response
|
||||
|
||||
node =
|
||||
@ -2939,6 +2816,7 @@ Unread =
|
||||
|
||||
Favicon =
|
||||
init: ->
|
||||
return if @el # Prevent race condition with options first run
|
||||
@el = $ 'link[rel="shortcut icon"]', d.head
|
||||
@el.type = 'image/x-icon'
|
||||
{href} = @el
|
||||
@ -3029,6 +2907,7 @@ ImageHover =
|
||||
|
||||
AutoGif =
|
||||
init: ->
|
||||
return if g.BOARD is 'gif'
|
||||
Main.callbacks.push @node
|
||||
node: (post) ->
|
||||
return if post.root.hidden or not post.img
|
||||
@ -3174,17 +3053,11 @@ Main =
|
||||
|
||||
switch location.hostname
|
||||
when 'sys.4chan.org'
|
||||
if path is '/robots.txt'
|
||||
QR.message.send req: 'status', ready: true
|
||||
else if /report/.test location.search
|
||||
if /report/.test location.search
|
||||
$.ready ->
|
||||
$.on $.id('recaptcha_response_field'), 'keydown', (e) ->
|
||||
window.location = 'javascript:Recaptcha.reload()' if e.keyCode is 8 and not e.target.value
|
||||
return
|
||||
when 'www.4chan.org'
|
||||
if path is '/banned'
|
||||
QR.message.send req: 'banned'
|
||||
return
|
||||
when 'images.4chan.org'
|
||||
$.ready -> Redirect.init() if d.title is '4chan - 404'
|
||||
return
|
||||
@ -3361,11 +3234,7 @@ Main =
|
||||
$.on d, 'DOMNodeInserted', Main.addStyle
|
||||
|
||||
message: (e) ->
|
||||
{data} = e
|
||||
if data.QR
|
||||
QR.message.receive data
|
||||
return
|
||||
{version} = data
|
||||
{version} = e.data
|
||||
if version and version isnt Main.version and confirm 'An updated version of 4chan X is available, would you like to install it now?'
|
||||
window.location = "https://raw.github.com/mayhemydg/4chan-x/#{version}/4chan_x.user.js"
|
||||
|
||||
@ -3401,7 +3270,7 @@ Main =
|
||||
Main.node [Main.preParse target] if target.nodeName is 'TABLE'
|
||||
|
||||
namespace: '4chan_x.'
|
||||
version: '2.29.1'
|
||||
version: '2.29.3'
|
||||
callbacks: []
|
||||
css: '
|
||||
/* dialog styling */
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user