diff --git a/CHANGELOG.md b/CHANGELOG.md
index f270b8ff3..3a7b3b904 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,12 @@
### v1.14.21
+**v1.14.21.5** *(2021-07-07)* - [[Userscript](https://raw.githubusercontent.com/ccd0/4chan-x/1.14.21.5/builds/4chan-X-noupdate.user.js)] [[Chrome extension](https://raw.githubusercontent.com/ccd0/4chan-x/1.14.21.5/builds/4chan-X-noupdate.crx)]
+- Fix bug causing captcha to sometimes not work when replying from index.
+
+**v1.14.21.4** *(2021-07-05)* - [[Userscript](https://raw.githubusercontent.com/ccd0/4chan-x/1.14.21.4/builds/4chan-X-noupdate.user.js)] [[Chrome extension](https://raw.githubusercontent.com/ccd0/4chan-x/1.14.21.4/builds/4chan-X-noupdate.crx)]
+- Preliminary support for new first-party captcha on 4chan.
+
**v1.14.21.3** *(2021-05-07)* - [[Userscript](https://raw.githubusercontent.com/ccd0/4chan-x/1.14.21.3/builds/4chan-X-noupdate.user.js)] [[Chrome extension](https://raw.githubusercontent.com/ccd0/4chan-x/1.14.21.3/builds/4chan-X-noupdate.crx)]
- Fix race condition causing unread posts tracking to malfunction.
diff --git a/builds/4chan-X-beta.crx b/builds/4chan-X-beta.crx
index 31ac6ddf6..a102e1fd3 100644
Binary files a/builds/4chan-X-beta.crx and b/builds/4chan-X-beta.crx differ
diff --git a/builds/4chan-X-beta.meta.js b/builds/4chan-X-beta.meta.js
index 06d6236da..3c135b8e3 100644
--- a/builds/4chan-X-beta.meta.js
+++ b/builds/4chan-X-beta.meta.js
@@ -1,6 +1,6 @@
// ==UserScript==
// @name 4chan X beta
-// @version 1.14.21.3
+// @version 1.14.21.5
// @minGMVer 1.14
// @minFFVer 26
// @namespace 4chan-X
diff --git a/builds/4chan-X-beta.user.js b/builds/4chan-X-beta.user.js
index 11f69fa49..ffbd1011d 100644
--- a/builds/4chan-X-beta.user.js
+++ b/builds/4chan-X-beta.user.js
@@ -1,6 +1,6 @@
// ==UserScript==
// @name 4chan X beta
-// @version 1.14.21.3
+// @version 1.14.21.5
// @minGMVer 1.14
// @minFFVer 26
// @namespace 4chan-X
@@ -218,7 +218,7 @@ docSet = function() {
};
g = {
- VERSION: '1.14.21.3',
+ VERSION: '1.14.21.5',
NAMESPACE: '4chan X.',
sites: Object.create(null),
boards: Object.create(null)
@@ -23732,6 +23732,115 @@ Captcha = {};
}).call(this);
+(function() {
+ Captcha.t = {
+ init: function() {
+ var root;
+ if (d.cookie.indexOf('pass_enabled=1') >= 0) {
+ return;
+ }
+ if (!(this.isEnabled = !!$('#t-root') || !$.id('postForm'))) {
+ return;
+ }
+ root = $.el('div', {
+ className: 'captcha-root'
+ });
+ this.nodes = {
+ root: root
+ };
+ $.addClass(QR.nodes.el, 'has-captcha', 'captcha-t');
+ return $.after(QR.nodes.com.parentNode, root);
+ },
+ moreNeeded: function() {},
+ getThread: function() {
+ var boardID, threadID;
+ boardID = g.BOARD.ID;
+ if (QR.posts[0].thread === 'new') {
+ threadID = '0';
+ } else {
+ threadID = '' + QR.posts[0].thread;
+ }
+ return {
+ boardID: boardID,
+ threadID: threadID
+ };
+ },
+ setup: function(focus) {
+ if (!this.isEnabled) {
+ return;
+ }
+ if (!this.nodes.container) {
+ this.nodes.container = $.el('div', {
+ className: 'captcha-container'
+ });
+ $.prepend(this.nodes.root, this.nodes.container);
+ Captcha.t.currentThread = Captcha.t.getThread();
+ $.global(function() {
+ var el;
+ el = document.querySelector('#qr .captcha-container');
+ window.TCaptcha.init(el, this.boardID, +this.threadID);
+ return window.TCaptcha.setErrorCb(function(err) {
+ return window.dispatchEvent(new CustomEvent('CreateNotification', {
+ detail: {
+ type: 'warning',
+ content: '' + err
+ }
+ }));
+ });
+ }, Captcha.t.currentThread);
+ }
+ if (focus) {
+ return $('#t-resp').focus();
+ }
+ },
+ destroy: function() {
+ if (!(this.isEnabled && this.nodes.container)) {
+ return;
+ }
+ $.global(function() {
+ return window.TCaptcha.destroy();
+ });
+ $.rm(this.nodes.container);
+ return delete this.nodes.container;
+ },
+ updateThread: function() {
+ var boardID, newThread, ref, threadID;
+ ref = Captcha.t.currentThread, boardID = ref.boardID, threadID = ref.threadID;
+ newThread = Captcha.t.getThread();
+ if (!(newThread.boardID === boardID && newThread.threadID === threadID)) {
+ Captcha.t.destroy();
+ return Captcha.t.setup();
+ }
+ },
+ getOne: function() {
+ var i, key, len, ref, response;
+ response = {};
+ if (this.nodes.container) {
+ ref = ['t-response', 't-challenge'];
+ for (i = 0, len = ref.length; i < len; i++) {
+ key = ref[i];
+ response[key] = $("[name='" + key + "']", this.nodes.container).value;
+ }
+ }
+ if (!response['t-response']) {
+ response = null;
+ }
+ return response;
+ },
+ setUsed: function() {
+ if (this.nodes.container) {
+ return $.global(function() {
+ return window.TCaptcha.clearChallenge();
+ });
+ }
+ },
+ occupied: function() {
+ return !!this.nodes.container;
+ }
+ };
+
+}).call(this);
+
(function() {
var indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
@@ -24158,7 +24267,6 @@ QR = (function() {
return;
}
this.posts = [];
- this.captcha = Captcha.v2;
$.on(d, '4chanXInitFinished', function() {
return BoardConfig.ready(QR.initReady);
});
@@ -24186,7 +24294,9 @@ QR = (function() {
return Header.addShortcut('qr', sc, 540);
},
initReady: function() {
- var config, link, linkBot, navLinksBot, origToggle, prop;
+ var captchaVersion, config, link, linkBot, navLinksBot, origToggle, prop;
+ captchaVersion = $('#t-root') ? 't' : 'v2';
+ QR.captcha = Captcha[captchaVersion];
QR.postingIsEnabled = true;
config = g.BOARD.config;
prop = function(key, def) {
@@ -24964,8 +25074,11 @@ QR = (function() {
if (g.BOARD.ID === 'r9k' && !((ref = post.com) != null ? ref.match(/[a-z-]/i) : void 0)) {
err || (err = 'Original comment required.');
}
- if (QR.captcha.isEnabled && !(/\b_ct=/.test(d.cookie) && threadID) && !(err && !force)) {
- captcha = QR.captcha.getOne(!!threadID) || Captcha.cache.request(!!threadID);
+ if (QR.captcha.isEnabled && !(QR.captcha === Captcha.v2 && /\b_ct=/.test(d.cookie) && threadID) && !(err && !force)) {
+ captcha = QR.captcha.getOne(!!threadID);
+ if (QR.captcha === Captcha.v2) {
+ captcha || (captcha = Captcha.cache.request(!!threadID));
+ }
if (!captcha) {
err = 'No valid captcha.';
QR.captcha.setup(!QR.cooldown.auto || d.activeElement === QR.nodes.status);
@@ -25015,13 +25128,21 @@ QR = (function() {
};
}
cb = function(response) {
+ var key, val;
if (response != null) {
QR.currentCaptcha = response;
- if (response.challenge != null) {
- options.form.append('recaptcha_challenge_field', response.challenge);
- options.form.append('recaptcha_response_field', response.response);
+ if (QR.captcha === Captcha.v2) {
+ if (response.challenge != null) {
+ options.form.append('recaptcha_challenge_field', response.challenge);
+ options.form.append('recaptcha_response_field', response.response);
+ } else {
+ options.form.append('g-recaptcha-response', response.response);
+ }
} else {
- options.form.append('g-recaptcha-response', response.response);
+ for (key in response) {
+ val = response[key];
+ options.form.append(key, val);
+ }
}
}
QR.req = $.ajax("https://sys." + (location.hostname.split('.')[1]) + ".org/" + g.BOARD + "/post", options);
@@ -25031,12 +25152,14 @@ QR = (function() {
QR.req = {
progress: '...',
abort: function() {
- Captcha.cache.abort();
+ if (QR.captcha === Captcha.v2) {
+ Captcha.cache.abort();
+ }
return cb = null;
}
};
captcha(function(response) {
- if (Captcha.cache.haveCookie()) {
+ if (QR.captcha === Captcha.v2 && Captcha.cache.haveCookie()) {
if (typeof cb === "function") {
cb();
}
@@ -25058,7 +25181,7 @@ QR = (function() {
return QR.status();
},
response: function() {
- var URL, _, connErr, err, h1, isReply, j, lastPostToThread, len, m, mi, open, post, postID, postsCount, ref, ref1, ref2, ref3, seconds, threadID;
+ var URL, _, base, connErr, err, h1, isReply, j, lastPostToThread, len, m, mi, open, post, postID, postsCount, ref, ref1, ref2, ref3, seconds, threadID;
if (this !== QR.req) {
return;
}
@@ -25071,12 +25194,17 @@ QR = (function() {
}
} else if ((connErr = !this.response || this.response.title !== 'Post successful!')) {
err = QR.connectionError();
- if (QR.currentCaptcha) {
+ if (QR.captcha === Captcha.v2 && QR.currentCaptcha) {
Captcha.cache.save(QR.currentCaptcha);
}
} else if (this.status !== 200) {
err = "Error " + this.statusText + " (" + this.status + ")";
}
+ if (!connErr) {
+ if (typeof (base = QR.captcha).setUsed === "function") {
+ base.setUsed();
+ }
+ }
delete QR.currentCaptcha;
if (err) {
QR.errorCount = (QR.errorCount || 0) + 1;
@@ -25197,7 +25325,7 @@ QR = (function() {
if ((oldReq = QR.req) && !QR.req.isUploadFinished) {
delete QR.req;
oldReq.abort();
- if (QR.currentCaptcha) {
+ if (QR.captcha === Captcha.v2 && QR.currentCaptcha) {
Captcha.cache.save(QR.currentCaptcha);
}
delete QR.currentCaptcha;
@@ -25853,7 +25981,7 @@ QR = (function() {
}
_Class.prototype.rm = function() {
- var index;
+ var base, index;
this["delete"]();
index = QR.posts.indexOf(this);
if (QR.posts.length === 1) {
@@ -25863,7 +25991,8 @@ QR = (function() {
(QR.posts[index - 1] || QR.posts[index + 1]).select();
}
QR.posts.splice(index, 1);
- return QR.status();
+ QR.status();
+ return typeof (base = QR.captcha).updateThread === "function" ? base.updateThread() : void 0;
};
_Class.prototype["delete"] = function() {
@@ -25928,7 +26057,7 @@ QR = (function() {
};
_Class.prototype.save = function(input, forced) {
- var name, prev;
+ var base, name, prev;
if (input.type === 'checkbox') {
this.spoiler = input.checked;
return;
@@ -25943,6 +26072,9 @@ QR = (function() {
case 'thread':
(this.thread !== 'new' ? $.addClass : $.rmClass)(QR.nodes.el, 'reply-to-thread');
QR.status();
+ if (typeof (base = QR.captcha).updateThread === "function") {
+ base.updateThread();
+ }
break;
case 'com':
this.updateComment();
@@ -26003,7 +26135,9 @@ QR = (function() {
}
this.nodes.span.textContent = this.com;
QR.captcha.moreNeeded();
- return Captcha.cache.prerequest();
+ if (QR.captcha === Captcha.v2) {
+ return Captcha.cache.prerequest();
+ }
};
_Class.prototype.isOnlyQuotes = function() {
@@ -26335,7 +26469,7 @@ QR = (function() {
};
_Class.prototype.drop = function() {
- var el, index, newIndex, oldIndex, post;
+ var base, el, index, newIndex, oldIndex, post;
$.rmClass(this, 'over');
if (!this.draggable) {
return;
@@ -26352,7 +26486,8 @@ QR = (function() {
(oldIndex < newIndex ? $.after : $.before)(this, el);
post = QR.posts.splice(oldIndex, 1)[0];
QR.posts.splice(newIndex, 0, post);
- return QR.status();
+ QR.status();
+ return typeof (base = QR.captcha).updateThread === "function" ? base.updateThread() : void 0;
};
return _Class;
diff --git a/builds/4chan-X-noupdate.crx b/builds/4chan-X-noupdate.crx
index b639cca4e..5e06564da 100644
Binary files a/builds/4chan-X-noupdate.crx and b/builds/4chan-X-noupdate.crx differ
diff --git a/builds/4chan-X-noupdate.user.js b/builds/4chan-X-noupdate.user.js
index 4258ca1ab..f3a1df160 100644
--- a/builds/4chan-X-noupdate.user.js
+++ b/builds/4chan-X-noupdate.user.js
@@ -1,6 +1,6 @@
// ==UserScript==
// @name 4chan X
-// @version 1.14.21.3
+// @version 1.14.21.5
// @minGMVer 1.14
// @minFFVer 26
// @namespace 4chan-X
@@ -218,7 +218,7 @@ docSet = function() {
};
g = {
- VERSION: '1.14.21.3',
+ VERSION: '1.14.21.5',
NAMESPACE: '4chan X.',
sites: Object.create(null),
boards: Object.create(null)
@@ -23732,6 +23732,115 @@ Captcha = {};
}).call(this);
+(function() {
+ Captcha.t = {
+ init: function() {
+ var root;
+ if (d.cookie.indexOf('pass_enabled=1') >= 0) {
+ return;
+ }
+ if (!(this.isEnabled = !!$('#t-root') || !$.id('postForm'))) {
+ return;
+ }
+ root = $.el('div', {
+ className: 'captcha-root'
+ });
+ this.nodes = {
+ root: root
+ };
+ $.addClass(QR.nodes.el, 'has-captcha', 'captcha-t');
+ return $.after(QR.nodes.com.parentNode, root);
+ },
+ moreNeeded: function() {},
+ getThread: function() {
+ var boardID, threadID;
+ boardID = g.BOARD.ID;
+ if (QR.posts[0].thread === 'new') {
+ threadID = '0';
+ } else {
+ threadID = '' + QR.posts[0].thread;
+ }
+ return {
+ boardID: boardID,
+ threadID: threadID
+ };
+ },
+ setup: function(focus) {
+ if (!this.isEnabled) {
+ return;
+ }
+ if (!this.nodes.container) {
+ this.nodes.container = $.el('div', {
+ className: 'captcha-container'
+ });
+ $.prepend(this.nodes.root, this.nodes.container);
+ Captcha.t.currentThread = Captcha.t.getThread();
+ $.global(function() {
+ var el;
+ el = document.querySelector('#qr .captcha-container');
+ window.TCaptcha.init(el, this.boardID, +this.threadID);
+ return window.TCaptcha.setErrorCb(function(err) {
+ return window.dispatchEvent(new CustomEvent('CreateNotification', {
+ detail: {
+ type: 'warning',
+ content: '' + err
+ }
+ }));
+ });
+ }, Captcha.t.currentThread);
+ }
+ if (focus) {
+ return $('#t-resp').focus();
+ }
+ },
+ destroy: function() {
+ if (!(this.isEnabled && this.nodes.container)) {
+ return;
+ }
+ $.global(function() {
+ return window.TCaptcha.destroy();
+ });
+ $.rm(this.nodes.container);
+ return delete this.nodes.container;
+ },
+ updateThread: function() {
+ var boardID, newThread, ref, threadID;
+ ref = Captcha.t.currentThread, boardID = ref.boardID, threadID = ref.threadID;
+ newThread = Captcha.t.getThread();
+ if (!(newThread.boardID === boardID && newThread.threadID === threadID)) {
+ Captcha.t.destroy();
+ return Captcha.t.setup();
+ }
+ },
+ getOne: function() {
+ var i, key, len, ref, response;
+ response = {};
+ if (this.nodes.container) {
+ ref = ['t-response', 't-challenge'];
+ for (i = 0, len = ref.length; i < len; i++) {
+ key = ref[i];
+ response[key] = $("[name='" + key + "']", this.nodes.container).value;
+ }
+ }
+ if (!response['t-response']) {
+ response = null;
+ }
+ return response;
+ },
+ setUsed: function() {
+ if (this.nodes.container) {
+ return $.global(function() {
+ return window.TCaptcha.clearChallenge();
+ });
+ }
+ },
+ occupied: function() {
+ return !!this.nodes.container;
+ }
+ };
+
+}).call(this);
+
(function() {
var indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
@@ -24158,7 +24267,6 @@ QR = (function() {
return;
}
this.posts = [];
- this.captcha = Captcha.v2;
$.on(d, '4chanXInitFinished', function() {
return BoardConfig.ready(QR.initReady);
});
@@ -24186,7 +24294,9 @@ QR = (function() {
return Header.addShortcut('qr', sc, 540);
},
initReady: function() {
- var config, link, linkBot, navLinksBot, origToggle, prop;
+ var captchaVersion, config, link, linkBot, navLinksBot, origToggle, prop;
+ captchaVersion = $('#t-root') ? 't' : 'v2';
+ QR.captcha = Captcha[captchaVersion];
QR.postingIsEnabled = true;
config = g.BOARD.config;
prop = function(key, def) {
@@ -24964,8 +25074,11 @@ QR = (function() {
if (g.BOARD.ID === 'r9k' && !((ref = post.com) != null ? ref.match(/[a-z-]/i) : void 0)) {
err || (err = 'Original comment required.');
}
- if (QR.captcha.isEnabled && !(/\b_ct=/.test(d.cookie) && threadID) && !(err && !force)) {
- captcha = QR.captcha.getOne(!!threadID) || Captcha.cache.request(!!threadID);
+ if (QR.captcha.isEnabled && !(QR.captcha === Captcha.v2 && /\b_ct=/.test(d.cookie) && threadID) && !(err && !force)) {
+ captcha = QR.captcha.getOne(!!threadID);
+ if (QR.captcha === Captcha.v2) {
+ captcha || (captcha = Captcha.cache.request(!!threadID));
+ }
if (!captcha) {
err = 'No valid captcha.';
QR.captcha.setup(!QR.cooldown.auto || d.activeElement === QR.nodes.status);
@@ -25015,13 +25128,21 @@ QR = (function() {
};
}
cb = function(response) {
+ var key, val;
if (response != null) {
QR.currentCaptcha = response;
- if (response.challenge != null) {
- options.form.append('recaptcha_challenge_field', response.challenge);
- options.form.append('recaptcha_response_field', response.response);
+ if (QR.captcha === Captcha.v2) {
+ if (response.challenge != null) {
+ options.form.append('recaptcha_challenge_field', response.challenge);
+ options.form.append('recaptcha_response_field', response.response);
+ } else {
+ options.form.append('g-recaptcha-response', response.response);
+ }
} else {
- options.form.append('g-recaptcha-response', response.response);
+ for (key in response) {
+ val = response[key];
+ options.form.append(key, val);
+ }
}
}
QR.req = $.ajax("https://sys." + (location.hostname.split('.')[1]) + ".org/" + g.BOARD + "/post", options);
@@ -25031,12 +25152,14 @@ QR = (function() {
QR.req = {
progress: '...',
abort: function() {
- Captcha.cache.abort();
+ if (QR.captcha === Captcha.v2) {
+ Captcha.cache.abort();
+ }
return cb = null;
}
};
captcha(function(response) {
- if (Captcha.cache.haveCookie()) {
+ if (QR.captcha === Captcha.v2 && Captcha.cache.haveCookie()) {
if (typeof cb === "function") {
cb();
}
@@ -25058,7 +25181,7 @@ QR = (function() {
return QR.status();
},
response: function() {
- var URL, _, connErr, err, h1, isReply, j, lastPostToThread, len, m, mi, open, post, postID, postsCount, ref, ref1, ref2, ref3, seconds, threadID;
+ var URL, _, base, connErr, err, h1, isReply, j, lastPostToThread, len, m, mi, open, post, postID, postsCount, ref, ref1, ref2, ref3, seconds, threadID;
if (this !== QR.req) {
return;
}
@@ -25071,12 +25194,17 @@ QR = (function() {
}
} else if ((connErr = !this.response || this.response.title !== 'Post successful!')) {
err = QR.connectionError();
- if (QR.currentCaptcha) {
+ if (QR.captcha === Captcha.v2 && QR.currentCaptcha) {
Captcha.cache.save(QR.currentCaptcha);
}
} else if (this.status !== 200) {
err = "Error " + this.statusText + " (" + this.status + ")";
}
+ if (!connErr) {
+ if (typeof (base = QR.captcha).setUsed === "function") {
+ base.setUsed();
+ }
+ }
delete QR.currentCaptcha;
if (err) {
QR.errorCount = (QR.errorCount || 0) + 1;
@@ -25197,7 +25325,7 @@ QR = (function() {
if ((oldReq = QR.req) && !QR.req.isUploadFinished) {
delete QR.req;
oldReq.abort();
- if (QR.currentCaptcha) {
+ if (QR.captcha === Captcha.v2 && QR.currentCaptcha) {
Captcha.cache.save(QR.currentCaptcha);
}
delete QR.currentCaptcha;
@@ -25853,7 +25981,7 @@ QR = (function() {
}
_Class.prototype.rm = function() {
- var index;
+ var base, index;
this["delete"]();
index = QR.posts.indexOf(this);
if (QR.posts.length === 1) {
@@ -25863,7 +25991,8 @@ QR = (function() {
(QR.posts[index - 1] || QR.posts[index + 1]).select();
}
QR.posts.splice(index, 1);
- return QR.status();
+ QR.status();
+ return typeof (base = QR.captcha).updateThread === "function" ? base.updateThread() : void 0;
};
_Class.prototype["delete"] = function() {
@@ -25928,7 +26057,7 @@ QR = (function() {
};
_Class.prototype.save = function(input, forced) {
- var name, prev;
+ var base, name, prev;
if (input.type === 'checkbox') {
this.spoiler = input.checked;
return;
@@ -25943,6 +26072,9 @@ QR = (function() {
case 'thread':
(this.thread !== 'new' ? $.addClass : $.rmClass)(QR.nodes.el, 'reply-to-thread');
QR.status();
+ if (typeof (base = QR.captcha).updateThread === "function") {
+ base.updateThread();
+ }
break;
case 'com':
this.updateComment();
@@ -26003,7 +26135,9 @@ QR = (function() {
}
this.nodes.span.textContent = this.com;
QR.captcha.moreNeeded();
- return Captcha.cache.prerequest();
+ if (QR.captcha === Captcha.v2) {
+ return Captcha.cache.prerequest();
+ }
};
_Class.prototype.isOnlyQuotes = function() {
@@ -26335,7 +26469,7 @@ QR = (function() {
};
_Class.prototype.drop = function() {
- var el, index, newIndex, oldIndex, post;
+ var base, el, index, newIndex, oldIndex, post;
$.rmClass(this, 'over');
if (!this.draggable) {
return;
@@ -26352,7 +26486,8 @@ QR = (function() {
(oldIndex < newIndex ? $.after : $.before)(this, el);
post = QR.posts.splice(oldIndex, 1)[0];
QR.posts.splice(newIndex, 0, post);
- return QR.status();
+ QR.status();
+ return typeof (base = QR.captcha).updateThread === "function" ? base.updateThread() : void 0;
};
return _Class;
diff --git a/builds/4chan-X.crx b/builds/4chan-X.crx
index 30c57bd0a..e363c3fa9 100644
Binary files a/builds/4chan-X.crx and b/builds/4chan-X.crx differ
diff --git a/builds/4chan-X.meta.js b/builds/4chan-X.meta.js
index 71ec614d4..1294f04f6 100644
--- a/builds/4chan-X.meta.js
+++ b/builds/4chan-X.meta.js
@@ -1,6 +1,6 @@
// ==UserScript==
// @name 4chan X
-// @version 1.14.21.3
+// @version 1.14.21.5
// @minGMVer 1.14
// @minFFVer 26
// @namespace 4chan-X
diff --git a/builds/4chan-X.user.js b/builds/4chan-X.user.js
index 40e397241..28f27b257 100644
--- a/builds/4chan-X.user.js
+++ b/builds/4chan-X.user.js
@@ -1,6 +1,6 @@
// ==UserScript==
// @name 4chan X
-// @version 1.14.21.3
+// @version 1.14.21.5
// @minGMVer 1.14
// @minFFVer 26
// @namespace 4chan-X
@@ -218,7 +218,7 @@ docSet = function() {
};
g = {
- VERSION: '1.14.21.3',
+ VERSION: '1.14.21.5',
NAMESPACE: '4chan X.',
sites: Object.create(null),
boards: Object.create(null)
@@ -23732,6 +23732,115 @@ Captcha = {};
}).call(this);
+(function() {
+ Captcha.t = {
+ init: function() {
+ var root;
+ if (d.cookie.indexOf('pass_enabled=1') >= 0) {
+ return;
+ }
+ if (!(this.isEnabled = !!$('#t-root') || !$.id('postForm'))) {
+ return;
+ }
+ root = $.el('div', {
+ className: 'captcha-root'
+ });
+ this.nodes = {
+ root: root
+ };
+ $.addClass(QR.nodes.el, 'has-captcha', 'captcha-t');
+ return $.after(QR.nodes.com.parentNode, root);
+ },
+ moreNeeded: function() {},
+ getThread: function() {
+ var boardID, threadID;
+ boardID = g.BOARD.ID;
+ if (QR.posts[0].thread === 'new') {
+ threadID = '0';
+ } else {
+ threadID = '' + QR.posts[0].thread;
+ }
+ return {
+ boardID: boardID,
+ threadID: threadID
+ };
+ },
+ setup: function(focus) {
+ if (!this.isEnabled) {
+ return;
+ }
+ if (!this.nodes.container) {
+ this.nodes.container = $.el('div', {
+ className: 'captcha-container'
+ });
+ $.prepend(this.nodes.root, this.nodes.container);
+ Captcha.t.currentThread = Captcha.t.getThread();
+ $.global(function() {
+ var el;
+ el = document.querySelector('#qr .captcha-container');
+ window.TCaptcha.init(el, this.boardID, +this.threadID);
+ return window.TCaptcha.setErrorCb(function(err) {
+ return window.dispatchEvent(new CustomEvent('CreateNotification', {
+ detail: {
+ type: 'warning',
+ content: '' + err
+ }
+ }));
+ });
+ }, Captcha.t.currentThread);
+ }
+ if (focus) {
+ return $('#t-resp').focus();
+ }
+ },
+ destroy: function() {
+ if (!(this.isEnabled && this.nodes.container)) {
+ return;
+ }
+ $.global(function() {
+ return window.TCaptcha.destroy();
+ });
+ $.rm(this.nodes.container);
+ return delete this.nodes.container;
+ },
+ updateThread: function() {
+ var boardID, newThread, ref, threadID;
+ ref = Captcha.t.currentThread, boardID = ref.boardID, threadID = ref.threadID;
+ newThread = Captcha.t.getThread();
+ if (!(newThread.boardID === boardID && newThread.threadID === threadID)) {
+ Captcha.t.destroy();
+ return Captcha.t.setup();
+ }
+ },
+ getOne: function() {
+ var i, key, len, ref, response;
+ response = {};
+ if (this.nodes.container) {
+ ref = ['t-response', 't-challenge'];
+ for (i = 0, len = ref.length; i < len; i++) {
+ key = ref[i];
+ response[key] = $("[name='" + key + "']", this.nodes.container).value;
+ }
+ }
+ if (!response['t-response']) {
+ response = null;
+ }
+ return response;
+ },
+ setUsed: function() {
+ if (this.nodes.container) {
+ return $.global(function() {
+ return window.TCaptcha.clearChallenge();
+ });
+ }
+ },
+ occupied: function() {
+ return !!this.nodes.container;
+ }
+ };
+
+}).call(this);
+
(function() {
var indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
@@ -24158,7 +24267,6 @@ QR = (function() {
return;
}
this.posts = [];
- this.captcha = Captcha.v2;
$.on(d, '4chanXInitFinished', function() {
return BoardConfig.ready(QR.initReady);
});
@@ -24186,7 +24294,9 @@ QR = (function() {
return Header.addShortcut('qr', sc, 540);
},
initReady: function() {
- var config, link, linkBot, navLinksBot, origToggle, prop;
+ var captchaVersion, config, link, linkBot, navLinksBot, origToggle, prop;
+ captchaVersion = $('#t-root') ? 't' : 'v2';
+ QR.captcha = Captcha[captchaVersion];
QR.postingIsEnabled = true;
config = g.BOARD.config;
prop = function(key, def) {
@@ -24964,8 +25074,11 @@ QR = (function() {
if (g.BOARD.ID === 'r9k' && !((ref = post.com) != null ? ref.match(/[a-z-]/i) : void 0)) {
err || (err = 'Original comment required.');
}
- if (QR.captcha.isEnabled && !(/\b_ct=/.test(d.cookie) && threadID) && !(err && !force)) {
- captcha = QR.captcha.getOne(!!threadID) || Captcha.cache.request(!!threadID);
+ if (QR.captcha.isEnabled && !(QR.captcha === Captcha.v2 && /\b_ct=/.test(d.cookie) && threadID) && !(err && !force)) {
+ captcha = QR.captcha.getOne(!!threadID);
+ if (QR.captcha === Captcha.v2) {
+ captcha || (captcha = Captcha.cache.request(!!threadID));
+ }
if (!captcha) {
err = 'No valid captcha.';
QR.captcha.setup(!QR.cooldown.auto || d.activeElement === QR.nodes.status);
@@ -25015,13 +25128,21 @@ QR = (function() {
};
}
cb = function(response) {
+ var key, val;
if (response != null) {
QR.currentCaptcha = response;
- if (response.challenge != null) {
- options.form.append('recaptcha_challenge_field', response.challenge);
- options.form.append('recaptcha_response_field', response.response);
+ if (QR.captcha === Captcha.v2) {
+ if (response.challenge != null) {
+ options.form.append('recaptcha_challenge_field', response.challenge);
+ options.form.append('recaptcha_response_field', response.response);
+ } else {
+ options.form.append('g-recaptcha-response', response.response);
+ }
} else {
- options.form.append('g-recaptcha-response', response.response);
+ for (key in response) {
+ val = response[key];
+ options.form.append(key, val);
+ }
}
}
QR.req = $.ajax("https://sys." + (location.hostname.split('.')[1]) + ".org/" + g.BOARD + "/post", options);
@@ -25031,12 +25152,14 @@ QR = (function() {
QR.req = {
progress: '...',
abort: function() {
- Captcha.cache.abort();
+ if (QR.captcha === Captcha.v2) {
+ Captcha.cache.abort();
+ }
return cb = null;
}
};
captcha(function(response) {
- if (Captcha.cache.haveCookie()) {
+ if (QR.captcha === Captcha.v2 && Captcha.cache.haveCookie()) {
if (typeof cb === "function") {
cb();
}
@@ -25058,7 +25181,7 @@ QR = (function() {
return QR.status();
},
response: function() {
- var URL, _, connErr, err, h1, isReply, j, lastPostToThread, len, m, mi, open, post, postID, postsCount, ref, ref1, ref2, ref3, seconds, threadID;
+ var URL, _, base, connErr, err, h1, isReply, j, lastPostToThread, len, m, mi, open, post, postID, postsCount, ref, ref1, ref2, ref3, seconds, threadID;
if (this !== QR.req) {
return;
}
@@ -25071,12 +25194,17 @@ QR = (function() {
}
} else if ((connErr = !this.response || this.response.title !== 'Post successful!')) {
err = QR.connectionError();
- if (QR.currentCaptcha) {
+ if (QR.captcha === Captcha.v2 && QR.currentCaptcha) {
Captcha.cache.save(QR.currentCaptcha);
}
} else if (this.status !== 200) {
err = "Error " + this.statusText + " (" + this.status + ")";
}
+ if (!connErr) {
+ if (typeof (base = QR.captcha).setUsed === "function") {
+ base.setUsed();
+ }
+ }
delete QR.currentCaptcha;
if (err) {
QR.errorCount = (QR.errorCount || 0) + 1;
@@ -25197,7 +25325,7 @@ QR = (function() {
if ((oldReq = QR.req) && !QR.req.isUploadFinished) {
delete QR.req;
oldReq.abort();
- if (QR.currentCaptcha) {
+ if (QR.captcha === Captcha.v2 && QR.currentCaptcha) {
Captcha.cache.save(QR.currentCaptcha);
}
delete QR.currentCaptcha;
@@ -25853,7 +25981,7 @@ QR = (function() {
}
_Class.prototype.rm = function() {
- var index;
+ var base, index;
this["delete"]();
index = QR.posts.indexOf(this);
if (QR.posts.length === 1) {
@@ -25863,7 +25991,8 @@ QR = (function() {
(QR.posts[index - 1] || QR.posts[index + 1]).select();
}
QR.posts.splice(index, 1);
- return QR.status();
+ QR.status();
+ return typeof (base = QR.captcha).updateThread === "function" ? base.updateThread() : void 0;
};
_Class.prototype["delete"] = function() {
@@ -25928,7 +26057,7 @@ QR = (function() {
};
_Class.prototype.save = function(input, forced) {
- var name, prev;
+ var base, name, prev;
if (input.type === 'checkbox') {
this.spoiler = input.checked;
return;
@@ -25943,6 +26072,9 @@ QR = (function() {
case 'thread':
(this.thread !== 'new' ? $.addClass : $.rmClass)(QR.nodes.el, 'reply-to-thread');
QR.status();
+ if (typeof (base = QR.captcha).updateThread === "function") {
+ base.updateThread();
+ }
break;
case 'com':
this.updateComment();
@@ -26003,7 +26135,9 @@ QR = (function() {
}
this.nodes.span.textContent = this.com;
QR.captcha.moreNeeded();
- return Captcha.cache.prerequest();
+ if (QR.captcha === Captcha.v2) {
+ return Captcha.cache.prerequest();
+ }
};
_Class.prototype.isOnlyQuotes = function() {
@@ -26335,7 +26469,7 @@ QR = (function() {
};
_Class.prototype.drop = function() {
- var el, index, newIndex, oldIndex, post;
+ var base, el, index, newIndex, oldIndex, post;
$.rmClass(this, 'over');
if (!this.draggable) {
return;
@@ -26352,7 +26486,8 @@ QR = (function() {
(oldIndex < newIndex ? $.after : $.before)(this, el);
post = QR.posts.splice(oldIndex, 1)[0];
QR.posts.splice(newIndex, 0, post);
- return QR.status();
+ QR.status();
+ return typeof (base = QR.captcha).updateThread === "function" ? base.updateThread() : void 0;
};
return _Class;
diff --git a/builds/4chan-X.zip b/builds/4chan-X.zip
index f908ce4c6..ecf1fed6f 100644
Binary files a/builds/4chan-X.zip and b/builds/4chan-X.zip differ
diff --git a/builds/updates-beta.json b/builds/updates-beta.json
index fbf5149d4..a89702610 100644
--- a/builds/updates-beta.json
+++ b/builds/updates-beta.json
@@ -3,7 +3,7 @@
"4chan-x@4chan-x.net": {
"updates": [
{
- "version": "1.14.21.3",
+ "version": "1.14.21.5",
"update_link": "https://www.4chan-x.net/builds/4chan-X-beta.crx"
}
]
diff --git a/builds/updates-beta.xml b/builds/updates-beta.xml
index 513cc85d0..3c1389d81 100644
--- a/builds/updates-beta.xml
+++ b/builds/updates-beta.xml
@@ -1,7 +1,7 @@
-
+
diff --git a/builds/updates.json b/builds/updates.json
index 75215e77d..44c6733e6 100644
--- a/builds/updates.json
+++ b/builds/updates.json
@@ -3,7 +3,7 @@
"4chan-x@4chan-x.net": {
"updates": [
{
- "version": "1.14.21.3",
+ "version": "1.14.21.5",
"update_link": "https://www.4chan-x.net/builds/4chan-X.crx"
}
]
diff --git a/builds/updates.xml b/builds/updates.xml
index 1117a6594..d54173130 100644
--- a/builds/updates.xml
+++ b/builds/updates.xml
@@ -1,7 +1,7 @@
-
+
diff --git a/src/Posting/Captcha.t.coffee b/src/Posting/Captcha.t.coffee
new file mode 100644
index 000000000..954b23fd7
--- /dev/null
+++ b/src/Posting/Captcha.t.coffee
@@ -0,0 +1,72 @@
+Captcha.t =
+ init: ->
+ return if d.cookie.indexOf('pass_enabled=1') >= 0
+ return if not (@isEnabled = !!$('#t-root') or !$.id('postForm'))
+
+ root = $.el 'div', className: 'captcha-root'
+ @nodes = {root}
+
+ $.addClass QR.nodes.el, 'has-captcha', 'captcha-t'
+ $.after QR.nodes.com.parentNode, root
+
+ moreNeeded: ->
+ return
+
+ getThread: ->
+ boardID = g.BOARD.ID
+ if QR.posts[0].thread is 'new'
+ threadID = '0'
+ else
+ threadID = '' + QR.posts[0].thread
+ {boardID, threadID}
+
+ setup: (focus) ->
+ return unless @isEnabled
+
+ if !@nodes.container
+ @nodes.container = $.el 'div', className: 'captcha-container'
+ $.prepend @nodes.root, @nodes.container
+ Captcha.t.currentThread = Captcha.t.getThread()
+ $.global ->
+ el = document.querySelector '#qr .captcha-container'
+ window.TCaptcha.init el, @boardID, +@threadID
+ window.TCaptcha.setErrorCb (err) ->
+ window.dispatchEvent new CustomEvent('CreateNotification', {detail: {
+ type: 'warning',
+ content: '' + err
+ }})
+ , Captcha.t.currentThread
+
+ if focus
+ $('#t-resp').focus()
+
+ destroy: ->
+ return unless @isEnabled and @nodes.container
+ $.global ->
+ window.TCaptcha.destroy()
+ $.rm @nodes.container
+ delete @nodes.container
+
+ updateThread: ->
+ {boardID, threadID} = Captcha.t.currentThread
+ newThread = Captcha.t.getThread()
+ unless newThread.boardID is boardID and newThread.threadID is threadID
+ Captcha.t.destroy()
+ Captcha.t.setup()
+
+ getOne: ->
+ response = {}
+ if @nodes.container
+ for key in ['t-response', 't-challenge']
+ response[key] = $("[name='#{key}']", @nodes.container).value
+ if !response['t-response']
+ response = null
+ response
+
+ setUsed: ->
+ if @nodes.container
+ $.global ->
+ window.TCaptcha.clearChallenge()
+
+ occupied: ->
+ !!@nodes.container
diff --git a/src/Posting/QR.coffee b/src/Posting/QR.coffee
index fa50ceee0..0b5ee1c0d 100644
--- a/src/Posting/QR.coffee
+++ b/src/Posting/QR.coffee
@@ -26,8 +26,6 @@ QR =
@posts = []
- @captcha = Captcha.v2
-
$.on d, '4chanXInitFinished', -> BoardConfig.ready QR.initReady
Callbacks.Post.push
@@ -50,6 +48,8 @@ QR =
Header.addShortcut 'qr', sc, 540
initReady: ->
+ captchaVersion = if $('#t-root') then 't' else 'v2'
+ QR.captcha = Captcha[captchaVersion]
QR.postingIsEnabled = true
{config} = g.BOARD
@@ -684,8 +684,10 @@ QR =
if g.BOARD.ID is 'r9k' and !post.com?.match(/[a-z-]/i)
err or= 'Original comment required.'
- if QR.captcha.isEnabled and !(/\b_ct=/.test(d.cookie) and threadID) and !(err and !force)
- captcha = QR.captcha.getOne(!!threadID) or Captcha.cache.request(!!threadID)
+ if QR.captcha.isEnabled and !(QR.captcha is Captcha.v2 and /\b_ct=/.test(d.cookie) and threadID) and !(err and !force)
+ captcha = QR.captcha.getOne(!!threadID)
+ if QR.captcha is Captcha.v2
+ captcha or= Captcha.cache.request(!!threadID)
unless captcha
err = 'No valid captcha.'
QR.captcha.setup(!QR.cooldown.auto or d.activeElement is QR.nodes.status)
@@ -736,11 +738,15 @@ QR =
cb = (response) ->
if response?
QR.currentCaptcha = response
- if response.challenge?
- options.form.append 'recaptcha_challenge_field', response.challenge
- options.form.append 'recaptcha_response_field', response.response
+ if QR.captcha is Captcha.v2
+ if response.challenge?
+ options.form.append 'recaptcha_challenge_field', response.challenge
+ options.form.append 'recaptcha_response_field', response.response
+ else
+ options.form.append 'g-recaptcha-response', response.response
else
- options.form.append 'g-recaptcha-response', response.response
+ for key, val of response
+ options.form.append key, val
QR.req = $.ajax "https://sys.#{location.hostname.split('.')[1]}.org/#{g.BOARD}/post", options
QR.req.progress = '...'
@@ -749,10 +755,11 @@ QR =
QR.req =
progress: '...'
abort: ->
- Captcha.cache.abort()
+ if QR.captcha is Captcha.v2
+ Captcha.cache.abort()
cb = null
captcha (response) ->
- if Captcha.cache.haveCookie()
+ if QR.captcha is Captcha.v2 and Captcha.cache.haveCookie()
cb?()
Captcha.cache.save response if response
else if response
@@ -780,10 +787,11 @@ QR =
$('a', err)?.target = '_blank' # duplicate image link
else if (connErr = (!@response or @response.title isnt 'Post successful!'))
err = QR.connectionError()
- Captcha.cache.save QR.currentCaptcha if QR.currentCaptcha
+ Captcha.cache.save QR.currentCaptcha if QR.captcha is Captcha.v2 and QR.currentCaptcha
else if @status isnt 200
err = "Error #{@statusText} (#{@status})"
+ QR.captcha.setUsed?() unless connErr
delete QR.currentCaptcha
if err
@@ -901,7 +909,7 @@ QR =
if (oldReq = QR.req) and !QR.req.isUploadFinished
delete QR.req
oldReq.abort()
- Captcha.cache.save QR.currentCaptcha if QR.currentCaptcha
+ Captcha.cache.save QR.currentCaptcha if QR.captcha is Captcha.v2 and QR.currentCaptcha
delete QR.currentCaptcha
QR.posts[0].unlock()
QR.cooldown.auto = false
diff --git a/src/Posting/QR.post.coffee b/src/Posting/QR.post.coffee
index c0b376be2..a658a82a2 100644
--- a/src/Posting/QR.post.coffee
+++ b/src/Posting/QR.post.coffee
@@ -74,6 +74,7 @@ QR.post = class
(QR.posts[index-1] or QR.posts[index+1]).select()
QR.posts.splice index, 1
QR.status()
+ QR.captcha.updateThread?()
delete: ->
$.rm @nodes.el
@@ -129,6 +130,7 @@ QR.post = class
when 'thread'
(if @thread isnt 'new' then $.addClass else $.rmClass) QR.nodes.el, 'reply-to-thread'
QR.status()
+ QR.captcha.updateThread?()
when 'com'
@updateComment()
when 'filename'
@@ -167,7 +169,8 @@ QR.post = class
QR.characterCount()
@nodes.span.textContent = @com
QR.captcha.moreNeeded()
- Captcha.cache.prerequest()
+ if QR.captcha is Captcha.v2
+ Captcha.cache.prerequest()
isOnlyQuotes: ->
(@com or '').trim() is (@quotedText or '').trim()
@@ -402,3 +405,4 @@ QR.post = class
post = QR.posts.splice(oldIndex, 1)[0]
QR.posts.splice newIndex, 0, post
QR.status()
+ QR.captcha.updateThread?()
diff --git a/version.json b/version.json
index 2867a2ecf..0a7374711 100644
--- a/version.json
+++ b/version.json
@@ -1,4 +1,4 @@
{
- "version": "1.14.21.3",
- "date": "2021-05-07T07:49:08.122Z"
+ "version": "1.14.21.5",
+ "date": "2021-07-07T06:16:45.892Z"
}
\ No newline at end of file