Merge branch 'v3' of git://github.com/MayhemYDG/4chan-x into v3

Conflicts:
	src/General/Main.coffee
	src/General/lib/$.coffee
	src/Monitoring/Unread.coffee
	src/Posting/QuickReply.coffee
This commit is contained in:
Zixaphir 2013-08-07 13:53:35 -07:00
commit 80884e2bde
6 changed files with 137 additions and 142 deletions

View File

@ -441,13 +441,22 @@
return fd; return fd;
}; };
$.ajax = function(url, callbacks, opts) { $.extend = function(object, properties) {
var cred, err, form, headers, key, r, sync, type, upCallbacks, val; var key, val;
if (opts == null) { for (key in properties) {
opts = {}; val = properties[key];
object[key] = val;
} }
type = opts.type, cred = opts.cred, headers = opts.headers, upCallbacks = opts.upCallbacks, form = opts.form, sync = opts.sync; };
$.ajax = function(url, options, extra) {
var form, headers, key, r, sync, type, upCallbacks, val;
if (extra == null) {
extra = {};
}
type = extra.type, headers = extra.headers, upCallbacks = extra.upCallbacks, form = extra.form, sync = extra.sync;
r = new XMLHttpRequest(); r = new XMLHttpRequest();
r.overrideMimeType('text/html'); r.overrideMimeType('text/html');
type || (type = form && 'post' || 'get'); type || (type = form && 'post' || 'get');
@ -456,13 +465,8 @@
val = headers[key]; val = headers[key];
r.setRequestHeader(key, val); r.setRequestHeader(key, val);
} }
$.extend(r, callbacks); $.extend(r, options);
$.extend(r.upload, upCallbacks); $.extend(r.upload, upCallbacks);
try {
r.withCredentials = cred;
} catch (_error) {
err = _error;
}
r.send(form); r.send(form);
return r; return r;
}; };
@ -5968,7 +5972,7 @@
}, },
preSubmitHooks: [], preSubmitHooks: [],
submit: function(e) { submit: function(e) {
var callbacks, challenge, err, filetag, hook, opts, post, postData, response, textOnly, thread, threadID, _i, _len, _ref, _ref1; var challenge, err, extra, filetag, hook, options, post, postData, response, textOnly, thread, threadID, _i, _len, _ref, _ref1;
if (e != null) { if (e != null) {
e.preventDefault(); e.preventDefault();
@ -6047,7 +6051,9 @@
recaptcha_challenge_field: challenge, recaptcha_challenge_field: challenge,
recaptcha_response_field: response recaptcha_response_field: response
}; };
callbacks = { options = {
responseType: 'document',
withCredentials: true,
onload: QR.response, onload: QR.response,
onerror: function() { onerror: function() {
delete QR.req; delete QR.req;
@ -6055,12 +6061,11 @@
QR.cooldown.auto = false; QR.cooldown.auto = false;
QR.status(); QR.status();
return QR.error($.el('span', { return QR.error($.el('span', {
innerHTML: "4chan X encountered an error while posting. Please try again. \n[<a href=\"https://github.com/seaweedchan/4chan-x/wiki/Frequently-Asked-Questions#what-does-4chan-x-encountered-an-error-while-posting-please-try-again-mean\" target=_blank>?</a>]" innerHTML: "4chan X encountered an error while posting. Please try again.\n[<a href=\"https://github.com/seaweedchan/4chan-x/wiki/Frequently-Asked-Questions#what-does-4chan-x-encountered-an-error-while-posting-please-try-again-mean\" target=_blank>?</a>]"
})); }));
} }
}; };
opts = { extra = {
cred: true,
form: $.formData(postData), form: $.formData(postData),
upCallbacks: { upCallbacks: {
onload: function() { onload: function() {
@ -6075,30 +6080,29 @@
} }
} }
}; };
QR.req = $.ajax($.id('postForm').parentNode.action, callbacks, opts); QR.req = $.ajax($.id('postForm').parentNode.action, options, extra);
QR.req.uploadStartTime = Date.now(); QR.req.uploadStartTime = Date.now();
QR.req.progress = '...'; QR.req.progress = '...';
return QR.status(); return QR.status();
}, },
response: function() { response: function() {
var URL, ban, board, err, h1, isReply, m, post, postID, req, threadID, tmpDoc, _, _ref, _ref1; var URL, ban, board, err, h1, isReply, m, post, postID, req, resDoc, threadID, _, _ref, _ref1;
req = QR.req; req = QR.req;
delete QR.req; delete QR.req;
post = QR.posts[0]; post = QR.posts[0];
post.unlock(); post.unlock();
tmpDoc = d.implementation.createHTMLDocument(''); resDoc = req.response;
tmpDoc.documentElement.innerHTML = req.response; if (ban = $('.banType', resDoc)) {
if (ban = $('.banType', tmpDoc)) { board = $('.board', resDoc).innerHTML;
board = $('.board', tmpDoc).innerHTML;
err = $.el('span', { err = $.el('span', {
innerHTML: ban.textContent.toLowerCase() === 'banned' ? ("You are banned on " + board + "! ;_;<br>") + "Click <a href=//www.4chan.org/banned target=_blank>here</a> to see the reason." : ("You were issued a warning on " + board + " as " + ($('.nameBlock', tmpDoc).innerHTML) + ".<br>") + ("Reason: " + ($('.reason', tmpDoc).innerHTML)) innerHTML: ban.textContent.toLowerCase() === 'banned' ? "You are banned on " + board + "! ;_;<br>\nClick <a href=//www.4chan.org/banned target=_blank>here</a> to see the reason." : "You were issued a warning on " + board + " as " + ($('.nameBlock', resDoc).innerHTML) + ".<br>\nReason: " + ($('.reason', resDoc).innerHTML)
}); });
} else if (err = tmpDoc.getElementById('errmsg')) { } else if (err = resDoc.getElementById('errmsg')) {
if ((_ref = $('a', err)) != null) { if ((_ref = $('a', err)) != null) {
_ref.target = '_blank'; _ref.target = '_blank';
} }
} else if (tmpDoc.title !== 'Post successful!') { } else if (resDoc.title !== 'Post successful!') {
err = 'Connection error with sys.4chan.org.'; err = 'Connection error with sys.4chan.org.';
} else if (req.status !== 200) { } else if (req.status !== 200) {
err = "Error " + req.statusText + " (" + req.status + ")"; err = "Error " + req.statusText + " (" + req.status + ")";
@ -6124,8 +6128,8 @@
QR.error(err); QR.error(err);
return; return;
} }
h1 = $('h1', resDoc);
QR.cleanNotifications(); QR.cleanNotifications();
h1 = $('h1', tmpDoc);
if (Conf['Posting Success Notifications']) { if (Conf['Posting Success Notifications']) {
QR.notifications.push(new Notification('success', h1.textContent, 5)); QR.notifications.push(new Notification('success', h1.textContent, 5));
} }
@ -6879,6 +6883,8 @@
form[post.ID] = 'delete'; form[post.ID] = 'delete';
link = this; link = this;
return $.ajax($.id('delform').action.replace("/" + g.BOARD + "/", "/" + post.board + "/"), { return $.ajax($.id('delform').action.replace("/" + g.BOARD + "/", "/" + post.board + "/"), {
responseType: 'document',
withCredentials: true,
onload: function() { onload: function() {
return DeleteLink.load(link, post, fileOnly, this.response); return DeleteLink.load(link, post, fileOnly, this.response);
}, },
@ -6886,22 +6892,19 @@
return DeleteLink.error(link); return DeleteLink.error(link);
} }
}, { }, {
cred: true,
form: $.formData(form) form: $.formData(form)
}); });
}, },
load: function(link, post, fileOnly, html) { load: function(link, post, fileOnly, resDoc) {
var msg, s, tmpDoc; var msg, s;
tmpDoc = d.implementation.createHTMLDocument(''); if (resDoc.title === '4chan - Banned') {
tmpDoc.documentElement.innerHTML = html;
if (tmpDoc.title === '4chan - Banned') {
s = 'Banned!'; s = 'Banned!';
} else if (msg = tmpDoc.getElementById('errmsg')) { } else if (msg = resDoc.getElementById('errmsg')) {
s = msg.textContent; s = msg.textContent;
$.on(link, 'click', DeleteLink["delete"]); $.on(link, 'click', DeleteLink["delete"]);
} else { } else {
if (tmpDoc.title === 'Updating index...') { if (resDoc.title === 'Updating index...') {
(post.origin || post).kill(fileOnly); (post.origin || post).kill(fileOnly);
} }
s = 'Deleted'; s = 'Deleted';
@ -7930,8 +7933,7 @@
if (Conf['Unread Line']) { if (Conf['Unread Line']) {
Unread.setLine(posts.contains(Unread.posts[0])); Unread.setLine(posts.contains(Unread.posts[0]));
} }
Unread.read(); return Unread.read();
return Unread.update();
}, },
addPostQuotingYou: function(post) { addPostQuotingYou: function(post) {
var quotelink, _i, _len, _ref; var quotelink, _i, _len, _ref;
@ -7981,17 +7983,16 @@
} }
return arr.splice(0, i); return arr.splice(0, i);
}, },
read: $.debounce(50, function(e) { read: $.debounce(50, function() {
var ID, bottom, height, i, post, posts, read; var ID, bottom, height, i, post, posts;
if (d.hidden || !Unread.posts.length) { if (d.hidden || !Unread.posts.length) {
return; return;
} }
height = doc.clientHeight; height = doc.clientHeight;
posts = Unread.posts; posts = Unread.posts;
read = []; i = 0;
i = posts.length; while (post = posts[i++]) {
while (post = posts[--i]) {
bottom = post.nodes.root.getBoundingClientRect().bottom; bottom = post.nodes.root.getBoundingClientRect().bottom;
if (bottom < height) { if (bottom < height) {
ID = post.ID; ID = post.ID;
@ -8004,9 +8005,7 @@
Unread.lastReadPost = ID; Unread.lastReadPost = ID;
Unread.saveLastReadPost(); Unread.saveLastReadPost();
Unread.readArray(Unread.postsQuotingYou); Unread.readArray(Unread.postsQuotingYou);
if (e) { return Unread.update();
return Unread.update();
}
}), }),
saveLastReadPost: $.debounce(2 * $.SECOND, function() { saveLastReadPost: $.debounce(2 * $.SECOND, function() {
if (Unread.thread.isDead) { if (Unread.thread.isDead) {

View File

@ -422,13 +422,22 @@
return fd; return fd;
}; };
$.ajax = function(url, callbacks, opts) { $.extend = function(object, properties) {
var cred, err, form, headers, key, r, sync, type, upCallbacks, val; var key, val;
if (opts == null) { for (key in properties) {
opts = {}; val = properties[key];
object[key] = val;
} }
type = opts.type, cred = opts.cred, headers = opts.headers, upCallbacks = opts.upCallbacks, form = opts.form, sync = opts.sync; };
$.ajax = function(url, options, extra) {
var form, headers, key, r, sync, type, upCallbacks, val;
if (extra == null) {
extra = {};
}
type = extra.type, headers = extra.headers, upCallbacks = extra.upCallbacks, form = extra.form, sync = extra.sync;
r = new XMLHttpRequest(); r = new XMLHttpRequest();
r.overrideMimeType('text/html'); r.overrideMimeType('text/html');
type || (type = form && 'post' || 'get'); type || (type = form && 'post' || 'get');
@ -437,13 +446,8 @@
val = headers[key]; val = headers[key];
r.setRequestHeader(key, val); r.setRequestHeader(key, val);
} }
$.extend(r, callbacks); $.extend(r, options);
$.extend(r.upload, upCallbacks); $.extend(r.upload, upCallbacks);
try {
r.withCredentials = cred;
} catch (_error) {
err = _error;
}
r.send(form); r.send(form);
return r; return r;
}; };
@ -5949,7 +5953,7 @@
}, },
preSubmitHooks: [], preSubmitHooks: [],
submit: function(e) { submit: function(e) {
var callbacks, challenge, err, filetag, hook, opts, post, postData, response, textOnly, thread, threadID, _i, _len, _ref, _ref1; var challenge, err, extra, filetag, hook, options, post, postData, response, textOnly, thread, threadID, _i, _len, _ref, _ref1;
if (e != null) { if (e != null) {
e.preventDefault(); e.preventDefault();
@ -6028,7 +6032,9 @@
recaptcha_challenge_field: challenge, recaptcha_challenge_field: challenge,
recaptcha_response_field: response recaptcha_response_field: response
}; };
callbacks = { options = {
responseType: 'document',
withCredentials: true,
onload: QR.response, onload: QR.response,
onerror: function() { onerror: function() {
delete QR.req; delete QR.req;
@ -6036,12 +6042,11 @@
QR.cooldown.auto = false; QR.cooldown.auto = false;
QR.status(); QR.status();
return QR.error($.el('span', { return QR.error($.el('span', {
innerHTML: "4chan X encountered an error while posting. Please try again. \n[<a href=\"https://github.com/seaweedchan/4chan-x/wiki/Frequently-Asked-Questions#what-does-4chan-x-encountered-an-error-while-posting-please-try-again-mean\" target=_blank>?</a>]" innerHTML: "4chan X encountered an error while posting. Please try again.\n[<a href=\"https://github.com/seaweedchan/4chan-x/wiki/Frequently-Asked-Questions#what-does-4chan-x-encountered-an-error-while-posting-please-try-again-mean\" target=_blank>?</a>]"
})); }));
} }
}; };
opts = { extra = {
cred: true,
form: $.formData(postData), form: $.formData(postData),
upCallbacks: { upCallbacks: {
onload: function() { onload: function() {
@ -6056,30 +6061,29 @@
} }
} }
}; };
QR.req = $.ajax($.id('postForm').parentNode.action, callbacks, opts); QR.req = $.ajax($.id('postForm').parentNode.action, options, extra);
QR.req.uploadStartTime = Date.now(); QR.req.uploadStartTime = Date.now();
QR.req.progress = '...'; QR.req.progress = '...';
return QR.status(); return QR.status();
}, },
response: function() { response: function() {
var URL, ban, board, err, h1, isReply, m, post, postID, req, threadID, tmpDoc, _, _ref, _ref1; var URL, ban, board, err, h1, isReply, m, post, postID, req, resDoc, threadID, _, _ref, _ref1;
req = QR.req; req = QR.req;
delete QR.req; delete QR.req;
post = QR.posts[0]; post = QR.posts[0];
post.unlock(); post.unlock();
tmpDoc = d.implementation.createHTMLDocument(''); resDoc = req.response;
tmpDoc.documentElement.innerHTML = req.response; if (ban = $('.banType', resDoc)) {
if (ban = $('.banType', tmpDoc)) { board = $('.board', resDoc).innerHTML;
board = $('.board', tmpDoc).innerHTML;
err = $.el('span', { err = $.el('span', {
innerHTML: ban.textContent.toLowerCase() === 'banned' ? ("You are banned on " + board + "! ;_;<br>") + "Click <a href=//www.4chan.org/banned target=_blank>here</a> to see the reason." : ("You were issued a warning on " + board + " as " + ($('.nameBlock', tmpDoc).innerHTML) + ".<br>") + ("Reason: " + ($('.reason', tmpDoc).innerHTML)) innerHTML: ban.textContent.toLowerCase() === 'banned' ? "You are banned on " + board + "! ;_;<br>\nClick <a href=//www.4chan.org/banned target=_blank>here</a> to see the reason." : "You were issued a warning on " + board + " as " + ($('.nameBlock', resDoc).innerHTML) + ".<br>\nReason: " + ($('.reason', resDoc).innerHTML)
}); });
} else if (err = tmpDoc.getElementById('errmsg')) { } else if (err = resDoc.getElementById('errmsg')) {
if ((_ref = $('a', err)) != null) { if ((_ref = $('a', err)) != null) {
_ref.target = '_blank'; _ref.target = '_blank';
} }
} else if (tmpDoc.title !== 'Post successful!') { } else if (resDoc.title !== 'Post successful!') {
err = 'Connection error with sys.4chan.org.'; err = 'Connection error with sys.4chan.org.';
} else if (req.status !== 200) { } else if (req.status !== 200) {
err = "Error " + req.statusText + " (" + req.status + ")"; err = "Error " + req.statusText + " (" + req.status + ")";
@ -6105,8 +6109,8 @@
QR.error(err); QR.error(err);
return; return;
} }
h1 = $('h1', resDoc);
QR.cleanNotifications(); QR.cleanNotifications();
h1 = $('h1', tmpDoc);
if (Conf['Posting Success Notifications']) { if (Conf['Posting Success Notifications']) {
QR.notifications.push(new Notification('success', h1.textContent, 5)); QR.notifications.push(new Notification('success', h1.textContent, 5));
} }
@ -6860,6 +6864,8 @@
form[post.ID] = 'delete'; form[post.ID] = 'delete';
link = this; link = this;
return $.ajax($.id('delform').action.replace("/" + g.BOARD + "/", "/" + post.board + "/"), { return $.ajax($.id('delform').action.replace("/" + g.BOARD + "/", "/" + post.board + "/"), {
responseType: 'document',
withCredentials: true,
onload: function() { onload: function() {
return DeleteLink.load(link, post, fileOnly, this.response); return DeleteLink.load(link, post, fileOnly, this.response);
}, },
@ -6867,22 +6873,19 @@
return DeleteLink.error(link); return DeleteLink.error(link);
} }
}, { }, {
cred: true,
form: $.formData(form) form: $.formData(form)
}); });
}, },
load: function(link, post, fileOnly, html) { load: function(link, post, fileOnly, resDoc) {
var msg, s, tmpDoc; var msg, s;
tmpDoc = d.implementation.createHTMLDocument(''); if (resDoc.title === '4chan - Banned') {
tmpDoc.documentElement.innerHTML = html;
if (tmpDoc.title === '4chan - Banned') {
s = 'Banned!'; s = 'Banned!';
} else if (msg = tmpDoc.getElementById('errmsg')) { } else if (msg = resDoc.getElementById('errmsg')) {
s = msg.textContent; s = msg.textContent;
$.on(link, 'click', DeleteLink["delete"]); $.on(link, 'click', DeleteLink["delete"]);
} else { } else {
if (tmpDoc.title === 'Updating index...') { if (resDoc.title === 'Updating index...') {
(post.origin || post).kill(fileOnly); (post.origin || post).kill(fileOnly);
} }
s = 'Deleted'; s = 'Deleted';
@ -7911,8 +7914,7 @@
if (Conf['Unread Line']) { if (Conf['Unread Line']) {
Unread.setLine(posts.contains(Unread.posts[0])); Unread.setLine(posts.contains(Unread.posts[0]));
} }
Unread.read(); return Unread.read();
return Unread.update();
}, },
addPostQuotingYou: function(post) { addPostQuotingYou: function(post) {
var quotelink, _i, _len, _ref; var quotelink, _i, _len, _ref;
@ -7962,17 +7964,16 @@
} }
return arr.splice(0, i); return arr.splice(0, i);
}, },
read: $.debounce(50, function(e) { read: $.debounce(50, function() {
var ID, bottom, height, i, post, posts, read; var ID, bottom, height, i, post, posts;
if (d.hidden || !Unread.posts.length) { if (d.hidden || !Unread.posts.length) {
return; return;
} }
height = doc.clientHeight; height = doc.clientHeight;
posts = Unread.posts; posts = Unread.posts;
read = []; i = 0;
i = posts.length; while (post = posts[i++]) {
while (post = posts[--i]) {
bottom = post.nodes.root.getBoundingClientRect().bottom; bottom = post.nodes.root.getBoundingClientRect().bottom;
if (bottom < height) { if (bottom < height) {
ID = post.ID; ID = post.ID;
@ -7985,9 +7986,7 @@
Unread.lastReadPost = ID; Unread.lastReadPost = ID;
Unread.saveLastReadPost(); Unread.saveLastReadPost();
Unread.readArray(Unread.postsQuotingYou); Unread.readArray(Unread.postsQuotingYou);
if (e) { return Unread.update();
return Unread.update();
}
}), }),
saveLastReadPost: $.debounce(2 * $.SECOND, function() { saveLastReadPost: $.debounce(2 * $.SECOND, function() {
if (Unread.thread.isDead) { if (Unread.thread.isDead) {

View File

@ -70,24 +70,21 @@ $.formData = (form) ->
fd.append key, val fd.append key, val
fd fd
$.ajax = (url, callbacks, opts={}) -> $.extend = (object, properties) ->
{type, cred, headers, upCallbacks, form, sync} = opts for key, val of properties
object[key] = val
return
$.ajax = (url, options, extra={}) ->
{type, headers, upCallbacks, form, sync} = extra
r = new XMLHttpRequest() r = new XMLHttpRequest()
r.overrideMimeType 'text/html' r.overrideMimeType 'text/html'
type or= form and 'post' or 'get' type or= form and 'post' or 'get'
r.open type, url, !sync r.open type, url, !sync
for key, val of headers for key, val of headers
r.setRequestHeader key, val r.setRequestHeader key, val
$.extend r, callbacks $.extend r, options
$.extend r.upload, upCallbacks $.extend r.upload, upCallbacks
try
# Firefox throws an error if you try
# to set this on a synchronous XHR.
# Only cookies from the remote domain
# are used in a request withCredentials.
r.withCredentials = cred
catch err
# do nothing
r.send form r.send form
r r

View File

@ -55,21 +55,20 @@ DeleteLink =
link = @ link = @
$.ajax $.id('delform').action.replace("/#{g.BOARD}/", "/#{post.board}/"), $.ajax $.id('delform').action.replace("/#{g.BOARD}/", "/#{post.board}/"),
responseType: 'document'
withCredentials: true
onload: -> DeleteLink.load link, post, fileOnly, @response onload: -> DeleteLink.load link, post, fileOnly, @response
onerror: -> DeleteLink.error link onerror: -> DeleteLink.error link
, ,
cred: true
form: $.formData form form: $.formData form
load: (link, post, fileOnly, html) -> load: (link, post, fileOnly, resDoc) ->
tmpDoc = d.implementation.createHTMLDocument '' if resDoc.title is '4chan - Banned' # Ban/warn check
tmpDoc.documentElement.innerHTML = html
if tmpDoc.title is '4chan - Banned' # Ban/warn check
s = 'Banned!' s = 'Banned!'
else if msg = tmpDoc.getElementById 'errmsg' # error! else if msg = resDoc.getElementById 'errmsg' # error!
s = msg.textContent s = msg.textContent
$.on link, 'click', DeleteLink.delete $.on link, 'click', DeleteLink.delete
else else
if tmpDoc.title is 'Updating index...' if resDoc.title is 'Updating index...'
# We're 100% sure. # We're 100% sure.
(post.origin or post).kill fileOnly (post.origin or post).kill fileOnly
s = 'Deleted' s = 'Deleted'

View File

@ -86,7 +86,6 @@ Unread =
# Force line on visible threads if there were no unread posts previously. # Force line on visible threads if there were no unread posts previously.
Unread.setLine posts.contains Unread.posts[0] Unread.setLine posts.contains Unread.posts[0]
Unread.read() Unread.read()
Unread.update()
addPostQuotingYou: (post) -> addPostQuotingYou: (post) ->
return unless QR.db return unless QR.db
@ -116,24 +115,23 @@ Unread =
break if post.ID > Unread.lastReadPost break if post.ID > Unread.lastReadPost
arr.splice 0, i arr.splice 0, i
read: $.debounce 50, (e) -> read: $.debounce 50, ->
return if d.hidden or !Unread.posts.length return if d.hidden or !Unread.posts.length
height = doc.clientHeight height = doc.clientHeight
{posts} = Unread {posts} = Unread
read = [] i = 0
i = posts.length
while post = posts[--i] while post = posts[i++]
{bottom} = post.nodes.root.getBoundingClientRect() {bottom} = post.nodes.root.getBoundingClientRect()
if (bottom < height) # post is completely read if (bottom < height) # post is completely read
ID = post.ID {ID} = post
posts.remove post posts.remove post
return unless ID return unless ID
Unread.lastReadPost = ID Unread.lastReadPost = ID
Unread.saveLastReadPost() Unread.saveLastReadPost()
Unread.readArray Unread.postsQuotingYou Unread.readArray Unread.postsQuotingYou
Unread.update() if e Unread.update()
saveLastReadPost: $.debounce 2 * $.SECOND, -> saveLastReadPost: $.debounce 2 * $.SECOND, ->
return if Unread.thread.isDead return if Unread.thread.isDead

View File

@ -142,7 +142,7 @@ QR =
else else
QR.notifications.push new Notification 'warning', el QR.notifications.push new Notification 'warning', el
alert el.textContent if d.hidden alert el.textContent if d.hidden
notifications: [] notifications: []
cleanNotifications: -> cleanNotifications: ->
for notification in QR.notifications for notification in QR.notifications
@ -718,7 +718,7 @@ QR =
dragOver: (e) -> dragOver: (e) ->
e.preventDefault() e.preventDefault()
e.dataTransfer.dropEffect = 'move' e.dataTransfer.dropEffect = 'move'
drop: -> drop: ->
$.rmClass @, 'over' $.rmClass @, 'over'
return unless @draggable return unless @draggable
@ -736,7 +736,7 @@ QR =
return if d.cookie.indexOf('pass_enabled=1') >= 0 return if d.cookie.indexOf('pass_enabled=1') >= 0
return unless @isEnabled = !!$.id 'captchaFormPart' return unless @isEnabled = !!$.id 'captchaFormPart'
$.asap (-> $.id 'recaptcha_challenge_field_holder'), @ready.bind @ $.asap (-> $.id 'recaptcha_challenge_field_holder'), @ready.bind @
ready: -> ready: ->
setLifetime = (e) => @lifetime = e.detail setLifetime = (e) => @lifetime = e.detail
$.on window, 'captcha:timeout', setLifetime $.on window, 'captcha:timeout', setLifetime
@ -784,7 +784,7 @@ QR =
sync: (captchas) -> sync: (captchas) ->
QR.captcha.captchas = captchas QR.captcha.captchas = captchas
QR.captcha.count() QR.captcha.count()
getOne: -> getOne: ->
@clear() @clear()
if captcha = @captchas.shift() if captcha = @captchas.shift()
@ -800,7 +800,7 @@ QR =
# If there's only one word, duplicate it. # If there's only one word, duplicate it.
response = "#{response} #{response}" unless /\s/.test response response = "#{response} #{response}" unless /\s/.test response
{challenge, response} {challenge, response}
save: -> save: ->
return unless response = @nodes.input.value.trim() return unless response = @nodes.input.value.trim()
@captchas.push @captchas.push
@ -810,7 +810,7 @@ QR =
@count() @count()
@reload() @reload()
$.set 'captchas', @captchas $.set 'captchas', @captchas
clear: -> clear: ->
now = Date.now() now = Date.now()
for captcha, i in @captchas for captcha, i in @captchas
@ -819,7 +819,7 @@ QR =
@captchas = @captchas[i..] @captchas = @captchas[i..]
@count() @count()
$.set 'captchas', @captchas $.set 'captchas', @captchas
load: -> load: ->
return unless @nodes.challenge.firstChild return unless @nodes.challenge.firstChild
# -1 minute to give upload some time. # -1 minute to give upload some time.
@ -829,7 +829,7 @@ QR =
@nodes.img.src = "//www.google.com/recaptcha/api/image?c=#{challenge}" @nodes.img.src = "//www.google.com/recaptcha/api/image?c=#{challenge}"
@nodes.input.value = null @nodes.input.value = null
@clear() @clear()
count: -> count: ->
count = @captchas.length count = @captchas.length
@nodes.input.placeholder = switch count @nodes.input.placeholder = switch count
@ -840,13 +840,13 @@ QR =
else else
"Verification (#{count} cached captchas)" "Verification (#{count} cached captchas)"
@nodes.input.alt = count @nodes.input.alt = count
reload: (focus) -> reload: (focus) ->
# the 't' argument prevents the input from being focused # the 't' argument prevents the input from being focused
$.globalEval 'Recaptcha.reload("t")' $.globalEval 'Recaptcha.reload("t")'
# Focus if we meant to. # Focus if we meant to.
@nodes.input.focus() if focus @nodes.input.focus() if focus
keydown: (e) -> keydown: (e) ->
if e.keyCode is 8 and not @nodes.input.value if e.keyCode is 8 and not @nodes.input.value
@reload() @reload()
@ -971,7 +971,7 @@ QR =
$.event 'QRDialogCreation', null, dialog $.event 'QRDialogCreation', null, dialog
preSubmitHooks: [] preSubmitHooks: []
submit: (e) -> submit: (e) ->
e?.preventDefault() e?.preventDefault()
@ -1045,7 +1045,9 @@ QR =
recaptcha_challenge_field: challenge recaptcha_challenge_field: challenge
recaptcha_response_field: response recaptcha_response_field: response
callbacks = options =
responseType: 'document'
withCredentials: true
onload: QR.response onload: QR.response
onerror: -> onerror: ->
# Connection error, or # Connection error, or
@ -1056,11 +1058,10 @@ QR =
QR.status() QR.status()
QR.error $.el 'span', QR.error $.el 'span',
innerHTML: """ innerHTML: """
4chan X encountered an error while posting. Please try again. 4chan X encountered an error while posting. Please try again.
[<a href="https://github.com/seaweedchan/4chan-x/wiki/Frequently-Asked-Questions#what-does-4chan-x-encountered-an-error-while-posting-please-try-again-mean" target=_blank>?</a>] [<a href="https://github.com/seaweedchan/4chan-x/wiki/Frequently-Asked-Questions#what-does-4chan-x-encountered-an-error-while-posting-please-try-again-mean" target=_blank>?</a>]
""" """
opts = extra =
cred: true
form: $.formData postData form: $.formData postData
upCallbacks: upCallbacks:
onload: -> onload: ->
@ -1074,7 +1075,7 @@ QR =
QR.req.progress = "#{Math.round e.loaded / e.total * 100}%" QR.req.progress = "#{Math.round e.loaded / e.total * 100}%"
QR.status() QR.status()
QR.req = $.ajax $.id('postForm').parentNode.action, callbacks, opts QR.req = $.ajax $.id('postForm').parentNode.action, options, extra
# Starting to upload might take some time. # Starting to upload might take some time.
# Provide some feedback that we're starting to submit. # Provide some feedback that we're starting to submit.
QR.req.uploadStartTime = Date.now() QR.req.uploadStartTime = Date.now()
@ -1088,20 +1089,23 @@ QR =
post = QR.posts[0] post = QR.posts[0]
post.unlock() post.unlock()
tmpDoc = d.implementation.createHTMLDocument '' resDoc = req.response
tmpDoc.documentElement.innerHTML = req.response if ban = $ '.banType', resDoc # banned/warning
if ban = $ '.banType', tmpDoc # banned/warning board = $('.board', resDoc).innerHTML
board = $('.board', tmpDoc).innerHTML
err = $.el 'span', innerHTML: err = $.el 'span', innerHTML:
if ban.textContent.toLowerCase() is 'banned' if ban.textContent.toLowerCase() is 'banned'
"You are banned on #{board}! ;_;<br>" + """
"Click <a href=//www.4chan.org/banned target=_blank>here</a> to see the reason." You are banned on #{board}! ;_;<br>
Click <a href=//www.4chan.org/banned target=_blank>here</a> to see the reason.
"""
else else
"You were issued a warning on #{board} as #{$('.nameBlock', tmpDoc).innerHTML}.<br>" + """
"Reason: #{$('.reason', tmpDoc).innerHTML}" You were issued a warning on #{board} as #{$('.nameBlock', resDoc).innerHTML}.<br>
else if err = tmpDoc.getElementById 'errmsg' # error! Reason: #{$('.reason', resDoc).innerHTML}
"""
else if err = resDoc.getElementById 'errmsg' # error!
$('a', err)?.target = '_blank' # duplicate image link $('a', err)?.target = '_blank' # duplicate image link
else if tmpDoc.title isnt 'Post successful!' else if resDoc.title isnt 'Post successful!'
err = 'Connection error with sys.4chan.org.' err = 'Connection error with sys.4chan.org.'
else if req.status isnt 200 else if req.status isnt 200
err = "Error #{req.statusText} (#{req.status})" err = "Error #{req.statusText} (#{req.status})"
@ -1134,11 +1138,10 @@ QR =
QR.status() QR.status()
QR.error err QR.error err
return return
h1 = $ 'h1', resDoc
QR.cleanNotifications() QR.cleanNotifications()
h1 = $ 'h1', tmpDoc
if Conf['Posting Success Notifications'] if Conf['Posting Success Notifications']
QR.notifications.push new Notification 'success', h1.textContent, 5 QR.notifications.push new Notification 'success', h1.textContent, 5