Quick Reply
This commit is contained in:
parent
4a0377dedf
commit
13563ffcda
@ -9101,10 +9101,19 @@
|
|||||||
QR = {
|
QR = {
|
||||||
mimeTypes: ['image/jpeg', 'image/png', 'image/gif', 'application/pdf', 'application/vnd.adobe.flash.movie', 'application/x-shockwave-flash', 'video/webm'],
|
mimeTypes: ['image/jpeg', 'image/png', 'image/gif', 'application/pdf', 'application/vnd.adobe.flash.movie', 'application/x-shockwave-flash', 'video/webm'],
|
||||||
init: function() {
|
init: function() {
|
||||||
var con, sc;
|
var con, noscript, sc;
|
||||||
this.db = new DataBoard('yourPosts');
|
this.db = new DataBoard('yourPosts');
|
||||||
this.posts = [];
|
this.posts = [];
|
||||||
|
if (g.VIEW === 'archive') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$.globalEval('document.documentElement.dataset.jsEnabled = true;');
|
||||||
|
noscript = Conf['Force Noscript Captcha'] || !doc.dataset.jsEnabled;
|
||||||
|
this.captcha = Captcha[noscript ? 'noscript' : 'v2'];
|
||||||
$.on(d, '4chanXInitFinished', this.initReady);
|
$.on(d, '4chanXInitFinished', this.initReady);
|
||||||
|
window.addEventListener('focus', this.focus, true);
|
||||||
|
window.addEventListener('blur', this.focus, true);
|
||||||
|
$.on(d, 'click', this.focus);
|
||||||
Post.callbacks.push({
|
Post.callbacks.push({
|
||||||
name: 'Quick Reply',
|
name: 'Quick Reply',
|
||||||
cb: this.node
|
cb: this.node
|
||||||
@ -9154,6 +9163,7 @@
|
|||||||
if (!QR.postingIsEnabled) {
|
if (!QR.postingIsEnabled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
$.on(d, 'paste', QR.paste);
|
||||||
$.on(d, 'dragover', QR.dragOver);
|
$.on(d, 'dragover', QR.dragOver);
|
||||||
$.on(d, 'drop', QR.dropFile);
|
$.on(d, 'drop', QR.dropFile);
|
||||||
$.on(d, 'dragstart dragend', QR.drag);
|
$.on(d, 'dragstart dragend', QR.drag);
|
||||||
@ -9163,12 +9173,17 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QR.open();
|
QR.open();
|
||||||
if (Conf['Auto-Hide QR']) {
|
if (Conf['Auto Hide QR']) {
|
||||||
return QR.hide();
|
return QR.hide();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
statusCheck: function() {
|
statusCheck: function() {
|
||||||
if (g.DEAD) {
|
var thread;
|
||||||
|
if (!QR.nodes) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
thread = QR.posts[0].thread;
|
||||||
|
if (thread !== 'new' && g.threads["" + g.BOARD + "." + thread].isDead) {
|
||||||
return QR.abort();
|
return QR.abort();
|
||||||
} else {
|
} else {
|
||||||
return QR.status();
|
return QR.status();
|
||||||
@ -9196,9 +9211,11 @@
|
|||||||
open: function() {
|
open: function() {
|
||||||
var err;
|
var err;
|
||||||
if (QR.nodes) {
|
if (QR.nodes) {
|
||||||
|
if (QR.nodes.el.hidden) {
|
||||||
|
QR.captcha.setup();
|
||||||
|
}
|
||||||
QR.nodes.el.hidden = false;
|
QR.nodes.el.hidden = false;
|
||||||
QR.unhide();
|
QR.unhide();
|
||||||
QR.captcha.setup();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@ -9235,14 +9252,34 @@
|
|||||||
QR.status();
|
QR.status();
|
||||||
return QR.captcha.destroy();
|
return QR.captcha.destroy();
|
||||||
},
|
},
|
||||||
focusin: function() {
|
focus: function() {
|
||||||
if ($.hasClass(QR.nodes.el, 'autohide') && !$.hasClass(QR.nodes.el, 'focus')) {
|
return $.queueTask(function() {
|
||||||
QR.captcha.setup();
|
var focus;
|
||||||
}
|
if (!QR.nodes) {
|
||||||
return $.addClass(QR.nodes.el, 'focus');
|
return;
|
||||||
|
}
|
||||||
|
if (!$$('.goog-bubble-content > iframe').some(function(el) {
|
||||||
|
return el.getBoundingClientRect().top >= 0;
|
||||||
|
})) {
|
||||||
|
focus = d.activeElement && QR.nodes.el.contains(d.activeElement);
|
||||||
|
$[focus ? 'addClass' : 'rmClass'](QR.nodes.el, 'focus');
|
||||||
|
}
|
||||||
|
if (typeof chrome !== "undefined" && chrome !== null) {
|
||||||
|
if (d.activeElement && QR.nodes.el.contains(d.activeElement) && d.activeElement.nodeName === 'IFRAME') {
|
||||||
|
QR.scrollY = window.scrollY;
|
||||||
|
return $.on(d, 'scroll', QR.scrollLock);
|
||||||
|
} else {
|
||||||
|
return $.off(d, 'scroll', QR.scrollLock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
focusout: function() {
|
scrollLock: function(e) {
|
||||||
return $.rmClass(QR.nodes.el, 'focus');
|
if (d.activeElement && QR.nodes.el.contains(d.activeElement) && d.activeElement.nodeName === 'IFRAME') {
|
||||||
|
return window.scroll(window.scrollX, QR.scrollY);
|
||||||
|
} else {
|
||||||
|
return $.off(d, 'scroll', QR.scrollLock);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
hide: function() {
|
hide: function() {
|
||||||
d.activeElement.blur();
|
d.activeElement.blur();
|
||||||
@ -9271,8 +9308,10 @@
|
|||||||
}
|
}
|
||||||
if (QR.captcha.isEnabled && /captcha|verification/i.test(el.textContent)) {
|
if (QR.captcha.isEnabled && /captcha|verification/i.test(el.textContent)) {
|
||||||
QR.captcha.setup(true);
|
QR.captcha.setup(true);
|
||||||
|
QR.captcha.notify(el);
|
||||||
|
} else {
|
||||||
|
QR.notify(el);
|
||||||
}
|
}
|
||||||
QR.notify(el);
|
|
||||||
if (d.hidden) {
|
if (d.hidden) {
|
||||||
return alert(el.textContent);
|
return alert(el.textContent);
|
||||||
}
|
}
|
||||||
@ -9328,7 +9367,7 @@
|
|||||||
}
|
}
|
||||||
sel = d.getSelection();
|
sel = d.getSelection();
|
||||||
post = Get.postFromNode(this);
|
post = Get.postFromNode(this);
|
||||||
text = ">>" + post + "\n";
|
text = post.board.ID === g.BOARD.ID ? ">>" + post + "\n" : ">>>/" + post.board + "/" + post + "\n";
|
||||||
if (sel.toString().trim() && post === Get.postFromNode(sel.anchorNode)) {
|
if (sel.toString().trim() && post === Get.postFromNode(sel.anchorNode)) {
|
||||||
range = sel.getRangeAt(0);
|
range = sel.getRangeAt(0);
|
||||||
frag = range.cloneContents();
|
frag = range.cloneContents();
|
||||||
@ -9557,16 +9596,17 @@
|
|||||||
}
|
}
|
||||||
list.value = g.VIEW === 'thread' ? g.THREADID : 'new';
|
list.value = g.VIEW === 'thread' ? g.THREADID : 'new';
|
||||||
if ($.hasClass(list, 'riced')) {
|
if ($.hasClass(list, 'riced')) {
|
||||||
return list.nextElementSibling.firstChild.textContent = list.options[list.selectedIndex].textContent;
|
list.nextElementSibling.firstChild.textContent = list.options[list.selectedIndex].textContent;
|
||||||
}
|
}
|
||||||
|
return (g.VIEW === 'thread' ? $.addClass : $.rmClass)(QR.nodes.el, 'reply-to-thread');
|
||||||
},
|
},
|
||||||
dialog: function() {
|
dialog: function() {
|
||||||
var dialog, elm, event, i, items, match_max, match_min, name, node, nodes, rules, save, setNode;
|
var dialog, event, i, items, match_max, match_min, name, node, nodes, rules, save, setNode;
|
||||||
QR.nodes = nodes = {
|
QR.nodes = nodes = {
|
||||||
el: dialog = UI.dialog('qr', 'top:0;right:0;')
|
el: dialog = UI.dialog('qr', 'top:0;right:0;')
|
||||||
};
|
};
|
||||||
$.extend(dialog, {
|
$.extend(dialog, {
|
||||||
innerHTML: "<div id=qrtab class=move>\r<input type=checkbox id=autohide title=Auto-hide>\r<div id=qr-thread-select>\r<select data-name=thread title='Create a new thread / Reply'>\r<option value=new>New thread</option>\r</select>\r</div>\r<a href=javascript:; class='close fa' title=Close>\\uf00d</a>\r</div>\r<form>\r<div class=persona>\r<input name=name data-name=name list=\"list-name\" placeholder=Name class=field size=1>\r<input name=email data-name=email list=\"list-email\" placeholder=Options class=field size=1>\r<input name=sub data-name=sub list=\"list-sub\" placeholder=Subject class=field size=1> \r</div>\r<div class=textarea>\r<textarea data-name=com placeholder=Comment class=field></textarea>\r<span id=char-count></span>\r</div>\r<div id=dump-list-container>\r<div id=dump-list></div>\r<a id=add-post href=javascript:; title=\"Add a post\">+</a>\r</div>\r<div id=file-n-submit>\r<span id=qr-filename-container class=field tabindex=0>\r<span id=qr-no-file>No selected file</span>\r<input id=\"qr-filename\" data-name=\"filename\" spellcheck=\"false\">\r<span id=qr-extras-container>\r<label id=qr-spoiler-label>\r<input type=checkbox id=qr-file-spoiler title='Spoiler image'>\r</label>\r<span class=description>Spoiler</span>\r<a id=url-button><i class=\"fa\">\\uf0c1</i></a>\r<span class=description>Post from URL</span>\r<a id=dump-button title='Dump list'>+</a>\r<span class=description>Dump</span>\r<a id=qr-filerm href=javascript:; title='Remove file' class=fa>\\uf00d</a>\r<span class=description>Remove File</span>\r</span>\r</span>\r<input type=submit>\r</div>\r<input type=file multiple>\r</form>\r<datalist id=\"list-name\"></datalist>\r<datalist id=\"list-email\"></datalist>\r<datalist id=\"list-sub\"></datalist>\r"
|
innerHTML: "<div id=qrtab class=move>\r<input type=checkbox id=autohide title=Auto-hide>\r<div id=qr-thread-select>\r<select data-name=thread title='Create a new thread / Reply'>\r<option value=new>New thread</option>\r</select>\r</div>\r<a href=javascript:; class='close fa' title=Close>\\uf00d</a>\r</div>\r<form>\r<div class=persona>\r<input name=name data-name=name list=\"list-name\" placeholder=Name class=field size=1>\r<input name=email data-name=email list=\"list-email\" placeholder=Options class=field size=1>\r<input name=sub data-name=sub list=\"list-sub\" placeholder=Subject class=field size=1> \r</div>\r<div class=textarea>\r<textarea data-name=com placeholder=Comment class=field></textarea>\r<span id=char-count></span>\r</div>\r<div id=dump-list-container>\r<div id=dump-list></div>\r<a id=add-post href=javascript:; title=\"Add a post\">+</a>\r</div>\r<div id=file-n-submit>\r<span id=qr-filename-container class=field tabindex=0>\r<span id=qr-no-file>No selected file</span>\r<input id=\"qr-filename\" data-name=\"filename\" spellcheck=\"false\">\r<span id=qr-extras-container>\r<label id=qr-spoiler-label>\r<input type=checkbox id=qr-file-spoiler title='Spoiler image'>\r</label>\r<span class=description>Spoiler</span>\r<a id=url-button><i class=\"fa\">\\uf0c1</i></a>\r<span class=description>Post from URL</span>\r<a id=dump-button title='Dump list'>+</a>\r<span class=description>Dump</span>\r<a id=qr-filerm href=javascript:; title='Remove file' class=fa>\\uf00d</a>\r<span class=description>Remove File</span>\r</span>\r</span>\r<input type=submit>\r</div>\r<input type=file multiple>\r</form>\r<datalist id=\"list-name\"></datalist>\r<datalist id=\"list-email\"></datalist>\r<datalist id=\"list-sub\"></datalist>\r"
|
||||||
});
|
});
|
||||||
setNode = function(name, query) {
|
setNode = function(name, query) {
|
||||||
return nodes[name] = $(query, dialog);
|
return nodes[name] = $(query, dialog);
|
||||||
@ -9606,6 +9646,14 @@
|
|||||||
QR.max_size_video = 3145728;
|
QR.max_size_video = 3145728;
|
||||||
QR.max_width_video = QR.max_height_video = 2048;
|
QR.max_width_video = QR.max_height_video = 2048;
|
||||||
QR.max_duration_video = 120;
|
QR.max_duration_video = 120;
|
||||||
|
if (Conf['Show New Thread Option in Threads']) {
|
||||||
|
$.addClass(QR.nodes.el, 'show-new-thread-option');
|
||||||
|
}
|
||||||
|
if (Conf['Show Name and Subject']) {
|
||||||
|
$.addClass(QR.nodes.name, 'force-show');
|
||||||
|
$.addClass(QR.nodes.sub, 'force-show');
|
||||||
|
QR.nodes.email.placeholder = 'E-mail';
|
||||||
|
}
|
||||||
QR.forcedAnon = !!$('form[name="post"] input[name="name"][type="hidden"]');
|
QR.forcedAnon = !!$('form[name="post"] input[name="name"][type="hidden"]');
|
||||||
if (QR.forcedAnon) {
|
if (QR.forcedAnon) {
|
||||||
$.addClass(QR.nodes.el, 'forced-anon');
|
$.addClass(QR.nodes.el, 'forced-anon');
|
||||||
@ -9622,20 +9670,15 @@
|
|||||||
}
|
}
|
||||||
if (g.BOARD.ID === 'f' && g.VIEW !== 'thread') {
|
if (g.BOARD.ID === 'f' && g.VIEW !== 'thread') {
|
||||||
nodes.flashTag = $.el('select', {
|
nodes.flashTag = $.el('select', {
|
||||||
name: 'filetag',
|
name: 'filetag'
|
||||||
innerHTML: "<option value=0>Hentai</option>\n<option value=6>Porn</option>\n<option value=1>Japanese</option>\n<option value=2>Anime</option>\n<option value=3>Game</option>\n<option value=5>Loop</option>\n<option value=4 selected>Other</option>"
|
}, $.extend(nodes.flashTag, {
|
||||||
});
|
innerHTML: "<option value=\"0\">Hentai</option><option value=\"6\">Porn</option><option value=\"1\">Japanese</option><option value=\"2\">Anime</option><option value=\"3\">Game</option><option value=\"5\">Loop</option><option value=\"4\" selected>Other</option>"
|
||||||
|
}));
|
||||||
nodes.flashTag.dataset["default"] = '4';
|
nodes.flashTag.dataset["default"] = '4';
|
||||||
$.add(nodes.form, nodes.flashTag);
|
$.add(nodes.form, nodes.flashTag);
|
||||||
}
|
}
|
||||||
QR.flagsInput();
|
QR.flagsInput();
|
||||||
$.on(nodes.filename.parentNode, 'click keydown', QR.openFileInput);
|
$.on(nodes.filename.parentNode, 'click keydown', QR.openFileInput);
|
||||||
items = $$('*', QR.nodes.el);
|
|
||||||
i = 0;
|
|
||||||
while (elm = items[i++]) {
|
|
||||||
$.on(elm, 'blur', QR.focusout);
|
|
||||||
$.on(elm, 'focus', QR.focusin);
|
|
||||||
}
|
|
||||||
$.on(nodes.autohide, 'change', QR.toggleHide);
|
$.on(nodes.autohide, 'change', QR.toggleHide);
|
||||||
$.on(nodes.close, 'click', QR.close);
|
$.on(nodes.close, 'click', QR.close);
|
||||||
$.on(nodes.dumpButton, 'click', function() {
|
$.on(nodes.dumpButton, 'click', function() {
|
||||||
@ -9664,7 +9707,7 @@
|
|||||||
while (name = items[i++]) {
|
while (name = items[i++]) {
|
||||||
$.on(nodes[name], 'mouseover', QR.mouseover);
|
$.on(nodes[name], 'mouseover', QR.mouseover);
|
||||||
}
|
}
|
||||||
items = ['name', 'email', 'sub', 'com', 'filename', 'flag'];
|
items = ['thread', 'name', 'email', 'sub', 'com', 'filename', 'flag'];
|
||||||
i = 0;
|
i = 0;
|
||||||
save = function() {
|
save = function() {
|
||||||
return QR.selected.save(this);
|
return QR.selected.save(this);
|
||||||
@ -9734,25 +9777,18 @@
|
|||||||
return select;
|
return select;
|
||||||
},
|
},
|
||||||
flagsInput: function() {
|
flagsInput: function() {
|
||||||
var flag, nodes;
|
var nodes;
|
||||||
nodes = QR.nodes;
|
nodes = QR.nodes;
|
||||||
if (!nodes) {
|
if (!nodes) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (nodes.flag) {
|
if (nodes.flag) {
|
||||||
$.rm(nodes.flag);
|
$.rm(nodes.flag);
|
||||||
delete nodes.flag;
|
return delete nodes.flag;
|
||||||
}
|
|
||||||
if (g.BOARD.ID === 'pol') {
|
|
||||||
flag = QR.flags();
|
|
||||||
flag.dataset.name = 'flag';
|
|
||||||
flag.dataset["default"] = '0';
|
|
||||||
nodes.flag = flag;
|
|
||||||
return $.add(nodes.form, flag);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
submit: function(e) {
|
submit: function(e) {
|
||||||
var err, extra, filetag, formData, options, post, response, textOnly, thread, threadID;
|
var captcha, cb, err, extra, filetag, formData, options, post, textOnly, thread, threadID;
|
||||||
if (e != null) {
|
if (e != null) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
@ -9787,8 +9823,8 @@
|
|||||||
err = 'Max limit of image replies has been reached.';
|
err = 'Max limit of image replies has been reached.';
|
||||||
}
|
}
|
||||||
if (QR.captcha.isEnabled && !err) {
|
if (QR.captcha.isEnabled && !err) {
|
||||||
response = QR.captcha.getOne();
|
captcha = QR.captcha.getOne();
|
||||||
if (!response) {
|
if (!captcha) {
|
||||||
err = 'No valid captcha.';
|
err = 'No valid captcha.';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -9819,8 +9855,7 @@
|
|||||||
flag: post.flag,
|
flag: post.flag,
|
||||||
textonly: textOnly,
|
textonly: textOnly,
|
||||||
mode: 'regist',
|
mode: 'regist',
|
||||||
pwd: QR.persona.pwd,
|
pwd: QR.persona.pwd
|
||||||
'g-recaptcha-response': response
|
|
||||||
};
|
};
|
||||||
options = {
|
options = {
|
||||||
responseType: 'document',
|
responseType: 'document',
|
||||||
@ -9832,7 +9867,7 @@
|
|||||||
QR.cooldown.auto = false;
|
QR.cooldown.auto = false;
|
||||||
QR.status();
|
QR.status();
|
||||||
return QR.error($.el('span', {
|
return QR.error($.el('span', {
|
||||||
innerHTML: "Connection error. You may have been <a href=//www.4chan.org/banned target=_blank>banned</a>.\n[<a href=\"https://github.com/MayhemYDG/4chan-x/wiki/FAQ#what-does-connection-error-you-may-have-been-banned-mean\" target=_blank>?</a>]"
|
innerHTML: "4chan X encountered an error while posting. [<a href=\"//4chan.org/banned\" target=\"_blank\">Banned?</a>] [<a href=\"" + E(g.FAQ) + "#what-does-4chan-x-encountered-an-error-while-posting-please-try-again-mean\" target=\"_blank\">More info</a>]"
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -9851,9 +9886,33 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
QR.req = $.ajax("https://sys.4chan.org/" + g.BOARD + "/post", options, extra);
|
cb = function(response) {
|
||||||
QR.req.uploadStartTime = Date.now();
|
if (response != null) {
|
||||||
QR.req.progress = '...';
|
extra.form.append('g-recaptcha-response', response);
|
||||||
|
}
|
||||||
|
QR.req = $.ajax("https://sys.4chan.org/" + g.BOARD + "/post", options, extra);
|
||||||
|
return QR.req.progress = '...';
|
||||||
|
};
|
||||||
|
if (typeof captcha === 'function') {
|
||||||
|
QR.req = {
|
||||||
|
progress: '...',
|
||||||
|
abort: function() {
|
||||||
|
return cb = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
captcha(function(response) {
|
||||||
|
if (response) {
|
||||||
|
return typeof cb === "function" ? cb(response) : void 0;
|
||||||
|
} else {
|
||||||
|
delete QR.req;
|
||||||
|
post.unlock();
|
||||||
|
QR.cooldown.auto = !!QR.captcha.captchas.length;
|
||||||
|
return QR.status();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
cb(captcha);
|
||||||
|
}
|
||||||
return QR.status();
|
return QR.status();
|
||||||
},
|
},
|
||||||
response: function() {
|
response: function() {
|
||||||
@ -9865,8 +9924,10 @@
|
|||||||
resDoc = req.response;
|
resDoc = req.response;
|
||||||
if (ban = $('.banType', resDoc)) {
|
if (ban = $('.banType', resDoc)) {
|
||||||
board = $('.board', resDoc).innerHTML;
|
board = $('.board', resDoc).innerHTML;
|
||||||
err = $.el('span', {
|
err = $.el('span', ban.textContent.toLowerCase() === 'banned' ? {
|
||||||
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)
|
innerHTML: "You are banned on " + $(".board", resDoc).innerHTML + "! ;_;<br>Click <a href=\"//www.4chan.org/banned\" target=\"_blank\">here</a> to see the reason."
|
||||||
|
} : {
|
||||||
|
innerHTML: "You were issued a warning on " + $(".board", resDoc).innerHTML + " as " + $(".nameBlock", resDoc).innerHTML + ".<br>Reason: " + $(".reason", resDoc).innerHTML
|
||||||
});
|
});
|
||||||
} else if (err = resDoc.getElementById('errmsg')) {
|
} else if (err = resDoc.getElementById('errmsg')) {
|
||||||
if ((_ref = $('a', err)) != null) {
|
if ((_ref = $('a', err)) != null) {
|
||||||
@ -9885,14 +9946,11 @@
|
|||||||
err = 'This CAPTCHA is no longer valid because it has expired.';
|
err = 'This CAPTCHA is no longer valid because it has expired.';
|
||||||
}
|
}
|
||||||
QR.cooldown.auto = QR.captcha.isEnabled ? !!QR.captcha.captchas.length : err === 'Connection error with sys.4chan.org.' ? true : false;
|
QR.cooldown.auto = QR.captcha.isEnabled ? !!QR.captcha.captchas.length : err === 'Connection error with sys.4chan.org.' ? true : false;
|
||||||
QR.cooldown.set({
|
QR.cooldown.addDelay(post, 2);
|
||||||
delay: 2
|
} else if (err.textContent && (m = err.textContent.match(/wait\s+(\d+)\s+second/i)) && !/duplicate/i.test(err.textContent)) {
|
||||||
});
|
|
||||||
} else if (err.textContent && (m = err.textContent.match(/wait\s+(\d+)\s+second/i))) {
|
|
||||||
QR.cooldown.auto = QR.captcha.isEnabled ? !!QR.captcha.captchas.length : true;
|
QR.cooldown.auto = QR.captcha.isEnabled ? !!QR.captcha.captchas.length : true;
|
||||||
QR.cooldown.set({
|
QR.cooldown.addDelay(post, +m[1]);
|
||||||
delay: m[1]
|
QR.captcha.setup(d.activeElement === QR.nodes.status);
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
QR.cooldown.auto = false;
|
QR.cooldown.auto = false;
|
||||||
}
|
}
|
||||||
@ -9936,7 +9994,8 @@
|
|||||||
});
|
});
|
||||||
notif.onclick = function() {
|
notif.onclick = function() {
|
||||||
QR.open();
|
QR.open();
|
||||||
return window.focus();
|
window.focus();
|
||||||
|
return QR.captcha.setup(true);
|
||||||
};
|
};
|
||||||
notif.onshow = function() {
|
notif.onshow = function() {
|
||||||
return setTimeout(function() {
|
return setTimeout(function() {
|
||||||
@ -9944,21 +10003,16 @@
|
|||||||
}, 7 * $.SECOND);
|
}, 7 * $.SECOND);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (!(Conf['Persistent QR'] || QR.cooldown.auto)) {
|
if (!(Conf['Persistent QR'] || postsCount)) {
|
||||||
QR.close();
|
QR.close();
|
||||||
} else {
|
} else {
|
||||||
post.rm();
|
post.rm();
|
||||||
QR.captcha.setup(true);
|
QR.captcha.setup(d.activeElement === QR.nodes.status);
|
||||||
}
|
}
|
||||||
QR.cooldown.set({
|
QR.cooldown.add(req.uploadEndTime, threadID, postID);
|
||||||
req: req,
|
URL = threadID === postID ? window.location.origin + Build.path(g.BOARD.ID, threadID) : g.VIEW === 'index' && !QR.cooldown.auto && Conf['Open Post in New Tab'] ? window.location.origin + Build.path(g.BOARD.ID, threadID, postID) : void 0;
|
||||||
post: post,
|
|
||||||
isReply: isReply,
|
|
||||||
threadID: threadID
|
|
||||||
});
|
|
||||||
URL = threadID === postID ? Build.path(g.BOARD.ID, threadID) : g.VIEW === 'index' && !QR.cooldown.auto && Conf['Open Post in New Tab'] ? Build.path(g.BOARD.ID, threadID, postID) : void 0;
|
|
||||||
if (URL) {
|
if (URL) {
|
||||||
if (Conf['Open Post in New Tab']) {
|
if (Conf['Open Post in New Tab'] || postsCount) {
|
||||||
$.open(URL);
|
$.open(URL);
|
||||||
} else {
|
} else {
|
||||||
window.location = URL;
|
window.location = URL;
|
||||||
@ -9998,226 +10052,6 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
QR.captcha = {
|
|
||||||
init: function() {
|
|
||||||
var counter, root;
|
|
||||||
if (d.cookie.indexOf('pass_enabled=1') >= 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!(this.isEnabled = !!$.id('g-recaptcha'))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.captchas = [];
|
|
||||||
$.get('captchas', [], function(_arg) {
|
|
||||||
var captchas;
|
|
||||||
captchas = _arg.captchas;
|
|
||||||
return QR.captcha.sync(captchas);
|
|
||||||
});
|
|
||||||
$.sync('captchas', this.sync.bind(this));
|
|
||||||
root = $.el('div', {
|
|
||||||
className: 'captcha-root'
|
|
||||||
});
|
|
||||||
$.extend(root, {
|
|
||||||
innerHTML: "<div class=\"captcha-counter\"><a href=\"javascript:;\"></a></div>"
|
|
||||||
});
|
|
||||||
counter = $('.captcha-counter > a', root);
|
|
||||||
this.nodes = {
|
|
||||||
root: root,
|
|
||||||
counter: counter
|
|
||||||
};
|
|
||||||
this.count();
|
|
||||||
$.addClass(QR.nodes.el, 'has-captcha');
|
|
||||||
$.after(QR.nodes.com.parentNode, root);
|
|
||||||
$.on(counter, 'click', this.toggle.bind(this));
|
|
||||||
return $.on(window, 'captcha:success', (function(_this) {
|
|
||||||
return function() {
|
|
||||||
return $.queueTask(function() {
|
|
||||||
return _this.save(false);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
})(this));
|
|
||||||
},
|
|
||||||
shouldFocus: false,
|
|
||||||
timeouts: {},
|
|
||||||
postsCount: 0,
|
|
||||||
needed: function() {
|
|
||||||
var captchaCount;
|
|
||||||
captchaCount = this.captchas.length;
|
|
||||||
if (this.nodes.container && !this.timeouts.destroy) {
|
|
||||||
captchaCount++;
|
|
||||||
}
|
|
||||||
this.postsCount = QR.posts.length;
|
|
||||||
if (this.postsCount === 1 && !Conf['Auto-load captcha'] && !QR.posts[0].com && !QR.posts[0].file) {
|
|
||||||
this.postsCount = 0;
|
|
||||||
}
|
|
||||||
return captchaCount < this.postsCount;
|
|
||||||
},
|
|
||||||
onPostChange: function() {
|
|
||||||
if (this.postsCount === 0) {
|
|
||||||
this.setup();
|
|
||||||
}
|
|
||||||
if (QR.posts.length === 1 && !Conf['Auto-load captcha'] && !QR.posts[0].com && !QR.posts[0].file) {
|
|
||||||
return this.postsCount = 0;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
toggle: function() {
|
|
||||||
if (this.nodes.container && !this.timeouts.destroy) {
|
|
||||||
return this.destroy();
|
|
||||||
} else {
|
|
||||||
return this.setup(true, true);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setup: function(focus, force) {
|
|
||||||
if (!(this.isEnabled && (this.needed() || force))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$.addClass(QR.nodes.el, 'captcha-open');
|
|
||||||
if (focus) {
|
|
||||||
this.shouldFocus = true;
|
|
||||||
}
|
|
||||||
if (this.timeouts.destroy) {
|
|
||||||
clearTimeout(this.timeouts.destroy);
|
|
||||||
delete this.timeouts.destroy;
|
|
||||||
return this.reload();
|
|
||||||
}
|
|
||||||
if (this.nodes.container) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.nodes.container = $.el('div', {
|
|
||||||
className: 'captcha-container'
|
|
||||||
});
|
|
||||||
$.prepend(this.nodes.root, this.nodes.container);
|
|
||||||
new MutationObserver(this.afterSetup.bind(this)).observe(this.nodes.container, {
|
|
||||||
childList: true,
|
|
||||||
subtree: true
|
|
||||||
});
|
|
||||||
return $.globalEval('(function() {\n function render() {\n var container = document.querySelector("#qr .captcha-container");\n container.dataset.widgetID = window.grecaptcha.render(container, {\n sitekey: \'6Ldp2bsSAAAAAAJ5uyx_lx34lJeEpTLVkP5k04qc\',\n theme: document.documentElement.classList.contains(\'tomorrow\') ? \'dark\' : \'light\',\n callback: function(response) {\n window.dispatchEvent(new CustomEvent("captcha:success", {detail: response}));\n }\n });\n }\n if (window.grecaptcha) {\n render();\n } else {\n var cbNative = window.onRecaptchaLoaded;\n window.onRecaptchaLoaded = function() {\n render();\n cbNative();\n }\n }\n})();');
|
|
||||||
},
|
|
||||||
afterSetup: function(mutations) {
|
|
||||||
var iframe, mutation, node, textarea, _i, _j, _len, _len1, _ref;
|
|
||||||
for (_i = 0, _len = mutations.length; _i < _len; _i++) {
|
|
||||||
mutation = mutations[_i];
|
|
||||||
_ref = mutation.addedNodes;
|
|
||||||
for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
|
|
||||||
node = _ref[_j];
|
|
||||||
if (iframe = $.x('./descendant-or-self::iframe', node)) {
|
|
||||||
this.setupIFrame(iframe);
|
|
||||||
}
|
|
||||||
if (textarea = $.x('./descendant-or-self::textarea', node)) {
|
|
||||||
this.setupTextArea(textarea);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setupIFrame: function(iframe) {
|
|
||||||
this.setupTime = Date.now();
|
|
||||||
if (QR.nodes.el.getBoundingClientRect().bottom > doc.clientHeight) {
|
|
||||||
QR.nodes.el.style.top = null;
|
|
||||||
QR.nodes.el.style.bottom = '0px';
|
|
||||||
}
|
|
||||||
if (this.shouldFocus) {
|
|
||||||
iframe.focus();
|
|
||||||
}
|
|
||||||
return this.shouldFocus = false;
|
|
||||||
},
|
|
||||||
setupTextArea: function(textarea) {
|
|
||||||
return $.one(textarea, 'input', (function(_this) {
|
|
||||||
return function() {
|
|
||||||
return _this.save(true);
|
|
||||||
};
|
|
||||||
})(this));
|
|
||||||
},
|
|
||||||
destroy: function() {
|
|
||||||
if (!this.isEnabled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
delete this.timeouts.destroy;
|
|
||||||
$.rmClass(QR.nodes.el, 'captcha-open');
|
|
||||||
if (this.nodes.container) {
|
|
||||||
$.rm(this.nodes.container);
|
|
||||||
}
|
|
||||||
return delete this.nodes.container;
|
|
||||||
},
|
|
||||||
sync: function(captchas) {
|
|
||||||
if (captchas == null) {
|
|
||||||
captchas = [];
|
|
||||||
}
|
|
||||||
this.captchas = captchas;
|
|
||||||
this.clear();
|
|
||||||
return this.count();
|
|
||||||
},
|
|
||||||
getOne: function() {
|
|
||||||
var captcha;
|
|
||||||
this.clear();
|
|
||||||
if (captcha = this.captchas.shift()) {
|
|
||||||
this.count();
|
|
||||||
$.set('captchas', this.captchas);
|
|
||||||
return captcha.response;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
save: function(pasted) {
|
|
||||||
var reload, _base;
|
|
||||||
$.forceSync('captchas');
|
|
||||||
reload = (QR.cooldown.auto || Conf['Post on Captcha Completion']) && this.needed();
|
|
||||||
this.captchas.push({
|
|
||||||
response: $('textarea', this.nodes.container).value,
|
|
||||||
timeout: (pasted ? this.setupTime : Date.now()) + 2 * $.MINUTE
|
|
||||||
});
|
|
||||||
this.count();
|
|
||||||
$.set('captchas', this.captchas);
|
|
||||||
if (reload) {
|
|
||||||
this.shouldFocus = true;
|
|
||||||
this.reload();
|
|
||||||
} else {
|
|
||||||
if (pasted) {
|
|
||||||
this.destroy();
|
|
||||||
} else {
|
|
||||||
if ((_base = this.timeouts).destroy == null) {
|
|
||||||
_base.destroy = setTimeout(this.destroy.bind(this), 3 * $.SECOND);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
QR.nodes.status.focus();
|
|
||||||
}
|
|
||||||
if (Conf['Post on Captcha Completion'] && !QR.cooldown.auto) {
|
|
||||||
return QR.submit();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
clear: function() {
|
|
||||||
var captcha, i, now, _i, _len, _ref;
|
|
||||||
if (!this.captchas.length) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$.forceSync('captchas');
|
|
||||||
now = Date.now();
|
|
||||||
_ref = this.captchas;
|
|
||||||
for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
|
|
||||||
captcha = _ref[i];
|
|
||||||
if (captcha.timeout > now) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!i) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.captchas = this.captchas.slice(i);
|
|
||||||
this.count();
|
|
||||||
$.set('captchas', this.captchas);
|
|
||||||
return this.setup(true);
|
|
||||||
},
|
|
||||||
count: function() {
|
|
||||||
this.nodes.counter.textContent = "Captchas: " + this.captchas.length;
|
|
||||||
clearTimeout(this.timeouts.clear);
|
|
||||||
if (this.captchas.length) {
|
|
||||||
return this.timeouts.clear = setTimeout(this.clear.bind(this), this.captchas[0].timeout - Date.now());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
reload: function(focus) {
|
|
||||||
return $.globalEval('(function() {\n var container = document.querySelector("#qr .captcha-container");\n window.grecaptcha.reset(container.dataset.widgetID);\n})();');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
QR.cooldown = {
|
QR.cooldown = {
|
||||||
init: function() {
|
init: function() {
|
||||||
var key, setTimers, type;
|
var key, setTimers, type;
|
||||||
@ -18351,7 +18185,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
updateContext: function(view) {
|
updateContext: function(view) {
|
||||||
g.DEAD = false;
|
|
||||||
if (view === 'thread') {
|
if (view === 'thread') {
|
||||||
g.THREADID = +window.location.pathname.split('/')[3];
|
g.THREADID = +window.location.pathname.split('/')[3];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9146,10 +9146,19 @@
|
|||||||
QR = {
|
QR = {
|
||||||
mimeTypes: ['image/jpeg', 'image/png', 'image/gif', 'application/pdf', 'application/vnd.adobe.flash.movie', 'application/x-shockwave-flash', 'video/webm'],
|
mimeTypes: ['image/jpeg', 'image/png', 'image/gif', 'application/pdf', 'application/vnd.adobe.flash.movie', 'application/x-shockwave-flash', 'video/webm'],
|
||||||
init: function() {
|
init: function() {
|
||||||
var con, sc;
|
var con, noscript, sc;
|
||||||
this.db = new DataBoard('yourPosts');
|
this.db = new DataBoard('yourPosts');
|
||||||
this.posts = [];
|
this.posts = [];
|
||||||
|
if (g.VIEW === 'archive') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$.globalEval('document.documentElement.dataset.jsEnabled = true;');
|
||||||
|
noscript = Conf['Force Noscript Captcha'] || !doc.dataset.jsEnabled;
|
||||||
|
this.captcha = Captcha[noscript ? 'noscript' : 'v2'];
|
||||||
$.on(d, '4chanXInitFinished', this.initReady);
|
$.on(d, '4chanXInitFinished', this.initReady);
|
||||||
|
window.addEventListener('focus', this.focus, true);
|
||||||
|
window.addEventListener('blur', this.focus, true);
|
||||||
|
$.on(d, 'click', this.focus);
|
||||||
Post.callbacks.push({
|
Post.callbacks.push({
|
||||||
name: 'Quick Reply',
|
name: 'Quick Reply',
|
||||||
cb: this.node
|
cb: this.node
|
||||||
@ -9209,12 +9218,17 @@
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QR.open();
|
QR.open();
|
||||||
if (Conf['Auto-Hide QR']) {
|
if (Conf['Auto Hide QR']) {
|
||||||
return QR.hide();
|
return QR.hide();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
statusCheck: function() {
|
statusCheck: function() {
|
||||||
if (g.DEAD) {
|
var thread;
|
||||||
|
if (!QR.nodes) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
thread = QR.posts[0].thread;
|
||||||
|
if (thread !== 'new' && g.threads["" + g.BOARD + "." + thread].isDead) {
|
||||||
return QR.abort();
|
return QR.abort();
|
||||||
} else {
|
} else {
|
||||||
return QR.status();
|
return QR.status();
|
||||||
@ -9242,9 +9256,11 @@
|
|||||||
open: function() {
|
open: function() {
|
||||||
var err;
|
var err;
|
||||||
if (QR.nodes) {
|
if (QR.nodes) {
|
||||||
|
if (QR.nodes.el.hidden) {
|
||||||
|
QR.captcha.setup();
|
||||||
|
}
|
||||||
QR.nodes.el.hidden = false;
|
QR.nodes.el.hidden = false;
|
||||||
QR.unhide();
|
QR.unhide();
|
||||||
QR.captcha.setup();
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@ -9281,14 +9297,34 @@
|
|||||||
QR.status();
|
QR.status();
|
||||||
return QR.captcha.destroy();
|
return QR.captcha.destroy();
|
||||||
},
|
},
|
||||||
focusin: function() {
|
focus: function() {
|
||||||
if ($.hasClass(QR.nodes.el, 'autohide') && !$.hasClass(QR.nodes.el, 'focus')) {
|
return $.queueTask(function() {
|
||||||
QR.captcha.setup();
|
var focus;
|
||||||
}
|
if (!QR.nodes) {
|
||||||
return $.addClass(QR.nodes.el, 'focus');
|
return;
|
||||||
|
}
|
||||||
|
if (!$$('.goog-bubble-content > iframe').some(function(el) {
|
||||||
|
return el.getBoundingClientRect().top >= 0;
|
||||||
|
})) {
|
||||||
|
focus = d.activeElement && QR.nodes.el.contains(d.activeElement);
|
||||||
|
$[focus ? 'addClass' : 'rmClass'](QR.nodes.el, 'focus');
|
||||||
|
}
|
||||||
|
if (typeof chrome !== "undefined" && chrome !== null) {
|
||||||
|
if (d.activeElement && QR.nodes.el.contains(d.activeElement) && d.activeElement.nodeName === 'IFRAME') {
|
||||||
|
QR.scrollY = window.scrollY;
|
||||||
|
return $.on(d, 'scroll', QR.scrollLock);
|
||||||
|
} else {
|
||||||
|
return $.off(d, 'scroll', QR.scrollLock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
focusout: function() {
|
scrollLock: function(e) {
|
||||||
return $.rmClass(QR.nodes.el, 'focus');
|
if (d.activeElement && QR.nodes.el.contains(d.activeElement) && d.activeElement.nodeName === 'IFRAME') {
|
||||||
|
return window.scroll(window.scrollX, QR.scrollY);
|
||||||
|
} else {
|
||||||
|
return $.off(d, 'scroll', QR.scrollLock);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
hide: function() {
|
hide: function() {
|
||||||
d.activeElement.blur();
|
d.activeElement.blur();
|
||||||
@ -9317,8 +9353,10 @@
|
|||||||
}
|
}
|
||||||
if (QR.captcha.isEnabled && /captcha|verification/i.test(el.textContent)) {
|
if (QR.captcha.isEnabled && /captcha|verification/i.test(el.textContent)) {
|
||||||
QR.captcha.setup(true);
|
QR.captcha.setup(true);
|
||||||
|
QR.captcha.notify(el);
|
||||||
|
} else {
|
||||||
|
QR.notify(el);
|
||||||
}
|
}
|
||||||
QR.notify(el);
|
|
||||||
if (d.hidden) {
|
if (d.hidden) {
|
||||||
return alert(el.textContent);
|
return alert(el.textContent);
|
||||||
}
|
}
|
||||||
@ -9383,7 +9421,7 @@
|
|||||||
}
|
}
|
||||||
sel = d.getSelection();
|
sel = d.getSelection();
|
||||||
post = Get.postFromNode(this);
|
post = Get.postFromNode(this);
|
||||||
text = ">>" + post + "\n";
|
text = post.board.ID === g.BOARD.ID ? ">>" + post + "\n" : ">>>/" + post.board + "/" + post + "\n";
|
||||||
if (sel.toString().trim() && post === Get.postFromNode(sel.anchorNode)) {
|
if (sel.toString().trim() && post === Get.postFromNode(sel.anchorNode)) {
|
||||||
range = sel.getRangeAt(0);
|
range = sel.getRangeAt(0);
|
||||||
frag = range.cloneContents();
|
frag = range.cloneContents();
|
||||||
@ -9612,16 +9650,17 @@
|
|||||||
}
|
}
|
||||||
list.value = g.VIEW === 'thread' ? g.THREADID : 'new';
|
list.value = g.VIEW === 'thread' ? g.THREADID : 'new';
|
||||||
if ($.hasClass(list, 'riced')) {
|
if ($.hasClass(list, 'riced')) {
|
||||||
return list.nextElementSibling.firstChild.textContent = list.options[list.selectedIndex].textContent;
|
list.nextElementSibling.firstChild.textContent = list.options[list.selectedIndex].textContent;
|
||||||
}
|
}
|
||||||
|
return (g.VIEW === 'thread' ? $.addClass : $.rmClass)(QR.nodes.el, 'reply-to-thread');
|
||||||
},
|
},
|
||||||
dialog: function() {
|
dialog: function() {
|
||||||
var dialog, elm, event, i, items, match_max, match_min, name, node, nodes, rules, save, setNode;
|
var dialog, event, i, items, match_max, match_min, name, node, nodes, rules, save, setNode;
|
||||||
QR.nodes = nodes = {
|
QR.nodes = nodes = {
|
||||||
el: dialog = UI.dialog('qr', 'top:0;right:0;')
|
el: dialog = UI.dialog('qr', 'top:0;right:0;')
|
||||||
};
|
};
|
||||||
$.extend(dialog, {
|
$.extend(dialog, {
|
||||||
innerHTML: "<div id=qrtab class=move>\r<input type=checkbox id=autohide title=Auto-hide>\r<div id=qr-thread-select>\r<select data-name=thread title='Create a new thread / Reply'>\r<option value=new>New thread</option>\r</select>\r</div>\r<a href=javascript:; class='close fa' title=Close>\\uf00d</a>\r</div>\r<form>\r<div class=persona>\r<input name=name data-name=name list=\"list-name\" placeholder=Name class=field size=1>\r<input name=email data-name=email list=\"list-email\" placeholder=Options class=field size=1>\r<input name=sub data-name=sub list=\"list-sub\" placeholder=Subject class=field size=1> \r</div>\r<div class=textarea>\r<textarea data-name=com placeholder=Comment class=field></textarea>\r<span id=char-count></span>\r</div>\r<div id=dump-list-container>\r<div id=dump-list></div>\r<a id=add-post href=javascript:; title=\"Add a post\">+</a>\r</div>\r<div id=file-n-submit>\r<span id=qr-filename-container class=field tabindex=0>\r<span id=qr-no-file>No selected file</span>\r<input id=\"qr-filename\" data-name=\"filename\" spellcheck=\"false\">\r<span id=qr-extras-container>\r<label id=qr-spoiler-label>\r<input type=checkbox id=qr-file-spoiler title='Spoiler image'>\r</label>\r<span class=description>Spoiler</span>\r<a id=url-button><i class=\"fa\">\\uf0c1</i></a>\r<span class=description>Post from URL</span>\r<a id=dump-button title='Dump list'>+</a>\r<span class=description>Dump</span>\r<a id=qr-filerm href=javascript:; title='Remove file' class=fa>\\uf00d</a>\r<span class=description>Remove File</span>\r</span>\r</span>\r<input type=submit>\r</div>\r<input type=file multiple>\r</form>\r<datalist id=\"list-name\"></datalist>\r<datalist id=\"list-email\"></datalist>\r<datalist id=\"list-sub\"></datalist>\r"
|
innerHTML: "<div id=qrtab class=move>\r<input type=checkbox id=autohide title=Auto-hide>\r<div id=qr-thread-select>\r<select data-name=thread title='Create a new thread / Reply'>\r<option value=new>New thread</option>\r</select>\r</div>\r<a href=javascript:; class='close fa' title=Close>\\uf00d</a>\r</div>\r<form>\r<div class=persona>\r<input name=name data-name=name list=\"list-name\" placeholder=Name class=field size=1>\r<input name=email data-name=email list=\"list-email\" placeholder=Options class=field size=1>\r<input name=sub data-name=sub list=\"list-sub\" placeholder=Subject class=field size=1> \r</div>\r<div class=textarea>\r<textarea data-name=com placeholder=Comment class=field></textarea>\r<span id=char-count></span>\r</div>\r<div id=dump-list-container>\r<div id=dump-list></div>\r<a id=add-post href=javascript:; title=\"Add a post\">+</a>\r</div>\r<div id=file-n-submit>\r<span id=qr-filename-container class=field tabindex=0>\r<span id=qr-no-file>No selected file</span>\r<input id=\"qr-filename\" data-name=\"filename\" spellcheck=\"false\">\r<span id=qr-extras-container>\r<label id=qr-spoiler-label>\r<input type=checkbox id=qr-file-spoiler title='Spoiler image'>\r</label>\r<span class=description>Spoiler</span>\r<a id=url-button><i class=\"fa\">\\uf0c1</i></a>\r<span class=description>Post from URL</span>\r<a id=dump-button title='Dump list'>+</a>\r<span class=description>Dump</span>\r<a id=qr-filerm href=javascript:; title='Remove file' class=fa>\\uf00d</a>\r<span class=description>Remove File</span>\r</span>\r</span>\r<input type=submit>\r</div>\r<input type=file multiple>\r</form>\r<datalist id=\"list-name\"></datalist>\r<datalist id=\"list-email\"></datalist>\r<datalist id=\"list-sub\"></datalist>\r"
|
||||||
});
|
});
|
||||||
setNode = function(name, query) {
|
setNode = function(name, query) {
|
||||||
return nodes[name] = $(query, dialog);
|
return nodes[name] = $(query, dialog);
|
||||||
@ -9661,6 +9700,14 @@
|
|||||||
QR.max_size_video = 3145728;
|
QR.max_size_video = 3145728;
|
||||||
QR.max_width_video = QR.max_height_video = 2048;
|
QR.max_width_video = QR.max_height_video = 2048;
|
||||||
QR.max_duration_video = 120;
|
QR.max_duration_video = 120;
|
||||||
|
if (Conf['Show New Thread Option in Threads']) {
|
||||||
|
$.addClass(QR.nodes.el, 'show-new-thread-option');
|
||||||
|
}
|
||||||
|
if (Conf['Show Name and Subject']) {
|
||||||
|
$.addClass(QR.nodes.name, 'force-show');
|
||||||
|
$.addClass(QR.nodes.sub, 'force-show');
|
||||||
|
QR.nodes.email.placeholder = 'E-mail';
|
||||||
|
}
|
||||||
QR.forcedAnon = !!$('form[name="post"] input[name="name"][type="hidden"]');
|
QR.forcedAnon = !!$('form[name="post"] input[name="name"][type="hidden"]');
|
||||||
if (QR.forcedAnon) {
|
if (QR.forcedAnon) {
|
||||||
$.addClass(QR.nodes.el, 'forced-anon');
|
$.addClass(QR.nodes.el, 'forced-anon');
|
||||||
@ -9677,20 +9724,15 @@
|
|||||||
}
|
}
|
||||||
if (g.BOARD.ID === 'f' && g.VIEW !== 'thread') {
|
if (g.BOARD.ID === 'f' && g.VIEW !== 'thread') {
|
||||||
nodes.flashTag = $.el('select', {
|
nodes.flashTag = $.el('select', {
|
||||||
name: 'filetag',
|
name: 'filetag'
|
||||||
innerHTML: "<option value=0>Hentai</option>\n<option value=6>Porn</option>\n<option value=1>Japanese</option>\n<option value=2>Anime</option>\n<option value=3>Game</option>\n<option value=5>Loop</option>\n<option value=4 selected>Other</option>"
|
}, $.extend(nodes.flashTag, {
|
||||||
});
|
innerHTML: "<option value=\"0\">Hentai</option><option value=\"6\">Porn</option><option value=\"1\">Japanese</option><option value=\"2\">Anime</option><option value=\"3\">Game</option><option value=\"5\">Loop</option><option value=\"4\" selected>Other</option>"
|
||||||
|
}));
|
||||||
nodes.flashTag.dataset["default"] = '4';
|
nodes.flashTag.dataset["default"] = '4';
|
||||||
$.add(nodes.form, nodes.flashTag);
|
$.add(nodes.form, nodes.flashTag);
|
||||||
}
|
}
|
||||||
QR.flagsInput();
|
QR.flagsInput();
|
||||||
$.on(nodes.filename.parentNode, 'click keydown', QR.openFileInput);
|
$.on(nodes.filename.parentNode, 'click keydown', QR.openFileInput);
|
||||||
items = $$('*', QR.nodes.el);
|
|
||||||
i = 0;
|
|
||||||
while (elm = items[i++]) {
|
|
||||||
$.on(elm, 'blur', QR.focusout);
|
|
||||||
$.on(elm, 'focus', QR.focusin);
|
|
||||||
}
|
|
||||||
$.on(nodes.autohide, 'change', QR.toggleHide);
|
$.on(nodes.autohide, 'change', QR.toggleHide);
|
||||||
$.on(nodes.close, 'click', QR.close);
|
$.on(nodes.close, 'click', QR.close);
|
||||||
$.on(nodes.dumpButton, 'click', function() {
|
$.on(nodes.dumpButton, 'click', function() {
|
||||||
@ -9719,7 +9761,7 @@
|
|||||||
while (name = items[i++]) {
|
while (name = items[i++]) {
|
||||||
$.on(nodes[name], 'mouseover', QR.mouseover);
|
$.on(nodes[name], 'mouseover', QR.mouseover);
|
||||||
}
|
}
|
||||||
items = ['name', 'email', 'sub', 'com', 'filename', 'flag'];
|
items = ['thread', 'name', 'email', 'sub', 'com', 'filename', 'flag'];
|
||||||
i = 0;
|
i = 0;
|
||||||
save = function() {
|
save = function() {
|
||||||
return QR.selected.save(this);
|
return QR.selected.save(this);
|
||||||
@ -9778,25 +9820,18 @@
|
|||||||
return select;
|
return select;
|
||||||
},
|
},
|
||||||
flagsInput: function() {
|
flagsInput: function() {
|
||||||
var flag, nodes;
|
var nodes;
|
||||||
nodes = QR.nodes;
|
nodes = QR.nodes;
|
||||||
if (!nodes) {
|
if (!nodes) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (nodes.flag) {
|
if (nodes.flag) {
|
||||||
$.rm(nodes.flag);
|
$.rm(nodes.flag);
|
||||||
delete nodes.flag;
|
return delete nodes.flag;
|
||||||
}
|
|
||||||
if (g.BOARD.ID === 'pol') {
|
|
||||||
flag = QR.flags();
|
|
||||||
flag.dataset.name = 'flag';
|
|
||||||
flag.dataset["default"] = '0';
|
|
||||||
nodes.flag = flag;
|
|
||||||
return $.add(nodes.form, flag);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
submit: function(e) {
|
submit: function(e) {
|
||||||
var err, extra, filetag, formData, options, post, response, textOnly, thread, threadID;
|
var captcha, cb, err, extra, filetag, formData, options, post, textOnly, thread, threadID;
|
||||||
if (e != null) {
|
if (e != null) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
@ -9831,8 +9866,8 @@
|
|||||||
err = 'Max limit of image replies has been reached.';
|
err = 'Max limit of image replies has been reached.';
|
||||||
}
|
}
|
||||||
if (QR.captcha.isEnabled && !err) {
|
if (QR.captcha.isEnabled && !err) {
|
||||||
response = QR.captcha.getOne();
|
captcha = QR.captcha.getOne();
|
||||||
if (!response) {
|
if (!captcha) {
|
||||||
err = 'No valid captcha.';
|
err = 'No valid captcha.';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -9863,8 +9898,7 @@
|
|||||||
flag: post.flag,
|
flag: post.flag,
|
||||||
textonly: textOnly,
|
textonly: textOnly,
|
||||||
mode: 'regist',
|
mode: 'regist',
|
||||||
pwd: QR.persona.pwd,
|
pwd: QR.persona.pwd
|
||||||
'g-recaptcha-response': response
|
|
||||||
};
|
};
|
||||||
options = {
|
options = {
|
||||||
responseType: 'document',
|
responseType: 'document',
|
||||||
@ -9876,7 +9910,7 @@
|
|||||||
QR.cooldown.auto = false;
|
QR.cooldown.auto = false;
|
||||||
QR.status();
|
QR.status();
|
||||||
return QR.error($.el('span', {
|
return QR.error($.el('span', {
|
||||||
innerHTML: "Connection error. You may have been <a href=//www.4chan.org/banned target=_blank>banned</a>.\n[<a href=\"https://github.com/MayhemYDG/4chan-x/wiki/FAQ#what-does-connection-error-you-may-have-been-banned-mean\" target=_blank>?</a>]"
|
innerHTML: "4chan X encountered an error while posting. [<a href=\"//4chan.org/banned\" target=\"_blank\">Banned?</a>] [<a href=\"" + E(g.FAQ) + "#what-does-4chan-x-encountered-an-error-while-posting-please-try-again-mean\" target=\"_blank\">More info</a>]"
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -9895,9 +9929,33 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
QR.req = $.ajax("https://sys.4chan.org/" + g.BOARD + "/post", options, extra);
|
cb = function(response) {
|
||||||
QR.req.uploadStartTime = Date.now();
|
if (response != null) {
|
||||||
QR.req.progress = '...';
|
extra.form.append('g-recaptcha-response', response);
|
||||||
|
}
|
||||||
|
QR.req = $.ajax("https://sys.4chan.org/" + g.BOARD + "/post", options, extra);
|
||||||
|
return QR.req.progress = '...';
|
||||||
|
};
|
||||||
|
if (typeof captcha === 'function') {
|
||||||
|
QR.req = {
|
||||||
|
progress: '...',
|
||||||
|
abort: function() {
|
||||||
|
return cb = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
captcha(function(response) {
|
||||||
|
if (response) {
|
||||||
|
return typeof cb === "function" ? cb(response) : void 0;
|
||||||
|
} else {
|
||||||
|
delete QR.req;
|
||||||
|
post.unlock();
|
||||||
|
QR.cooldown.auto = !!QR.captcha.captchas.length;
|
||||||
|
return QR.status();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
cb(captcha);
|
||||||
|
}
|
||||||
return QR.status();
|
return QR.status();
|
||||||
},
|
},
|
||||||
response: function() {
|
response: function() {
|
||||||
@ -9909,8 +9967,10 @@
|
|||||||
resDoc = req.response;
|
resDoc = req.response;
|
||||||
if (ban = $('.banType', resDoc)) {
|
if (ban = $('.banType', resDoc)) {
|
||||||
board = $('.board', resDoc).innerHTML;
|
board = $('.board', resDoc).innerHTML;
|
||||||
err = $.el('span', {
|
err = $.el('span', ban.textContent.toLowerCase() === 'banned' ? {
|
||||||
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)
|
innerHTML: "You are banned on " + $(".board", resDoc).innerHTML + "! ;_;<br>Click <a href=\"//www.4chan.org/banned\" target=\"_blank\">here</a> to see the reason."
|
||||||
|
} : {
|
||||||
|
innerHTML: "You were issued a warning on " + $(".board", resDoc).innerHTML + " as " + $(".nameBlock", resDoc).innerHTML + ".<br>Reason: " + $(".reason", resDoc).innerHTML
|
||||||
});
|
});
|
||||||
} else if (err = resDoc.getElementById('errmsg')) {
|
} else if (err = resDoc.getElementById('errmsg')) {
|
||||||
if ((_ref = $('a', err)) != null) {
|
if ((_ref = $('a', err)) != null) {
|
||||||
@ -9929,14 +9989,11 @@
|
|||||||
err = 'This CAPTCHA is no longer valid because it has expired.';
|
err = 'This CAPTCHA is no longer valid because it has expired.';
|
||||||
}
|
}
|
||||||
QR.cooldown.auto = QR.captcha.isEnabled ? !!QR.captcha.captchas.length : err === 'Connection error with sys.4chan.org.' ? true : false;
|
QR.cooldown.auto = QR.captcha.isEnabled ? !!QR.captcha.captchas.length : err === 'Connection error with sys.4chan.org.' ? true : false;
|
||||||
QR.cooldown.set({
|
QR.cooldown.addDelay(post, 2);
|
||||||
delay: 2
|
} else if (err.textContent && (m = err.textContent.match(/wait\s+(\d+)\s+second/i)) && !/duplicate/i.test(err.textContent)) {
|
||||||
});
|
|
||||||
} else if (err.textContent && (m = err.textContent.match(/wait\s+(\d+)\s+second/i))) {
|
|
||||||
QR.cooldown.auto = QR.captcha.isEnabled ? !!QR.captcha.captchas.length : true;
|
QR.cooldown.auto = QR.captcha.isEnabled ? !!QR.captcha.captchas.length : true;
|
||||||
QR.cooldown.set({
|
QR.cooldown.addDelay(post, +m[1]);
|
||||||
delay: m[1]
|
QR.captcha.setup(d.activeElement === QR.nodes.status);
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
QR.cooldown.auto = false;
|
QR.cooldown.auto = false;
|
||||||
}
|
}
|
||||||
@ -9980,7 +10037,8 @@
|
|||||||
});
|
});
|
||||||
notif.onclick = function() {
|
notif.onclick = function() {
|
||||||
QR.open();
|
QR.open();
|
||||||
return window.focus();
|
window.focus();
|
||||||
|
return QR.captcha.setup(true);
|
||||||
};
|
};
|
||||||
notif.onshow = function() {
|
notif.onshow = function() {
|
||||||
return setTimeout(function() {
|
return setTimeout(function() {
|
||||||
@ -9988,21 +10046,16 @@
|
|||||||
}, 7 * $.SECOND);
|
}, 7 * $.SECOND);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (!(Conf['Persistent QR'] || QR.cooldown.auto)) {
|
if (!(Conf['Persistent QR'] || postsCount)) {
|
||||||
QR.close();
|
QR.close();
|
||||||
} else {
|
} else {
|
||||||
post.rm();
|
post.rm();
|
||||||
QR.captcha.setup(true);
|
QR.captcha.setup(d.activeElement === QR.nodes.status);
|
||||||
}
|
}
|
||||||
QR.cooldown.set({
|
QR.cooldown.add(req.uploadEndTime, threadID, postID);
|
||||||
req: req,
|
URL = threadID === postID ? window.location.origin + Build.path(g.BOARD.ID, threadID) : g.VIEW === 'index' && !QR.cooldown.auto && Conf['Open Post in New Tab'] ? window.location.origin + Build.path(g.BOARD.ID, threadID, postID) : void 0;
|
||||||
post: post,
|
|
||||||
isReply: isReply,
|
|
||||||
threadID: threadID
|
|
||||||
});
|
|
||||||
URL = threadID === postID ? Build.path(g.BOARD.ID, threadID) : g.VIEW === 'index' && !QR.cooldown.auto && Conf['Open Post in New Tab'] ? Build.path(g.BOARD.ID, threadID, postID) : void 0;
|
|
||||||
if (URL) {
|
if (URL) {
|
||||||
if (Conf['Open Post in New Tab']) {
|
if (Conf['Open Post in New Tab'] || postsCount) {
|
||||||
$.open(URL);
|
$.open(URL);
|
||||||
} else {
|
} else {
|
||||||
window.location = URL;
|
window.location = URL;
|
||||||
@ -10042,226 +10095,6 @@
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
QR.captcha = {
|
|
||||||
init: function() {
|
|
||||||
var counter, root;
|
|
||||||
if (d.cookie.indexOf('pass_enabled=1') >= 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!(this.isEnabled = !!$.id('g-recaptcha'))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.captchas = [];
|
|
||||||
$.get('captchas', [], function(_arg) {
|
|
||||||
var captchas;
|
|
||||||
captchas = _arg.captchas;
|
|
||||||
return QR.captcha.sync(captchas);
|
|
||||||
});
|
|
||||||
$.sync('captchas', this.sync.bind(this));
|
|
||||||
root = $.el('div', {
|
|
||||||
className: 'captcha-root'
|
|
||||||
});
|
|
||||||
$.extend(root, {
|
|
||||||
innerHTML: "<div class=\"captcha-counter\"><a href=\"javascript:;\"></a></div>"
|
|
||||||
});
|
|
||||||
counter = $('.captcha-counter > a', root);
|
|
||||||
this.nodes = {
|
|
||||||
root: root,
|
|
||||||
counter: counter
|
|
||||||
};
|
|
||||||
this.count();
|
|
||||||
$.addClass(QR.nodes.el, 'has-captcha');
|
|
||||||
$.after(QR.nodes.com.parentNode, root);
|
|
||||||
$.on(counter, 'click', this.toggle.bind(this));
|
|
||||||
return $.on(window, 'captcha:success', (function(_this) {
|
|
||||||
return function() {
|
|
||||||
return $.queueTask(function() {
|
|
||||||
return _this.save(false);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
})(this));
|
|
||||||
},
|
|
||||||
shouldFocus: false,
|
|
||||||
timeouts: {},
|
|
||||||
postsCount: 0,
|
|
||||||
needed: function() {
|
|
||||||
var captchaCount;
|
|
||||||
captchaCount = this.captchas.length;
|
|
||||||
if (this.nodes.container && !this.timeouts.destroy) {
|
|
||||||
captchaCount++;
|
|
||||||
}
|
|
||||||
this.postsCount = QR.posts.length;
|
|
||||||
if (this.postsCount === 1 && !Conf['Auto-load captcha'] && !QR.posts[0].com && !QR.posts[0].file) {
|
|
||||||
this.postsCount = 0;
|
|
||||||
}
|
|
||||||
return captchaCount < this.postsCount;
|
|
||||||
},
|
|
||||||
onPostChange: function() {
|
|
||||||
if (this.postsCount === 0) {
|
|
||||||
this.setup();
|
|
||||||
}
|
|
||||||
if (QR.posts.length === 1 && !Conf['Auto-load captcha'] && !QR.posts[0].com && !QR.posts[0].file) {
|
|
||||||
return this.postsCount = 0;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
toggle: function() {
|
|
||||||
if (this.nodes.container && !this.timeouts.destroy) {
|
|
||||||
return this.destroy();
|
|
||||||
} else {
|
|
||||||
return this.setup(true, true);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setup: function(focus, force) {
|
|
||||||
if (!(this.isEnabled && (this.needed() || force))) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$.addClass(QR.nodes.el, 'captcha-open');
|
|
||||||
if (focus) {
|
|
||||||
this.shouldFocus = true;
|
|
||||||
}
|
|
||||||
if (this.timeouts.destroy) {
|
|
||||||
clearTimeout(this.timeouts.destroy);
|
|
||||||
delete this.timeouts.destroy;
|
|
||||||
return this.reload();
|
|
||||||
}
|
|
||||||
if (this.nodes.container) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.nodes.container = $.el('div', {
|
|
||||||
className: 'captcha-container'
|
|
||||||
});
|
|
||||||
$.prepend(this.nodes.root, this.nodes.container);
|
|
||||||
new MutationObserver(this.afterSetup.bind(this)).observe(this.nodes.container, {
|
|
||||||
childList: true,
|
|
||||||
subtree: true
|
|
||||||
});
|
|
||||||
return $.globalEval('(function() {\n function render() {\n var container = document.querySelector("#qr .captcha-container");\n container.dataset.widgetID = window.grecaptcha.render(container, {\n sitekey: \'6Ldp2bsSAAAAAAJ5uyx_lx34lJeEpTLVkP5k04qc\',\n theme: document.documentElement.classList.contains(\'tomorrow\') ? \'dark\' : \'light\',\n callback: function(response) {\n window.dispatchEvent(new CustomEvent("captcha:success", {detail: response}));\n }\n });\n }\n if (window.grecaptcha) {\n render();\n } else {\n var cbNative = window.onRecaptchaLoaded;\n window.onRecaptchaLoaded = function() {\n render();\n cbNative();\n }\n }\n})();');
|
|
||||||
},
|
|
||||||
afterSetup: function(mutations) {
|
|
||||||
var iframe, mutation, node, textarea, _i, _j, _len, _len1, _ref;
|
|
||||||
for (_i = 0, _len = mutations.length; _i < _len; _i++) {
|
|
||||||
mutation = mutations[_i];
|
|
||||||
_ref = mutation.addedNodes;
|
|
||||||
for (_j = 0, _len1 = _ref.length; _j < _len1; _j++) {
|
|
||||||
node = _ref[_j];
|
|
||||||
if (iframe = $.x('./descendant-or-self::iframe', node)) {
|
|
||||||
this.setupIFrame(iframe);
|
|
||||||
}
|
|
||||||
if (textarea = $.x('./descendant-or-self::textarea', node)) {
|
|
||||||
this.setupTextArea(textarea);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setupIFrame: function(iframe) {
|
|
||||||
this.setupTime = Date.now();
|
|
||||||
if (QR.nodes.el.getBoundingClientRect().bottom > doc.clientHeight) {
|
|
||||||
QR.nodes.el.style.top = null;
|
|
||||||
QR.nodes.el.style.bottom = '0px';
|
|
||||||
}
|
|
||||||
if (this.shouldFocus) {
|
|
||||||
iframe.focus();
|
|
||||||
}
|
|
||||||
return this.shouldFocus = false;
|
|
||||||
},
|
|
||||||
setupTextArea: function(textarea) {
|
|
||||||
return $.one(textarea, 'input', (function(_this) {
|
|
||||||
return function() {
|
|
||||||
return _this.save(true);
|
|
||||||
};
|
|
||||||
})(this));
|
|
||||||
},
|
|
||||||
destroy: function() {
|
|
||||||
if (!this.isEnabled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
delete this.timeouts.destroy;
|
|
||||||
$.rmClass(QR.nodes.el, 'captcha-open');
|
|
||||||
if (this.nodes.container) {
|
|
||||||
$.rm(this.nodes.container);
|
|
||||||
}
|
|
||||||
return delete this.nodes.container;
|
|
||||||
},
|
|
||||||
sync: function(captchas) {
|
|
||||||
if (captchas == null) {
|
|
||||||
captchas = [];
|
|
||||||
}
|
|
||||||
this.captchas = captchas;
|
|
||||||
this.clear();
|
|
||||||
return this.count();
|
|
||||||
},
|
|
||||||
getOne: function() {
|
|
||||||
var captcha;
|
|
||||||
this.clear();
|
|
||||||
if (captcha = this.captchas.shift()) {
|
|
||||||
this.count();
|
|
||||||
$.set('captchas', this.captchas);
|
|
||||||
return captcha.response;
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
save: function(pasted) {
|
|
||||||
var reload, _base;
|
|
||||||
$.forceSync('captchas');
|
|
||||||
reload = (QR.cooldown.auto || Conf['Post on Captcha Completion']) && this.needed();
|
|
||||||
this.captchas.push({
|
|
||||||
response: $('textarea', this.nodes.container).value,
|
|
||||||
timeout: (pasted ? this.setupTime : Date.now()) + 2 * $.MINUTE
|
|
||||||
});
|
|
||||||
this.count();
|
|
||||||
$.set('captchas', this.captchas);
|
|
||||||
if (reload) {
|
|
||||||
this.shouldFocus = true;
|
|
||||||
this.reload();
|
|
||||||
} else {
|
|
||||||
if (pasted) {
|
|
||||||
this.destroy();
|
|
||||||
} else {
|
|
||||||
if ((_base = this.timeouts).destroy == null) {
|
|
||||||
_base.destroy = setTimeout(this.destroy.bind(this), 3 * $.SECOND);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
QR.nodes.status.focus();
|
|
||||||
}
|
|
||||||
if (Conf['Post on Captcha Completion'] && !QR.cooldown.auto) {
|
|
||||||
return QR.submit();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
clear: function() {
|
|
||||||
var captcha, i, now, _i, _len, _ref;
|
|
||||||
if (!this.captchas.length) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
$.forceSync('captchas');
|
|
||||||
now = Date.now();
|
|
||||||
_ref = this.captchas;
|
|
||||||
for (i = _i = 0, _len = _ref.length; _i < _len; i = ++_i) {
|
|
||||||
captcha = _ref[i];
|
|
||||||
if (captcha.timeout > now) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!i) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
this.captchas = this.captchas.slice(i);
|
|
||||||
this.count();
|
|
||||||
$.set('captchas', this.captchas);
|
|
||||||
return this.setup(true);
|
|
||||||
},
|
|
||||||
count: function() {
|
|
||||||
this.nodes.counter.textContent = "Captchas: " + this.captchas.length;
|
|
||||||
clearTimeout(this.timeouts.clear);
|
|
||||||
if (this.captchas.length) {
|
|
||||||
return this.timeouts.clear = setTimeout(this.clear.bind(this), this.captchas[0].timeout - Date.now());
|
|
||||||
}
|
|
||||||
},
|
|
||||||
reload: function(focus) {
|
|
||||||
return $.globalEval('(function() {\n var container = document.querySelector("#qr .captcha-container");\n window.grecaptcha.reset(container.dataset.widgetID);\n})();');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
QR.cooldown = {
|
QR.cooldown = {
|
||||||
init: function() {
|
init: function() {
|
||||||
var key, setTimers, type;
|
var key, setTimers, type;
|
||||||
@ -18383,7 +18216,6 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
updateContext: function(view) {
|
updateContext: function(view) {
|
||||||
g.DEAD = false;
|
|
||||||
if (view === 'thread') {
|
if (view === 'thread') {
|
||||||
g.THREADID = +window.location.pathname.split('/')[3];
|
g.THREADID = +window.location.pathname.split('/')[3];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -104,7 +104,6 @@ Navigate =
|
|||||||
|
|
||||||
updateContext: (view) ->
|
updateContext: (view) ->
|
||||||
# State tracking
|
# State tracking
|
||||||
g.DEAD = false
|
|
||||||
g.THREADID = +window.location.pathname.split('/')[3] if view is 'thread'
|
g.THREADID = +window.location.pathname.split('/')[3] if view is 'thread'
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
@ -9,9 +9,9 @@
|
|||||||
</div>
|
</div>
|
||||||
<form>
|
<form>
|
||||||
<div class=persona>
|
<div class=persona>
|
||||||
<input name=name data-name=name list="list-name" placeholder=Name class=field size=1>
|
<input name=name data-name=name list="list-name" placeholder=Name class=field size=1>
|
||||||
<input name=email data-name=email list="list-email" placeholder=Options class=field size=1>
|
<input name=email data-name=email list="list-email" placeholder=Options class=field size=1>
|
||||||
<input name=sub data-name=sub list="list-sub" placeholder=Subject class=field size=1>
|
<input name=sub data-name=sub list="list-sub" placeholder=Subject class=field size=1>
|
||||||
</div>
|
</div>
|
||||||
<div class=textarea>
|
<div class=textarea>
|
||||||
<textarea data-name=com placeholder=Comment class=field></textarea>
|
<textarea data-name=com placeholder=Comment class=field></textarea>
|
||||||
|
|||||||
@ -1,173 +0,0 @@
|
|||||||
QR.captcha =
|
|
||||||
init: ->
|
|
||||||
return if d.cookie.indexOf('pass_enabled=1') >= 0
|
|
||||||
return unless @isEnabled = !!$.id 'g-recaptcha'
|
|
||||||
|
|
||||||
@captchas = []
|
|
||||||
$.get 'captchas', [], ({captchas}) ->
|
|
||||||
QR.captcha.sync captchas
|
|
||||||
$.sync 'captchas', @sync.bind @
|
|
||||||
|
|
||||||
root = $.el 'div', className: 'captcha-root'
|
|
||||||
$.extend root, <%= html(
|
|
||||||
'<div class="captcha-counter"><a href="javascript:;"></a></div>'
|
|
||||||
) %>
|
|
||||||
counter = $ '.captcha-counter > a', root
|
|
||||||
@nodes = {root, counter}
|
|
||||||
@count()
|
|
||||||
$.addClass QR.nodes.el, 'has-captcha'
|
|
||||||
$.after QR.nodes.com.parentNode, root
|
|
||||||
|
|
||||||
$.on counter, 'click', @toggle.bind @
|
|
||||||
$.on window, 'captcha:success', =>
|
|
||||||
# XXX Greasemonkey 1.x workaround to gain access to GM_* functions.
|
|
||||||
$.queueTask => @save false
|
|
||||||
|
|
||||||
shouldFocus: false
|
|
||||||
timeouts: {}
|
|
||||||
postsCount: 0
|
|
||||||
|
|
||||||
needed: ->
|
|
||||||
captchaCount = @captchas.length
|
|
||||||
captchaCount++ if @nodes.container and !@timeouts.destroy
|
|
||||||
@postsCount = QR.posts.length
|
|
||||||
@postsCount = 0 if @postsCount is 1 and !Conf['Auto-load captcha'] and !QR.posts[0].com and !QR.posts[0].file
|
|
||||||
captchaCount < @postsCount
|
|
||||||
|
|
||||||
onPostChange: ->
|
|
||||||
@setup() if @postsCount is 0
|
|
||||||
@postsCount = 0 if QR.posts.length is 1 and !Conf['Auto-load captcha'] and !QR.posts[0].com and !QR.posts[0].file
|
|
||||||
|
|
||||||
toggle: ->
|
|
||||||
if @nodes.container and !@timeouts.destroy
|
|
||||||
@destroy()
|
|
||||||
else
|
|
||||||
@setup true, true
|
|
||||||
|
|
||||||
setup: (focus, force) ->
|
|
||||||
return unless @isEnabled and (@needed() or force)
|
|
||||||
$.addClass QR.nodes.el, 'captcha-open'
|
|
||||||
@shouldFocus = true if focus
|
|
||||||
if @timeouts.destroy
|
|
||||||
clearTimeout @timeouts.destroy
|
|
||||||
delete @timeouts.destroy
|
|
||||||
return @reload()
|
|
||||||
|
|
||||||
return if @nodes.container
|
|
||||||
|
|
||||||
@nodes.container = $.el 'div', className: 'captcha-container'
|
|
||||||
$.prepend @nodes.root, @nodes.container
|
|
||||||
new MutationObserver(@afterSetup.bind @).observe @nodes.container,
|
|
||||||
childList: true
|
|
||||||
subtree: true
|
|
||||||
|
|
||||||
$.globalEval '''
|
|
||||||
(function() {
|
|
||||||
function render() {
|
|
||||||
var container = document.querySelector("#qr .captcha-container");
|
|
||||||
container.dataset.widgetID = window.grecaptcha.render(container, {
|
|
||||||
sitekey: '<%= meta.recaptchaKey %>',
|
|
||||||
theme: document.documentElement.classList.contains('tomorrow') ? 'dark' : 'light',
|
|
||||||
callback: function(response) {
|
|
||||||
window.dispatchEvent(new CustomEvent("captcha:success", {detail: response}));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (window.grecaptcha) {
|
|
||||||
render();
|
|
||||||
} else {
|
|
||||||
var cbNative = window.onRecaptchaLoaded;
|
|
||||||
window.onRecaptchaLoaded = function() {
|
|
||||||
render();
|
|
||||||
cbNative();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
'''
|
|
||||||
|
|
||||||
afterSetup: (mutations) ->
|
|
||||||
for mutation in mutations
|
|
||||||
for node in mutation.addedNodes
|
|
||||||
@setupIFrame iframe if iframe = $.x './descendant-or-self::iframe', node
|
|
||||||
@setupTextArea textarea if textarea = $.x './descendant-or-self::textarea', node
|
|
||||||
return
|
|
||||||
|
|
||||||
setupIFrame: (iframe) ->
|
|
||||||
@setupTime = Date.now()
|
|
||||||
|
|
||||||
if QR.nodes.el.getBoundingClientRect().bottom > doc.clientHeight
|
|
||||||
QR.nodes.el.style.top = null
|
|
||||||
QR.nodes.el.style.bottom = '0px'
|
|
||||||
iframe.focus() if @shouldFocus
|
|
||||||
@shouldFocus = false
|
|
||||||
|
|
||||||
setupTextArea: (textarea) ->
|
|
||||||
$.one textarea, 'input', => @save true
|
|
||||||
|
|
||||||
destroy: ->
|
|
||||||
return unless @isEnabled
|
|
||||||
delete @timeouts.destroy
|
|
||||||
$.rmClass QR.nodes.el, 'captcha-open'
|
|
||||||
$.rm @nodes.container if @nodes.container
|
|
||||||
delete @nodes.container
|
|
||||||
|
|
||||||
sync: (captchas=[]) ->
|
|
||||||
@captchas = captchas
|
|
||||||
@clear()
|
|
||||||
@count()
|
|
||||||
|
|
||||||
getOne: ->
|
|
||||||
@clear()
|
|
||||||
if captcha = @captchas.shift()
|
|
||||||
@count()
|
|
||||||
$.set 'captchas', @captchas
|
|
||||||
captcha.response
|
|
||||||
else
|
|
||||||
null
|
|
||||||
|
|
||||||
save: (pasted) ->
|
|
||||||
$.forceSync 'captchas'
|
|
||||||
reload = (QR.cooldown.auto or Conf['Post on Captcha Completion']) and @needed()
|
|
||||||
@captchas.push
|
|
||||||
response: $('textarea', @nodes.container).value
|
|
||||||
timeout: (if pasted then @setupTime else Date.now()) + 2 * $.MINUTE
|
|
||||||
@count()
|
|
||||||
$.set 'captchas', @captchas
|
|
||||||
|
|
||||||
if reload
|
|
||||||
@shouldFocus = true
|
|
||||||
@reload()
|
|
||||||
else
|
|
||||||
if pasted
|
|
||||||
@destroy()
|
|
||||||
else
|
|
||||||
@timeouts.destroy ?= setTimeout @destroy.bind(@), 3 * $.SECOND
|
|
||||||
QR.nodes.status.focus()
|
|
||||||
|
|
||||||
QR.submit() if Conf['Post on Captcha Completion'] and !QR.cooldown.auto
|
|
||||||
|
|
||||||
clear: ->
|
|
||||||
return unless @captchas.length
|
|
||||||
$.forceSync 'captchas'
|
|
||||||
now = Date.now()
|
|
||||||
for captcha, i in @captchas
|
|
||||||
break if captcha.timeout > now
|
|
||||||
return unless i
|
|
||||||
@captchas = @captchas[i..]
|
|
||||||
@count()
|
|
||||||
$.set 'captchas', @captchas
|
|
||||||
@setup true
|
|
||||||
|
|
||||||
count: ->
|
|
||||||
@nodes.counter.textContent = "Captchas: #{@captchas.length}"
|
|
||||||
clearTimeout @timeouts.clear
|
|
||||||
if @captchas.length
|
|
||||||
@timeouts.clear = setTimeout @clear.bind(@), @captchas[0].timeout - Date.now()
|
|
||||||
|
|
||||||
reload: (focus) ->
|
|
||||||
$.globalEval '''
|
|
||||||
(function() {
|
|
||||||
var container = document.querySelector("#qr .captcha-container");
|
|
||||||
window.grecaptcha.reset(container.dataset.widgetID);
|
|
||||||
})();
|
|
||||||
'''
|
|
||||||
@ -5,8 +5,19 @@ QR =
|
|||||||
@db = new DataBoard 'yourPosts'
|
@db = new DataBoard 'yourPosts'
|
||||||
@posts = []
|
@posts = []
|
||||||
|
|
||||||
|
return if g.VIEW is 'archive'
|
||||||
|
|
||||||
|
$.globalEval 'document.documentElement.dataset.jsEnabled = true;'
|
||||||
|
noscript = Conf['Force Noscript Captcha'] or !doc.dataset.jsEnabled
|
||||||
|
@captcha = Captcha[if noscript then 'noscript' else 'v2']
|
||||||
|
|
||||||
$.on d, '4chanXInitFinished', @initReady
|
$.on d, '4chanXInitFinished', @initReady
|
||||||
|
|
||||||
|
window.addEventListener 'focus', @focus, true
|
||||||
|
window.addEventListener 'blur', @focus, true
|
||||||
|
# We don't receive blur events from captcha iframe.
|
||||||
|
$.on d, 'click', @focus
|
||||||
|
|
||||||
Post.callbacks.push
|
Post.callbacks.push
|
||||||
name: 'Quick Reply'
|
name: 'Quick Reply'
|
||||||
cb: @node
|
cb: @node
|
||||||
@ -45,9 +56,7 @@ QR =
|
|||||||
QR.postingIsEnabled = !!$.id 'postForm'
|
QR.postingIsEnabled = !!$.id 'postForm'
|
||||||
return unless QR.postingIsEnabled
|
return unless QR.postingIsEnabled
|
||||||
|
|
||||||
<% if (type === 'crx') { %>
|
|
||||||
$.on d, 'paste', QR.paste
|
$.on d, 'paste', QR.paste
|
||||||
<% } %>
|
|
||||||
$.on d, 'dragover', QR.dragOver
|
$.on d, 'dragover', QR.dragOver
|
||||||
$.on d, 'drop', QR.dropFile
|
$.on d, 'drop', QR.dropFile
|
||||||
$.on d, 'dragstart dragend', QR.drag
|
$.on d, 'dragstart dragend', QR.drag
|
||||||
@ -58,10 +67,12 @@ QR =
|
|||||||
|
|
||||||
return if !Conf['Persistent QR']
|
return if !Conf['Persistent QR']
|
||||||
QR.open()
|
QR.open()
|
||||||
QR.hide() if Conf['Auto-Hide QR']
|
QR.hide() if Conf['Auto Hide QR']
|
||||||
|
|
||||||
statusCheck: ->
|
statusCheck: ->
|
||||||
if g.DEAD
|
return unless QR.nodes
|
||||||
|
{thread} = QR.posts[0]
|
||||||
|
if thread isnt 'new' and g.threads["#{g.BOARD}.#{thread}"].isDead
|
||||||
QR.abort()
|
QR.abort()
|
||||||
else
|
else
|
||||||
QR.status()
|
QR.status()
|
||||||
@ -78,9 +89,9 @@ QR =
|
|||||||
|
|
||||||
open: ->
|
open: ->
|
||||||
if QR.nodes
|
if QR.nodes
|
||||||
|
QR.captcha.setup() if QR.nodes.el.hidden
|
||||||
QR.nodes.el.hidden = false
|
QR.nodes.el.hidden = false
|
||||||
QR.unhide()
|
QR.unhide()
|
||||||
QR.captcha.setup()
|
|
||||||
return
|
return
|
||||||
try
|
try
|
||||||
QR.dialog()
|
QR.dialog()
|
||||||
@ -107,12 +118,25 @@ QR =
|
|||||||
QR.status()
|
QR.status()
|
||||||
QR.captcha.destroy()
|
QR.captcha.destroy()
|
||||||
|
|
||||||
focusin: ->
|
focus: ->
|
||||||
QR.captcha.setup() if $.hasClass(QR.nodes.el, 'autohide') and !$.hasClass(QR.nodes.el, 'focus')
|
$.queueTask ->
|
||||||
$.addClass QR.nodes.el, 'focus'
|
return unless QR.nodes
|
||||||
|
unless $$('.goog-bubble-content > iframe').some((el) -> el.getBoundingClientRect().top >= 0)
|
||||||
|
focus = d.activeElement and QR.nodes.el.contains(d.activeElement)
|
||||||
|
$[if focus then 'addClass' else 'rmClass'] QR.nodes.el, 'focus'
|
||||||
|
if chrome?
|
||||||
|
# XXX Stop anomalous scrolling on space/tab in captcha iframe.
|
||||||
|
if d.activeElement and QR.nodes.el.contains(d.activeElement) and d.activeElement.nodeName is 'IFRAME'
|
||||||
|
QR.scrollY = window.scrollY
|
||||||
|
$.on d, 'scroll', QR.scrollLock
|
||||||
|
else
|
||||||
|
$.off d, 'scroll', QR.scrollLock
|
||||||
|
|
||||||
focusout: ->
|
scrollLock: (e) ->
|
||||||
$.rmClass QR.nodes.el, 'focus'
|
if d.activeElement and QR.nodes.el.contains(d.activeElement) and d.activeElement.nodeName is 'IFRAME'
|
||||||
|
window.scroll window.scrollX, QR.scrollY
|
||||||
|
else
|
||||||
|
$.off d, 'scroll', QR.scrollLock
|
||||||
|
|
||||||
hide: ->
|
hide: ->
|
||||||
d.activeElement.blur()
|
d.activeElement.blur()
|
||||||
@ -138,7 +162,9 @@ QR =
|
|||||||
el.removeAttribute 'style'
|
el.removeAttribute 'style'
|
||||||
if QR.captcha.isEnabled and /captcha|verification/i.test el.textContent
|
if QR.captcha.isEnabled and /captcha|verification/i.test el.textContent
|
||||||
QR.captcha.setup true
|
QR.captcha.setup true
|
||||||
QR.notify el
|
QR.captcha.notify el
|
||||||
|
else
|
||||||
|
QR.notify el
|
||||||
alert el.textContent if d.hidden
|
alert el.textContent if d.hidden
|
||||||
|
|
||||||
notify: (el) ->
|
notify: (el) ->
|
||||||
@ -196,7 +222,7 @@ QR =
|
|||||||
|
|
||||||
sel = d.getSelection()
|
sel = d.getSelection()
|
||||||
post = Get.postFromNode @
|
post = Get.postFromNode @
|
||||||
text = ">>#{post}\n"
|
text = if post.board.ID is g.BOARD.ID then ">>#{post}\n" else ">>>/#{post.board}/#{post}\n"
|
||||||
if sel.toString().trim() and post is Get.postFromNode sel.anchorNode
|
if sel.toString().trim() and post is Get.postFromNode sel.anchorNode
|
||||||
range = sel.getRangeAt 0
|
range = sel.getRangeAt 0
|
||||||
frag = range.cloneContents()
|
frag = range.cloneContents()
|
||||||
@ -356,6 +382,7 @@ QR =
|
|||||||
'new'
|
'new'
|
||||||
list.nextElementSibling.firstChild.textContent = list.options[list.selectedIndex].textContent if $.hasClass list, 'riced'
|
list.nextElementSibling.firstChild.textContent = list.options[list.selectedIndex].textContent if $.hasClass list, 'riced'
|
||||||
|
|
||||||
|
(if g.VIEW is 'thread' then $.addClass else $.rmClass) QR.nodes.el, 'reply-to-thread'
|
||||||
|
|
||||||
dialog: ->
|
dialog: ->
|
||||||
QR.nodes = nodes =
|
QR.nodes = nodes =
|
||||||
@ -405,6 +432,14 @@ QR =
|
|||||||
QR.max_width_video = QR.max_height_video = 2048
|
QR.max_width_video = QR.max_height_video = 2048
|
||||||
QR.max_duration_video = 120
|
QR.max_duration_video = 120
|
||||||
|
|
||||||
|
if Conf['Show New Thread Option in Threads']
|
||||||
|
$.addClass QR.nodes.el, 'show-new-thread-option'
|
||||||
|
|
||||||
|
if Conf['Show Name and Subject']
|
||||||
|
$.addClass QR.nodes.name, 'force-show'
|
||||||
|
$.addClass QR.nodes.sub, 'force-show'
|
||||||
|
QR.nodes.email.placeholder = 'E-mail'
|
||||||
|
|
||||||
QR.forcedAnon = !!$ 'form[name="post"] input[name="name"][type="hidden"]'
|
QR.forcedAnon = !!$ 'form[name="post"] input[name="name"][type="hidden"]'
|
||||||
if QR.forcedAnon
|
if QR.forcedAnon
|
||||||
$.addClass QR.nodes.el, 'forced-anon'
|
$.addClass QR.nodes.el, 'forced-anon'
|
||||||
@ -420,16 +455,16 @@ QR =
|
|||||||
nodes.addPost.tabIndex = 35
|
nodes.addPost.tabIndex = 35
|
||||||
|
|
||||||
if g.BOARD.ID is 'f' and g.VIEW isnt 'thread'
|
if g.BOARD.ID is 'f' and g.VIEW isnt 'thread'
|
||||||
nodes.flashTag = $.el 'select', name: 'filetag',
|
nodes.flashTag = $.el 'select', name: 'filetag',
|
||||||
innerHTML: """
|
$.extend nodes.flashTag, <%= html(
|
||||||
<option value=0>Hentai</option>
|
'<option value="0">Hentai</option>' +
|
||||||
<option value=6>Porn</option>
|
'<option value="6">Porn</option>' +
|
||||||
<option value=1>Japanese</option>
|
'<option value="1">Japanese</option>' +
|
||||||
<option value=2>Anime</option>
|
'<option value="2">Anime</option>' +
|
||||||
<option value=3>Game</option>
|
'<option value="3">Game</option>' +
|
||||||
<option value=5>Loop</option>
|
'<option value="5">Loop</option>' +
|
||||||
<option value=4 selected>Other</option>
|
'<option value="4" selected>Other</option>'
|
||||||
"""
|
) %>
|
||||||
nodes.flashTag.dataset.default = '4'
|
nodes.flashTag.dataset.default = '4'
|
||||||
$.add nodes.form, nodes.flashTag
|
$.add nodes.form, nodes.flashTag
|
||||||
|
|
||||||
@ -437,12 +472,6 @@ QR =
|
|||||||
|
|
||||||
$.on nodes.filename.parentNode, 'click keydown', QR.openFileInput
|
$.on nodes.filename.parentNode, 'click keydown', QR.openFileInput
|
||||||
|
|
||||||
items = $$ '*', QR.nodes.el
|
|
||||||
i = 0
|
|
||||||
while elm = items[i++]
|
|
||||||
$.on elm, 'blur', QR.focusout
|
|
||||||
$.on elm, 'focus', QR.focusin
|
|
||||||
|
|
||||||
$.on nodes.autohide, 'change', QR.toggleHide
|
$.on nodes.autohide, 'change', QR.toggleHide
|
||||||
$.on nodes.close, 'click', QR.close
|
$.on nodes.close, 'click', QR.close
|
||||||
$.on nodes.dumpButton, 'click', -> nodes.el.classList.toggle 'dump'
|
$.on nodes.dumpButton, 'click', -> nodes.el.classList.toggle 'dump'
|
||||||
@ -462,7 +491,7 @@ QR =
|
|||||||
$.on nodes[name], 'mouseover', QR.mouseover
|
$.on nodes[name], 'mouseover', QR.mouseover
|
||||||
|
|
||||||
# save selected post's data
|
# save selected post's data
|
||||||
items = ['name', 'email', 'sub', 'com', 'filename', 'flag']
|
items = ['thread', 'name', 'email', 'sub', 'com', 'filename', 'flag']
|
||||||
i = 0
|
i = 0
|
||||||
save = -> QR.selected.save @
|
save = -> QR.selected.save @
|
||||||
while name = items[i++]
|
while name = items[i++]
|
||||||
@ -549,12 +578,13 @@ QR =
|
|||||||
$.rm nodes.flag
|
$.rm nodes.flag
|
||||||
delete nodes.flag
|
delete nodes.flag
|
||||||
|
|
||||||
if g.BOARD.ID is 'pol'
|
# # if false?
|
||||||
flag = QR.flags()
|
# if g.BOARD.ID is 'pol'
|
||||||
flag.dataset.name = 'flag'
|
# flag = QR.flags()
|
||||||
flag.dataset.default = '0'
|
# flag.dataset.name = 'flag'
|
||||||
nodes.flag = flag
|
# flag.dataset.default = '0'
|
||||||
$.add nodes.form, flag
|
# nodes.flag = flag
|
||||||
|
# $.add nodes.form, flag
|
||||||
|
|
||||||
submit: (e) ->
|
submit: (e) ->
|
||||||
e?.preventDefault()
|
e?.preventDefault()
|
||||||
@ -590,8 +620,8 @@ QR =
|
|||||||
err = 'Max limit of image replies has been reached.'
|
err = 'Max limit of image replies has been reached.'
|
||||||
|
|
||||||
if QR.captcha.isEnabled and !err
|
if QR.captcha.isEnabled and !err
|
||||||
response = QR.captcha.getOne()
|
captcha = QR.captcha.getOne()
|
||||||
err = 'No valid captcha.' unless response
|
err = 'No valid captcha.' unless captcha
|
||||||
|
|
||||||
QR.cleanNotifications()
|
QR.cleanNotifications()
|
||||||
if err
|
if err
|
||||||
@ -613,10 +643,8 @@ QR =
|
|||||||
|
|
||||||
formData =
|
formData =
|
||||||
resto: threadID
|
resto: threadID
|
||||||
|
|
||||||
name: post.name unless QR.forcedAnon
|
name: post.name unless QR.forcedAnon
|
||||||
email: post.email
|
email: post.email
|
||||||
|
|
||||||
sub: post.sub unless QR.forcedAnon or threadID
|
sub: post.sub unless QR.forcedAnon or threadID
|
||||||
com: post.com
|
com: post.com
|
||||||
upfile: post.file
|
upfile: post.file
|
||||||
@ -626,7 +654,6 @@ QR =
|
|||||||
textonly: textOnly
|
textonly: textOnly
|
||||||
mode: 'regist'
|
mode: 'regist'
|
||||||
pwd: QR.persona.pwd
|
pwd: QR.persona.pwd
|
||||||
'g-recaptcha-response': response
|
|
||||||
|
|
||||||
options =
|
options =
|
||||||
responseType: 'document'
|
responseType: 'document'
|
||||||
@ -639,10 +666,11 @@ QR =
|
|||||||
QR.cooldown.auto = false
|
QR.cooldown.auto = false
|
||||||
QR.status()
|
QR.status()
|
||||||
QR.error $.el 'span',
|
QR.error $.el 'span',
|
||||||
innerHTML: """
|
<%= html(
|
||||||
Connection error. You may have been <a href=//www.4chan.org/banned target=_blank>banned</a>.
|
'4chan X encountered an error while posting. ' +
|
||||||
[<a href="https://github.com/MayhemYDG/4chan-x/wiki/FAQ#what-does-connection-error-you-may-have-been-banned-mean" target=_blank>?</a>]
|
'[<a href="//4chan.org/banned" target="_blank">Banned?</a>] ' +
|
||||||
"""
|
'[<a href="${g.FAQ}#what-does-4chan-x-encountered-an-error-while-posting-please-try-again-mean" target="_blank">More info</a>]'
|
||||||
|
) %>
|
||||||
extra =
|
extra =
|
||||||
form: $.formData formData
|
form: $.formData formData
|
||||||
upCallbacks:
|
upCallbacks:
|
||||||
@ -657,11 +685,29 @@ 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 "https://sys.4chan.org/#{g.BOARD}/post", options, extra
|
cb = (response) ->
|
||||||
|
extra.form.append 'g-recaptcha-response', response if response?
|
||||||
|
QR.req = $.ajax "https://sys.4chan.org/#{g.BOARD}/post", options, extra
|
||||||
|
QR.req.progress = '...'
|
||||||
|
|
||||||
|
if typeof captcha is 'function'
|
||||||
|
# Wait for captcha to be verified before submitting post.
|
||||||
|
QR.req =
|
||||||
|
progress: '...'
|
||||||
|
abort: -> cb = null
|
||||||
|
captcha (response) ->
|
||||||
|
if response
|
||||||
|
cb? response
|
||||||
|
else
|
||||||
|
delete QR.req
|
||||||
|
post.unlock()
|
||||||
|
QR.cooldown.auto = !!QR.captcha.captchas.length
|
||||||
|
QR.status()
|
||||||
|
else
|
||||||
|
cb captcha
|
||||||
|
|
||||||
# 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.progress = '...'
|
|
||||||
QR.status()
|
QR.status()
|
||||||
|
|
||||||
response: ->
|
response: ->
|
||||||
@ -674,17 +720,11 @@ QR =
|
|||||||
resDoc = req.response
|
resDoc = req.response
|
||||||
if ban = $ '.banType', resDoc # banned/warning
|
if ban = $ '.banType', resDoc # banned/warning
|
||||||
board = $('.board', resDoc).innerHTML
|
board = $('.board', resDoc).innerHTML
|
||||||
err = $.el 'span', innerHTML:
|
err = $.el 'span',
|
||||||
if ban.textContent.toLowerCase() is 'banned'
|
if ban.textContent.toLowerCase() is 'banned'
|
||||||
"""
|
<%= html('You are banned on &{$(".board", resDoc)}! ;_;<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
|
||||||
"""
|
<%= html('You were issued a warning on &{$(".board", resDoc)} as &{$(".nameBlock", resDoc)}.<br>Reason: &{$(".reason", resDoc)}') %>
|
||||||
You were issued a warning on #{board} as #{$('.nameBlock', resDoc).innerHTML}.<br>
|
|
||||||
Reason: #{$('.reason', resDoc).innerHTML}
|
|
||||||
"""
|
|
||||||
else if err = resDoc.getElementById 'errmsg' # error!
|
else if err = resDoc.getElementById 'errmsg' # error!
|
||||||
$('a', err)?.target = '_blank' # duplicate image link
|
$('a', err)?.target = '_blank' # duplicate image link
|
||||||
else if resDoc.title isnt 'Post successful!'
|
else if resDoc.title isnt 'Post successful!'
|
||||||
@ -710,13 +750,14 @@ QR =
|
|||||||
false
|
false
|
||||||
# Too many frequent mistyped captchas will auto-ban you!
|
# Too many frequent mistyped captchas will auto-ban you!
|
||||||
# On connection error, the post most likely didn't go through.
|
# On connection error, the post most likely didn't go through.
|
||||||
QR.cooldown.set delay: 2
|
QR.cooldown.addDelay post, 2
|
||||||
else if err.textContent and m = err.textContent.match /wait\s+(\d+)\s+second/i
|
else if err.textContent and (m = err.textContent.match /wait\s+(\d+)\s+second/i) and !/duplicate/i.test err.textContent
|
||||||
QR.cooldown.auto = if QR.captcha.isEnabled
|
QR.cooldown.auto = if QR.captcha.isEnabled
|
||||||
!!QR.captcha.captchas.length
|
!!QR.captcha.captchas.length
|
||||||
else
|
else
|
||||||
true
|
true
|
||||||
QR.cooldown.set delay: m[1]
|
QR.cooldown.addDelay post, +m[1]
|
||||||
|
QR.captcha.setup (d.activeElement is QR.nodes.status)
|
||||||
else # stop auto-posting
|
else # stop auto-posting
|
||||||
QR.cooldown.auto = false
|
QR.cooldown.auto = false
|
||||||
QR.status()
|
QR.status()
|
||||||
@ -762,26 +803,27 @@ QR =
|
|||||||
notif.onclick = ->
|
notif.onclick = ->
|
||||||
QR.open()
|
QR.open()
|
||||||
window.focus()
|
window.focus()
|
||||||
|
QR.captcha.setup true
|
||||||
notif.onshow = ->
|
notif.onshow = ->
|
||||||
setTimeout ->
|
setTimeout ->
|
||||||
notif.close()
|
notif.close()
|
||||||
, 7 * $.SECOND
|
, 7 * $.SECOND
|
||||||
|
|
||||||
unless Conf['Persistent QR'] or QR.cooldown.auto
|
unless Conf['Persistent QR'] or postsCount
|
||||||
QR.close()
|
QR.close()
|
||||||
else
|
else
|
||||||
post.rm()
|
post.rm()
|
||||||
QR.captcha.setup true
|
QR.captcha.setup(d.activeElement is QR.nodes.status)
|
||||||
|
|
||||||
QR.cooldown.set {req, post, isReply, threadID}
|
QR.cooldown.add req.uploadEndTime, threadID, postID
|
||||||
|
|
||||||
URL = if threadID is postID # new thread
|
URL = if threadID is postID # new thread
|
||||||
Build.path g.BOARD.ID, threadID
|
window.location.origin + Build.path g.BOARD.ID, threadID
|
||||||
else if g.VIEW is 'index' and !QR.cooldown.auto and Conf['Open Post in New Tab'] # replying from the index
|
else if g.VIEW is 'index' and !QR.cooldown.auto and Conf['Open Post in New Tab'] # replying from the index
|
||||||
Build.path g.BOARD.ID, threadID, postID
|
window.location.origin + Build.path g.BOARD.ID, threadID, postID
|
||||||
|
|
||||||
if URL
|
if URL
|
||||||
if Conf['Open Post in New Tab']
|
if Conf['Open Post in New Tab'] or postsCount
|
||||||
$.open URL
|
$.open URL
|
||||||
else
|
else
|
||||||
window.location = URL
|
window.location = URL
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user