Release 4chan X v1.11.19.0.

This commit is contained in:
ccd0 2015-11-29 17:28:38 -08:00
parent 07ece0b7ee
commit 6995f98834
13 changed files with 251 additions and 333 deletions

View File

@ -2,6 +2,14 @@
Sometimes the changelog has notes (not comprehensive) acknowledging people's work. This does not mean the changes are their fault, only that their code was used. All changes to the script are chosen by and the fault of the maintainer (ccd0).
### v1.11.19
**v1.11.19.0** *(2015-11-29)* - [[Firefox](https://raw.githubusercontent.com/ccd0/4chan-x/1.11.19.0/builds/4chan-X-noupdate.user.js "Firefox version")] [[Chromium](https://raw.githubusercontent.com/ccd0/4chan-x/1.11.19.0/builds/4chan-X-noupdate.crx "Chromium version")]
- Based on v1.11.18.7.
- Add preference `Remember Last Read Post` (on by default). Turning this off disables 4chan X recording your place in threads.
- Turning off `Mark Quotes of You` should now turn off recording your post history immediately in all tabs. Turning it back on again may require a refresh.
- Again try removing the measure of preventing all scrolling while the captcha is focused. If you encounter anomalous scrolling while using the v2 captcha, please report it.
### v1.11.18
**v1.11.18.7** *(2015-11-28)* - [[Firefox](https://raw.githubusercontent.com/ccd0/4chan-x/1.11.18.7/builds/4chan-X-noupdate.user.js "Firefox version")] [[Chromium](https://raw.githubusercontent.com/ccd0/4chan-x/1.11.18.7/builds/4chan-X-noupdate.crx "Chromium version")]

Binary file not shown.

View File

@ -1,6 +1,6 @@
// ==UserScript==
// @name 4chan X beta
// @version 1.11.18.7
// @version 1.11.19.0
// @minGMVer 1.14
// @minFFVer 26
// @namespace 4chan-X

View File

@ -1,7 +1,7 @@
// Generated by CoffeeScript
// ==UserScript==
// @name 4chan X beta
// @version 1.11.18.7
// @version 1.11.19.0
// @minGMVer 1.14
// @minFFVer 26
// @namespace 4chan-X
@ -216,7 +216,8 @@
'Hide Unread Count at (0)': [false, 'Hide the unread posts count in the tab title when it reaches 0.', 1],
'Unread Favicon': [true, 'Show a different favicon when there are unread posts.'],
'Unread Line': [true, 'Show a line to distinguish read posts from unread ones.'],
'Scroll to Last Read Post': [true, 'Scroll back to the last read post when reopening a thread.'],
'Remember Last Read Post': [true, 'Remember how far you\'ve read after you close the thread.'],
'Scroll to Last Read Post': [true, 'Scroll back to the last read post when reopening a thread.', 1],
'Thread Excerpt': [true, 'Show an excerpt of the thread in the tab title for threads in /f/.'],
'Remove Thread Excerpt': [false, 'Replace the excerpt of the thread in the tab title with the board title.'],
'Thread Stats': [true, 'Display reply and image count.'],
@ -432,7 +433,7 @@
doc = d.documentElement;
g = {
VERSION: '1.11.18.7',
VERSION: '1.11.19.0',
NAMESPACE: '4chan X.',
boards: {}
};
@ -6157,15 +6158,15 @@
});
},
firstNode: function() {
var a, clone, container, containers, hash, k, len1, len2, len3, link, markYours, nodes, post, q, quote, ref, ref1, u;
var a, clone, container, containers, hash, k, len1, len2, len3, link, markYours, nodes, post, q, quote, ref, ref1, ref2, u;
if (this.isClone || !this.quotes.length || this.isRebuilt) {
return;
}
markYours = Conf['Quick Reply'] && Conf['Mark Quotes of You'] && QR.db.get({
markYours = (ref = QR.db) != null ? ref.get({
boardID: this.board.ID,
threadID: this.thread.ID,
postID: this.ID
});
}) : void 0;
a = $.el('a', {
href: Build.postURL(this.board.ID, this.thread.ID, this.ID),
className: this.isHidden ? 'filtered backlink' : 'backlink',
@ -6178,14 +6179,14 @@
};
})(this)) + (markYours ? '\u00A0(You)' : '')
});
ref = this.quotes;
for (k = 0, len1 = ref.length; k < len1; k++) {
quote = ref[k];
ref1 = this.quotes;
for (k = 0, len1 = ref1.length; k < len1; k++) {
quote = ref1[k];
containers = [QuoteBacklink.getContainer(quote)];
if ((post = g.posts[quote]) && post.nodes.backlinkContainer) {
ref1 = post.clones;
for (q = 0, len2 = ref1.length; q < len2; q++) {
clone = ref1[q];
ref2 = post.clones;
for (q = 0, len2 = ref2.length; q < len2; q++) {
clone = ref2[q];
containers.push(clone.nodes.backlinkContainer);
}
}
@ -6785,9 +6786,6 @@
cb: {
seek: function(type) {
var highlight, post, posts, result, str;
if (!(Conf['Mark Quotes of You'] && Conf['Quick Reply'])) {
return;
}
if (highlight = $('.highlight')) {
$.rmClass(highlight, 'highlight');
}
@ -6965,6 +6963,9 @@
return;
}
if (Conf['Mark Quotes of You']) {
$.sync('Mark Quotes of You', function(enabled) {
return Conf['Mark Quotes of You'] = enabled;
});
this.db = new DataBoard('yourPosts');
}
this.posts = [];
@ -7119,15 +7120,7 @@
return $.queueTask(function() {
if (!QR.inBubble()) {
QR.hasFocus = d.activeElement && QR.nodes.el.contains(d.activeElement);
QR.nodes.el.classList.toggle('focus', QR.hasFocus);
}
if (QR.captcha.isEnabled && QR.captcha === Captcha.v2 && !QR.captcha.noscript) {
if (QR.inCaptcha()) {
QR.scrollY = window.scrollY;
return $.on(d, 'scroll', QR.scrollLock);
} else {
return $.off(d, 'scroll', QR.scrollLock);
}
return QR.nodes.el.classList.toggle('focus', QR.hasFocus);
}
});
},
@ -7138,17 +7131,6 @@
return getComputedStyle(el).visibility !== 'hidden' && el.getBoundingClientRect().bottom > 0;
});
},
inCaptcha: function() {
var ref;
return (((ref = d.activeElement) != null ? ref.nodeName : void 0) === 'IFRAME' && QR.nodes.el.contains(d.activeElement)) || (QR.hasFocus && QR.inBubble());
},
scrollLock: function() {
if (QR.inCaptcha()) {
return window.scroll(window.scrollX, QR.scrollY);
} else {
return $.off(d, 'scroll', QR.scrollLock);
}
},
hide: function() {
d.activeElement.blur();
$.addClass(QR.nodes.el, 'autohide');
@ -7870,13 +7852,16 @@
postID = +postID;
threadID = +threadID || postID;
isReply = threadID !== postID;
if ((ref3 = QR.db) != null) {
ref3.set({
boardID: g.BOARD.ID,
threadID: threadID,
postID: postID,
val: true
});
$.forceSync('Mark Quotes of You');
if (Conf['Mark Quotes of You']) {
if ((ref3 = QR.db) != null) {
ref3.set({
boardID: g.BOARD.ID,
threadID: threadID,
postID: postID,
val: true
});
}
}
$.event('QRPostSuccessful', {
boardID: g.BOARD.ID,
@ -8599,16 +8584,13 @@
return e.stopPropagation();
};
})(this));
$.on(window, 'captcha:success', (function(_this) {
return $.on(window, 'captcha:success', (function(_this) {
return function() {
return $.queueTask(function() {
return _this.save(false);
});
};
})(this));
return new MutationObserver(this.watchBubbles.bind(this)).observe(d.body, {
childList: true
});
},
timeouts: {},
postsCount: 0,
@ -8859,47 +8841,6 @@
} else {
return $.globalEval('(function() {\n var container = document.querySelector("#qr .captcha-container");\n window.grecaptcha.reset(container.dataset.widgetID);\n})();');
}
},
watchBubbles: function(mutations) {
var k, len1, mutation, node, overlay, results;
results = [];
for (k = 0, len1 = mutations.length; k < len1; k++) {
mutation = mutations[k];
results.push((function() {
var len2, q, ref, results1;
ref = mutation.addedNodes;
results1 = [];
for (q = 0, len2 = ref.length; q < len2; q++) {
node = ref[q];
if ($('iframe[src^="https://www.google.com/recaptcha/api2/frame"]', node)) {
new MutationObserver(this.fixBubble.bind(this, node)).observe(node, {
attributes: true
});
if ((overlay = $('div[style*="position: fixed;"]', node))) {
results1.push($.on(overlay, 'click', function() {
var ref1;
return (ref1 = $('#qr iframe')) != null ? ref1.blur() : void 0;
}));
} else {
results1.push(void 0);
}
} else {
results1.push(void 0);
}
}
return results1;
}).call(this));
}
return results;
},
fixBubble: function(node) {
var bottom, newLeft, qrLeft, ref, right, width;
ref = node.getBoundingClientRect(), bottom = ref.bottom, right = ref.right, width = ref.width;
if (getComputedStyle(node).visibility !== 'hidden' && bottom > 0 && right > doc.clientWidth) {
qrLeft = QR.nodes.el.getBoundingClientRect().left;
newLeft = Math.max(0, qrLeft - width);
return node.style.left = newLeft + "px";
}
}
};
@ -13583,6 +13524,7 @@
this.refreshButton = $('.refresh', this.dialog);
this.closeButton = $('.move > .close', this.dialog);
this.unreaddb = Unread.db || new DataBoard('lastReadPosts');
this.unreadEnabled = Conf['Remember Last Read Post'];
$.on(d, 'QRPostSuccessful', this.cb.post);
$.on(sc, 'click', this.toggleWatcher);
$.on(this.refreshButton, 'click', this.buttonFetchAll);
@ -13779,7 +13721,7 @@
threadID: threadID
});
} else {
if (Conf['Show Unread Count']) {
if (ThreadWatcher.unreadEnabled && Conf['Show Unread Count']) {
ThreadWatcher.fetchStatus({
boardID: boardID,
threadID: threadID,
@ -13835,7 +13777,7 @@
return;
}
db = ThreadWatcher.db;
interval = Conf['Show Unread Count'] ? 5 * $.MINUTE : 2 * $.HOUR;
interval = ThreadWatcher.unreadEnabled && Conf['Show Unread Count'] ? 5 * $.MINUTE : 2 * $.HOUR;
now = Date.now();
if (now >= (db.data.lastChecked || 0) + interval) {
db.data.lastChecked = now;
@ -14008,7 +13950,7 @@
title: data.excerpt,
className: 'watcher-link'
});
if (Conf['Show Unread Count'] && (data.unread != null)) {
if (ThreadWatcher.unreadEnabled && Conf['Show Unread Count'] && (data.unread != null)) {
count = $.el('span', {
textContent: "(" + data.unread + ")",
className: 'watcher-unread'
@ -14029,7 +13971,7 @@
if (data.isDead) {
$.addClass(div, 'dead-thread');
}
if (Conf['Show Unread Count']) {
if (ThreadWatcher.unreadEnabled && Conf['Show Unread Count']) {
if (data.unread === 0) {
$.addClass(div, 'replies-read');
}
@ -14198,7 +14140,7 @@
val: data
});
ThreadWatcher.refresh();
if (Conf['Show Unread Count']) {
if (ThreadWatcher.unreadEnabled && Conf['Show Unread Count']) {
return ThreadWatcher.fetchStatus({
boardID: boardID,
threadID: threadID,
@ -14311,6 +14253,11 @@
};
entry.el.title = desc;
input = entry.el.firstElementChild;
if (name === 'Show Unread Count' && !ThreadWatcher.unreadEnabled) {
input.disabled = true;
$.addClass(entry.el, 'disabled');
entry.el.title += '\n[Remember Last Read Post is disabled.]';
}
$.on(input, 'change', $.cb.checked);
if (name === 'Current Board' || name === 'Show Unread Count') {
$.on(input, 'change', ThreadWatcher.refresh);
@ -14325,10 +14272,15 @@
Unread = {
init: function() {
if (!(g.VIEW === 'thread' && (Conf['Unread Count'] || Conf['Unread Favicon'] || Conf['Unread Line'] || Conf['Scroll to Last Read Post'] || Conf['Thread Watcher'] || Conf['Desktop Notifications'] || Conf['Quote Threading']))) {
if (!(g.VIEW === 'thread' && (Conf['Unread Count'] || Conf['Unread Favicon'] || Conf['Unread Line'] || Conf['Remember Last Read Post'] || Conf['Desktop Notifications'] || Conf['Quote Threading']))) {
return;
}
this.db = new DataBoard('lastReadPosts', this.sync);
if (Conf['Remember Last Read Post']) {
$.sync('Remember Last Read Post', function(enabled) {
return Conf['Remember Last Read Post'] = enabled;
});
this.db = new DataBoard('lastReadPosts', this.sync);
}
this.hr = $.el('hr', {
id: 'unread-line'
});
@ -14346,18 +14298,17 @@
});
},
node: function() {
var ID, k, len1, ref;
var ID, k, len1, ref, ref1;
Unread.thread = this;
Unread.title = d.title;
Unread.lastReadPost = Unread.db.get({
Unread.lastReadPost = ((ref = Unread.db) != null ? ref.get({
boardID: this.board.ID,
threadID: this.ID,
defaultValue: 0
});
threadID: this.ID
}) : void 0) || 0;
Unread.readCount = 0;
ref = this.posts.keys;
for (k = 0, len1 = ref.length; k < len1; k++) {
ID = ref[k];
ref1 = this.posts.keys;
for (k = 0, len1 = ref1.length; k < len1; k++) {
ID = ref1[k];
if (+ID <= Unread.lastReadPost) {
Unread.readCount++;
}
@ -14369,7 +14320,7 @@
Unread.setLine(true);
Unread.read();
Unread.update();
if (Conf['Scroll to Last Read Post']) {
if (Conf['Remember Last Read Post'] && Conf['Scroll to Last Read Post']) {
Unread.scroll();
}
$.on(d, 'scroll visibilitychange', Unread.read);
@ -14519,11 +14470,11 @@
count++;
Unread.posts["delete"](ID);
Unread.postsQuotingYou["delete"](ID);
if (Conf['Mark Quotes of You'] && ((ref1 = QR.db) != null ? ref1.get({
if ((ref1 = QR.db) != null ? ref1.get({
boardID: data.board.ID,
threadID: data.thread.ID,
postID: ID
}) : void 0)) {
}) : void 0) {
QuoteYou.lastRead = root;
}
Unread.position = Unread.position.next;
@ -14544,6 +14495,10 @@
},
saveLastReadPost: $.debounce(2 * $.SECOND, function() {
var ID, i, k, postIDs, ref, ref1;
$.forceSync('Remember Last Read Post');
if (!(Conf['Remember Last Read Post'] && Unread.db)) {
return;
}
postIDs = Unread.thread.posts.keys;
for (i = k = ref = Unread.readCount, ref1 = postIDs.length; k < ref1; i = k += 1) {
ID = +postIDs[i];
@ -14588,7 +14543,8 @@
titleDead = Unread.thread.isDead ? Unread.title.replace('-', (Unread.thread.isArchived ? '- Archived -' : '- 404 -')) : Unread.title;
d.title = "" + titleQuotingYou + titleCount + titleDead;
}
if (!(Unread.thread.isDead && !Unread.thread.isArchived)) {
$.forceSync('Remember Last Read Post');
if (Conf['Remember Last Read Post'] && (!Unread.thread.isDead || Unread.thread.isArchived)) {
ThreadWatcher.update(Unread.thread.board.ID, Unread.thread.ID, {
isDead: Unread.thread.isDead,
unread: count,
@ -16081,13 +16037,13 @@
}
break;
case Conf['Previous Post Quoting You']:
if (!threadRoot) {
if (!(threadRoot && QR.db)) {
return;
}
QuoteYou.cb.seek('preceding');
break;
case Conf['Next Post Quoting You']:
if (!threadRoot) {
if (!(threadRoot && QR.db)) {
return;
}
QuoteYou.cb.seek('following');
@ -18745,6 +18701,10 @@
"body > div:last-of-type {\n" +
" transition: none !important;\n" +
"}\n" +
"/* Fix captcha scrolling to top of page. */\n" +
"body > div[style*=\" top: -10000px;\"] {\n" +
" visibility: hidden !important;\n" +
"}\n" +
"/* Anti-autoplay */\n" +
"audio.controls-added {\n" +
" display: block;\n" +
@ -19938,8 +19898,18 @@
"#qr .captcha-root {\n" +
" position: relative;\n" +
"}\n" +
"#qr .captcha-container > div > div {\n" +
"#qr .captcha-container > div {\n" +
" margin: auto;\n" +
" width: 304px;\n" +
"}\n" +
"/* scrollable with scroll bar hidden; prevents scroll on space press */\n" +
":root.blink #qr .captcha-container > div {\n" +
" overflow: hidden;\n" +
"}\n" +
":root.blink #qr .captcha-container > div > div:first-of-type {\n" +
" overflow-y: scroll;\n" +
" overflow-x: hidden;\n" +
" padding-right: 15px;\n" +
"}\n" +
"#qr .captcha-counter {\n" +
" display: block;\n" +

Binary file not shown.

View File

@ -1,7 +1,7 @@
// Generated by CoffeeScript
// ==UserScript==
// @name 4chan X
// @version 1.11.18.7
// @version 1.11.19.0
// @minGMVer 1.14
// @minFFVer 26
// @namespace 4chan-X
@ -216,7 +216,8 @@
'Hide Unread Count at (0)': [false, 'Hide the unread posts count in the tab title when it reaches 0.', 1],
'Unread Favicon': [true, 'Show a different favicon when there are unread posts.'],
'Unread Line': [true, 'Show a line to distinguish read posts from unread ones.'],
'Scroll to Last Read Post': [true, 'Scroll back to the last read post when reopening a thread.'],
'Remember Last Read Post': [true, 'Remember how far you\'ve read after you close the thread.'],
'Scroll to Last Read Post': [true, 'Scroll back to the last read post when reopening a thread.', 1],
'Thread Excerpt': [true, 'Show an excerpt of the thread in the tab title for threads in /f/.'],
'Remove Thread Excerpt': [false, 'Replace the excerpt of the thread in the tab title with the board title.'],
'Thread Stats': [true, 'Display reply and image count.'],
@ -432,7 +433,7 @@
doc = d.documentElement;
g = {
VERSION: '1.11.18.7',
VERSION: '1.11.19.0',
NAMESPACE: '4chan X.',
boards: {}
};
@ -6157,15 +6158,15 @@
});
},
firstNode: function() {
var a, clone, container, containers, hash, k, len1, len2, len3, link, markYours, nodes, post, q, quote, ref, ref1, u;
var a, clone, container, containers, hash, k, len1, len2, len3, link, markYours, nodes, post, q, quote, ref, ref1, ref2, u;
if (this.isClone || !this.quotes.length || this.isRebuilt) {
return;
}
markYours = Conf['Quick Reply'] && Conf['Mark Quotes of You'] && QR.db.get({
markYours = (ref = QR.db) != null ? ref.get({
boardID: this.board.ID,
threadID: this.thread.ID,
postID: this.ID
});
}) : void 0;
a = $.el('a', {
href: Build.postURL(this.board.ID, this.thread.ID, this.ID),
className: this.isHidden ? 'filtered backlink' : 'backlink',
@ -6178,14 +6179,14 @@
};
})(this)) + (markYours ? '\u00A0(You)' : '')
});
ref = this.quotes;
for (k = 0, len1 = ref.length; k < len1; k++) {
quote = ref[k];
ref1 = this.quotes;
for (k = 0, len1 = ref1.length; k < len1; k++) {
quote = ref1[k];
containers = [QuoteBacklink.getContainer(quote)];
if ((post = g.posts[quote]) && post.nodes.backlinkContainer) {
ref1 = post.clones;
for (q = 0, len2 = ref1.length; q < len2; q++) {
clone = ref1[q];
ref2 = post.clones;
for (q = 0, len2 = ref2.length; q < len2; q++) {
clone = ref2[q];
containers.push(clone.nodes.backlinkContainer);
}
}
@ -6785,9 +6786,6 @@
cb: {
seek: function(type) {
var highlight, post, posts, result, str;
if (!(Conf['Mark Quotes of You'] && Conf['Quick Reply'])) {
return;
}
if (highlight = $('.highlight')) {
$.rmClass(highlight, 'highlight');
}
@ -6965,6 +6963,9 @@
return;
}
if (Conf['Mark Quotes of You']) {
$.sync('Mark Quotes of You', function(enabled) {
return Conf['Mark Quotes of You'] = enabled;
});
this.db = new DataBoard('yourPosts');
}
this.posts = [];
@ -7119,15 +7120,7 @@
return $.queueTask(function() {
if (!QR.inBubble()) {
QR.hasFocus = d.activeElement && QR.nodes.el.contains(d.activeElement);
QR.nodes.el.classList.toggle('focus', QR.hasFocus);
}
if (QR.captcha.isEnabled && QR.captcha === Captcha.v2 && !QR.captcha.noscript) {
if (QR.inCaptcha()) {
QR.scrollY = window.scrollY;
return $.on(d, 'scroll', QR.scrollLock);
} else {
return $.off(d, 'scroll', QR.scrollLock);
}
return QR.nodes.el.classList.toggle('focus', QR.hasFocus);
}
});
},
@ -7138,17 +7131,6 @@
return getComputedStyle(el).visibility !== 'hidden' && el.getBoundingClientRect().bottom > 0;
});
},
inCaptcha: function() {
var ref;
return (((ref = d.activeElement) != null ? ref.nodeName : void 0) === 'IFRAME' && QR.nodes.el.contains(d.activeElement)) || (QR.hasFocus && QR.inBubble());
},
scrollLock: function() {
if (QR.inCaptcha()) {
return window.scroll(window.scrollX, QR.scrollY);
} else {
return $.off(d, 'scroll', QR.scrollLock);
}
},
hide: function() {
d.activeElement.blur();
$.addClass(QR.nodes.el, 'autohide');
@ -7870,13 +7852,16 @@
postID = +postID;
threadID = +threadID || postID;
isReply = threadID !== postID;
if ((ref3 = QR.db) != null) {
ref3.set({
boardID: g.BOARD.ID,
threadID: threadID,
postID: postID,
val: true
});
$.forceSync('Mark Quotes of You');
if (Conf['Mark Quotes of You']) {
if ((ref3 = QR.db) != null) {
ref3.set({
boardID: g.BOARD.ID,
threadID: threadID,
postID: postID,
val: true
});
}
}
$.event('QRPostSuccessful', {
boardID: g.BOARD.ID,
@ -8599,16 +8584,13 @@
return e.stopPropagation();
};
})(this));
$.on(window, 'captcha:success', (function(_this) {
return $.on(window, 'captcha:success', (function(_this) {
return function() {
return $.queueTask(function() {
return _this.save(false);
});
};
})(this));
return new MutationObserver(this.watchBubbles.bind(this)).observe(d.body, {
childList: true
});
},
timeouts: {},
postsCount: 0,
@ -8859,47 +8841,6 @@
} else {
return $.globalEval('(function() {\n var container = document.querySelector("#qr .captcha-container");\n window.grecaptcha.reset(container.dataset.widgetID);\n})();');
}
},
watchBubbles: function(mutations) {
var k, len1, mutation, node, overlay, results;
results = [];
for (k = 0, len1 = mutations.length; k < len1; k++) {
mutation = mutations[k];
results.push((function() {
var len2, q, ref, results1;
ref = mutation.addedNodes;
results1 = [];
for (q = 0, len2 = ref.length; q < len2; q++) {
node = ref[q];
if ($('iframe[src^="https://www.google.com/recaptcha/api2/frame"]', node)) {
new MutationObserver(this.fixBubble.bind(this, node)).observe(node, {
attributes: true
});
if ((overlay = $('div[style*="position: fixed;"]', node))) {
results1.push($.on(overlay, 'click', function() {
var ref1;
return (ref1 = $('#qr iframe')) != null ? ref1.blur() : void 0;
}));
} else {
results1.push(void 0);
}
} else {
results1.push(void 0);
}
}
return results1;
}).call(this));
}
return results;
},
fixBubble: function(node) {
var bottom, newLeft, qrLeft, ref, right, width;
ref = node.getBoundingClientRect(), bottom = ref.bottom, right = ref.right, width = ref.width;
if (getComputedStyle(node).visibility !== 'hidden' && bottom > 0 && right > doc.clientWidth) {
qrLeft = QR.nodes.el.getBoundingClientRect().left;
newLeft = Math.max(0, qrLeft - width);
return node.style.left = newLeft + "px";
}
}
};
@ -13583,6 +13524,7 @@
this.refreshButton = $('.refresh', this.dialog);
this.closeButton = $('.move > .close', this.dialog);
this.unreaddb = Unread.db || new DataBoard('lastReadPosts');
this.unreadEnabled = Conf['Remember Last Read Post'];
$.on(d, 'QRPostSuccessful', this.cb.post);
$.on(sc, 'click', this.toggleWatcher);
$.on(this.refreshButton, 'click', this.buttonFetchAll);
@ -13779,7 +13721,7 @@
threadID: threadID
});
} else {
if (Conf['Show Unread Count']) {
if (ThreadWatcher.unreadEnabled && Conf['Show Unread Count']) {
ThreadWatcher.fetchStatus({
boardID: boardID,
threadID: threadID,
@ -13835,7 +13777,7 @@
return;
}
db = ThreadWatcher.db;
interval = Conf['Show Unread Count'] ? 5 * $.MINUTE : 2 * $.HOUR;
interval = ThreadWatcher.unreadEnabled && Conf['Show Unread Count'] ? 5 * $.MINUTE : 2 * $.HOUR;
now = Date.now();
if (now >= (db.data.lastChecked || 0) + interval) {
db.data.lastChecked = now;
@ -14008,7 +13950,7 @@
title: data.excerpt,
className: 'watcher-link'
});
if (Conf['Show Unread Count'] && (data.unread != null)) {
if (ThreadWatcher.unreadEnabled && Conf['Show Unread Count'] && (data.unread != null)) {
count = $.el('span', {
textContent: "(" + data.unread + ")",
className: 'watcher-unread'
@ -14029,7 +13971,7 @@
if (data.isDead) {
$.addClass(div, 'dead-thread');
}
if (Conf['Show Unread Count']) {
if (ThreadWatcher.unreadEnabled && Conf['Show Unread Count']) {
if (data.unread === 0) {
$.addClass(div, 'replies-read');
}
@ -14198,7 +14140,7 @@
val: data
});
ThreadWatcher.refresh();
if (Conf['Show Unread Count']) {
if (ThreadWatcher.unreadEnabled && Conf['Show Unread Count']) {
return ThreadWatcher.fetchStatus({
boardID: boardID,
threadID: threadID,
@ -14311,6 +14253,11 @@
};
entry.el.title = desc;
input = entry.el.firstElementChild;
if (name === 'Show Unread Count' && !ThreadWatcher.unreadEnabled) {
input.disabled = true;
$.addClass(entry.el, 'disabled');
entry.el.title += '\n[Remember Last Read Post is disabled.]';
}
$.on(input, 'change', $.cb.checked);
if (name === 'Current Board' || name === 'Show Unread Count') {
$.on(input, 'change', ThreadWatcher.refresh);
@ -14325,10 +14272,15 @@
Unread = {
init: function() {
if (!(g.VIEW === 'thread' && (Conf['Unread Count'] || Conf['Unread Favicon'] || Conf['Unread Line'] || Conf['Scroll to Last Read Post'] || Conf['Thread Watcher'] || Conf['Desktop Notifications'] || Conf['Quote Threading']))) {
if (!(g.VIEW === 'thread' && (Conf['Unread Count'] || Conf['Unread Favicon'] || Conf['Unread Line'] || Conf['Remember Last Read Post'] || Conf['Desktop Notifications'] || Conf['Quote Threading']))) {
return;
}
this.db = new DataBoard('lastReadPosts', this.sync);
if (Conf['Remember Last Read Post']) {
$.sync('Remember Last Read Post', function(enabled) {
return Conf['Remember Last Read Post'] = enabled;
});
this.db = new DataBoard('lastReadPosts', this.sync);
}
this.hr = $.el('hr', {
id: 'unread-line'
});
@ -14346,18 +14298,17 @@
});
},
node: function() {
var ID, k, len1, ref;
var ID, k, len1, ref, ref1;
Unread.thread = this;
Unread.title = d.title;
Unread.lastReadPost = Unread.db.get({
Unread.lastReadPost = ((ref = Unread.db) != null ? ref.get({
boardID: this.board.ID,
threadID: this.ID,
defaultValue: 0
});
threadID: this.ID
}) : void 0) || 0;
Unread.readCount = 0;
ref = this.posts.keys;
for (k = 0, len1 = ref.length; k < len1; k++) {
ID = ref[k];
ref1 = this.posts.keys;
for (k = 0, len1 = ref1.length; k < len1; k++) {
ID = ref1[k];
if (+ID <= Unread.lastReadPost) {
Unread.readCount++;
}
@ -14369,7 +14320,7 @@
Unread.setLine(true);
Unread.read();
Unread.update();
if (Conf['Scroll to Last Read Post']) {
if (Conf['Remember Last Read Post'] && Conf['Scroll to Last Read Post']) {
Unread.scroll();
}
$.on(d, 'scroll visibilitychange', Unread.read);
@ -14519,11 +14470,11 @@
count++;
Unread.posts["delete"](ID);
Unread.postsQuotingYou["delete"](ID);
if (Conf['Mark Quotes of You'] && ((ref1 = QR.db) != null ? ref1.get({
if ((ref1 = QR.db) != null ? ref1.get({
boardID: data.board.ID,
threadID: data.thread.ID,
postID: ID
}) : void 0)) {
}) : void 0) {
QuoteYou.lastRead = root;
}
Unread.position = Unread.position.next;
@ -14544,6 +14495,10 @@
},
saveLastReadPost: $.debounce(2 * $.SECOND, function() {
var ID, i, k, postIDs, ref, ref1;
$.forceSync('Remember Last Read Post');
if (!(Conf['Remember Last Read Post'] && Unread.db)) {
return;
}
postIDs = Unread.thread.posts.keys;
for (i = k = ref = Unread.readCount, ref1 = postIDs.length; k < ref1; i = k += 1) {
ID = +postIDs[i];
@ -14588,7 +14543,8 @@
titleDead = Unread.thread.isDead ? Unread.title.replace('-', (Unread.thread.isArchived ? '- Archived -' : '- 404 -')) : Unread.title;
d.title = "" + titleQuotingYou + titleCount + titleDead;
}
if (!(Unread.thread.isDead && !Unread.thread.isArchived)) {
$.forceSync('Remember Last Read Post');
if (Conf['Remember Last Read Post'] && (!Unread.thread.isDead || Unread.thread.isArchived)) {
ThreadWatcher.update(Unread.thread.board.ID, Unread.thread.ID, {
isDead: Unread.thread.isDead,
unread: count,
@ -16081,13 +16037,13 @@
}
break;
case Conf['Previous Post Quoting You']:
if (!threadRoot) {
if (!(threadRoot && QR.db)) {
return;
}
QuoteYou.cb.seek('preceding');
break;
case Conf['Next Post Quoting You']:
if (!threadRoot) {
if (!(threadRoot && QR.db)) {
return;
}
QuoteYou.cb.seek('following');
@ -18745,6 +18701,10 @@
"body > div:last-of-type {\n" +
" transition: none !important;\n" +
"}\n" +
"/* Fix captcha scrolling to top of page. */\n" +
"body > div[style*=\" top: -10000px;\"] {\n" +
" visibility: hidden !important;\n" +
"}\n" +
"/* Anti-autoplay */\n" +
"audio.controls-added {\n" +
" display: block;\n" +
@ -19938,8 +19898,18 @@
"#qr .captcha-root {\n" +
" position: relative;\n" +
"}\n" +
"#qr .captcha-container > div > div {\n" +
"#qr .captcha-container > div {\n" +
" margin: auto;\n" +
" width: 304px;\n" +
"}\n" +
"/* scrollable with scroll bar hidden; prevents scroll on space press */\n" +
":root.blink #qr .captcha-container > div {\n" +
" overflow: hidden;\n" +
"}\n" +
":root.blink #qr .captcha-container > div > div:first-of-type {\n" +
" overflow-y: scroll;\n" +
" overflow-x: hidden;\n" +
" padding-right: 15px;\n" +
"}\n" +
"#qr .captcha-counter {\n" +
" display: block;\n" +

Binary file not shown.

View File

@ -1,6 +1,6 @@
// ==UserScript==
// @name 4chan X
// @version 1.11.18.7
// @version 1.11.19.0
// @minGMVer 1.14
// @minFFVer 26
// @namespace 4chan-X

View File

@ -1,7 +1,7 @@
// Generated by CoffeeScript
// ==UserScript==
// @name 4chan X
// @version 1.11.18.7
// @version 1.11.19.0
// @minGMVer 1.14
// @minFFVer 26
// @namespace 4chan-X
@ -216,7 +216,8 @@
'Hide Unread Count at (0)': [false, 'Hide the unread posts count in the tab title when it reaches 0.', 1],
'Unread Favicon': [true, 'Show a different favicon when there are unread posts.'],
'Unread Line': [true, 'Show a line to distinguish read posts from unread ones.'],
'Scroll to Last Read Post': [true, 'Scroll back to the last read post when reopening a thread.'],
'Remember Last Read Post': [true, 'Remember how far you\'ve read after you close the thread.'],
'Scroll to Last Read Post': [true, 'Scroll back to the last read post when reopening a thread.', 1],
'Thread Excerpt': [true, 'Show an excerpt of the thread in the tab title for threads in /f/.'],
'Remove Thread Excerpt': [false, 'Replace the excerpt of the thread in the tab title with the board title.'],
'Thread Stats': [true, 'Display reply and image count.'],
@ -432,7 +433,7 @@
doc = d.documentElement;
g = {
VERSION: '1.11.18.7',
VERSION: '1.11.19.0',
NAMESPACE: '4chan X.',
boards: {}
};
@ -6157,15 +6158,15 @@
});
},
firstNode: function() {
var a, clone, container, containers, hash, k, len1, len2, len3, link, markYours, nodes, post, q, quote, ref, ref1, u;
var a, clone, container, containers, hash, k, len1, len2, len3, link, markYours, nodes, post, q, quote, ref, ref1, ref2, u;
if (this.isClone || !this.quotes.length || this.isRebuilt) {
return;
}
markYours = Conf['Quick Reply'] && Conf['Mark Quotes of You'] && QR.db.get({
markYours = (ref = QR.db) != null ? ref.get({
boardID: this.board.ID,
threadID: this.thread.ID,
postID: this.ID
});
}) : void 0;
a = $.el('a', {
href: Build.postURL(this.board.ID, this.thread.ID, this.ID),
className: this.isHidden ? 'filtered backlink' : 'backlink',
@ -6178,14 +6179,14 @@
};
})(this)) + (markYours ? '\u00A0(You)' : '')
});
ref = this.quotes;
for (k = 0, len1 = ref.length; k < len1; k++) {
quote = ref[k];
ref1 = this.quotes;
for (k = 0, len1 = ref1.length; k < len1; k++) {
quote = ref1[k];
containers = [QuoteBacklink.getContainer(quote)];
if ((post = g.posts[quote]) && post.nodes.backlinkContainer) {
ref1 = post.clones;
for (q = 0, len2 = ref1.length; q < len2; q++) {
clone = ref1[q];
ref2 = post.clones;
for (q = 0, len2 = ref2.length; q < len2; q++) {
clone = ref2[q];
containers.push(clone.nodes.backlinkContainer);
}
}
@ -6785,9 +6786,6 @@
cb: {
seek: function(type) {
var highlight, post, posts, result, str;
if (!(Conf['Mark Quotes of You'] && Conf['Quick Reply'])) {
return;
}
if (highlight = $('.highlight')) {
$.rmClass(highlight, 'highlight');
}
@ -6965,6 +6963,9 @@
return;
}
if (Conf['Mark Quotes of You']) {
$.sync('Mark Quotes of You', function(enabled) {
return Conf['Mark Quotes of You'] = enabled;
});
this.db = new DataBoard('yourPosts');
}
this.posts = [];
@ -7119,15 +7120,7 @@
return $.queueTask(function() {
if (!QR.inBubble()) {
QR.hasFocus = d.activeElement && QR.nodes.el.contains(d.activeElement);
QR.nodes.el.classList.toggle('focus', QR.hasFocus);
}
if (QR.captcha.isEnabled && QR.captcha === Captcha.v2 && !QR.captcha.noscript) {
if (QR.inCaptcha()) {
QR.scrollY = window.scrollY;
return $.on(d, 'scroll', QR.scrollLock);
} else {
return $.off(d, 'scroll', QR.scrollLock);
}
return QR.nodes.el.classList.toggle('focus', QR.hasFocus);
}
});
},
@ -7138,17 +7131,6 @@
return getComputedStyle(el).visibility !== 'hidden' && el.getBoundingClientRect().bottom > 0;
});
},
inCaptcha: function() {
var ref;
return (((ref = d.activeElement) != null ? ref.nodeName : void 0) === 'IFRAME' && QR.nodes.el.contains(d.activeElement)) || (QR.hasFocus && QR.inBubble());
},
scrollLock: function() {
if (QR.inCaptcha()) {
return window.scroll(window.scrollX, QR.scrollY);
} else {
return $.off(d, 'scroll', QR.scrollLock);
}
},
hide: function() {
d.activeElement.blur();
$.addClass(QR.nodes.el, 'autohide');
@ -7870,13 +7852,16 @@
postID = +postID;
threadID = +threadID || postID;
isReply = threadID !== postID;
if ((ref3 = QR.db) != null) {
ref3.set({
boardID: g.BOARD.ID,
threadID: threadID,
postID: postID,
val: true
});
$.forceSync('Mark Quotes of You');
if (Conf['Mark Quotes of You']) {
if ((ref3 = QR.db) != null) {
ref3.set({
boardID: g.BOARD.ID,
threadID: threadID,
postID: postID,
val: true
});
}
}
$.event('QRPostSuccessful', {
boardID: g.BOARD.ID,
@ -8599,16 +8584,13 @@
return e.stopPropagation();
};
})(this));
$.on(window, 'captcha:success', (function(_this) {
return $.on(window, 'captcha:success', (function(_this) {
return function() {
return $.queueTask(function() {
return _this.save(false);
});
};
})(this));
return new MutationObserver(this.watchBubbles.bind(this)).observe(d.body, {
childList: true
});
},
timeouts: {},
postsCount: 0,
@ -8859,47 +8841,6 @@
} else {
return $.globalEval('(function() {\n var container = document.querySelector("#qr .captcha-container");\n window.grecaptcha.reset(container.dataset.widgetID);\n})();');
}
},
watchBubbles: function(mutations) {
var k, len1, mutation, node, overlay, results;
results = [];
for (k = 0, len1 = mutations.length; k < len1; k++) {
mutation = mutations[k];
results.push((function() {
var len2, q, ref, results1;
ref = mutation.addedNodes;
results1 = [];
for (q = 0, len2 = ref.length; q < len2; q++) {
node = ref[q];
if ($('iframe[src^="https://www.google.com/recaptcha/api2/frame"]', node)) {
new MutationObserver(this.fixBubble.bind(this, node)).observe(node, {
attributes: true
});
if ((overlay = $('div[style*="position: fixed;"]', node))) {
results1.push($.on(overlay, 'click', function() {
var ref1;
return (ref1 = $('#qr iframe')) != null ? ref1.blur() : void 0;
}));
} else {
results1.push(void 0);
}
} else {
results1.push(void 0);
}
}
return results1;
}).call(this));
}
return results;
},
fixBubble: function(node) {
var bottom, newLeft, qrLeft, ref, right, width;
ref = node.getBoundingClientRect(), bottom = ref.bottom, right = ref.right, width = ref.width;
if (getComputedStyle(node).visibility !== 'hidden' && bottom > 0 && right > doc.clientWidth) {
qrLeft = QR.nodes.el.getBoundingClientRect().left;
newLeft = Math.max(0, qrLeft - width);
return node.style.left = newLeft + "px";
}
}
};
@ -13583,6 +13524,7 @@
this.refreshButton = $('.refresh', this.dialog);
this.closeButton = $('.move > .close', this.dialog);
this.unreaddb = Unread.db || new DataBoard('lastReadPosts');
this.unreadEnabled = Conf['Remember Last Read Post'];
$.on(d, 'QRPostSuccessful', this.cb.post);
$.on(sc, 'click', this.toggleWatcher);
$.on(this.refreshButton, 'click', this.buttonFetchAll);
@ -13779,7 +13721,7 @@
threadID: threadID
});
} else {
if (Conf['Show Unread Count']) {
if (ThreadWatcher.unreadEnabled && Conf['Show Unread Count']) {
ThreadWatcher.fetchStatus({
boardID: boardID,
threadID: threadID,
@ -13835,7 +13777,7 @@
return;
}
db = ThreadWatcher.db;
interval = Conf['Show Unread Count'] ? 5 * $.MINUTE : 2 * $.HOUR;
interval = ThreadWatcher.unreadEnabled && Conf['Show Unread Count'] ? 5 * $.MINUTE : 2 * $.HOUR;
now = Date.now();
if (now >= (db.data.lastChecked || 0) + interval) {
db.data.lastChecked = now;
@ -14008,7 +13950,7 @@
title: data.excerpt,
className: 'watcher-link'
});
if (Conf['Show Unread Count'] && (data.unread != null)) {
if (ThreadWatcher.unreadEnabled && Conf['Show Unread Count'] && (data.unread != null)) {
count = $.el('span', {
textContent: "(" + data.unread + ")",
className: 'watcher-unread'
@ -14029,7 +13971,7 @@
if (data.isDead) {
$.addClass(div, 'dead-thread');
}
if (Conf['Show Unread Count']) {
if (ThreadWatcher.unreadEnabled && Conf['Show Unread Count']) {
if (data.unread === 0) {
$.addClass(div, 'replies-read');
}
@ -14198,7 +14140,7 @@
val: data
});
ThreadWatcher.refresh();
if (Conf['Show Unread Count']) {
if (ThreadWatcher.unreadEnabled && Conf['Show Unread Count']) {
return ThreadWatcher.fetchStatus({
boardID: boardID,
threadID: threadID,
@ -14311,6 +14253,11 @@
};
entry.el.title = desc;
input = entry.el.firstElementChild;
if (name === 'Show Unread Count' && !ThreadWatcher.unreadEnabled) {
input.disabled = true;
$.addClass(entry.el, 'disabled');
entry.el.title += '\n[Remember Last Read Post is disabled.]';
}
$.on(input, 'change', $.cb.checked);
if (name === 'Current Board' || name === 'Show Unread Count') {
$.on(input, 'change', ThreadWatcher.refresh);
@ -14325,10 +14272,15 @@
Unread = {
init: function() {
if (!(g.VIEW === 'thread' && (Conf['Unread Count'] || Conf['Unread Favicon'] || Conf['Unread Line'] || Conf['Scroll to Last Read Post'] || Conf['Thread Watcher'] || Conf['Desktop Notifications'] || Conf['Quote Threading']))) {
if (!(g.VIEW === 'thread' && (Conf['Unread Count'] || Conf['Unread Favicon'] || Conf['Unread Line'] || Conf['Remember Last Read Post'] || Conf['Desktop Notifications'] || Conf['Quote Threading']))) {
return;
}
this.db = new DataBoard('lastReadPosts', this.sync);
if (Conf['Remember Last Read Post']) {
$.sync('Remember Last Read Post', function(enabled) {
return Conf['Remember Last Read Post'] = enabled;
});
this.db = new DataBoard('lastReadPosts', this.sync);
}
this.hr = $.el('hr', {
id: 'unread-line'
});
@ -14346,18 +14298,17 @@
});
},
node: function() {
var ID, k, len1, ref;
var ID, k, len1, ref, ref1;
Unread.thread = this;
Unread.title = d.title;
Unread.lastReadPost = Unread.db.get({
Unread.lastReadPost = ((ref = Unread.db) != null ? ref.get({
boardID: this.board.ID,
threadID: this.ID,
defaultValue: 0
});
threadID: this.ID
}) : void 0) || 0;
Unread.readCount = 0;
ref = this.posts.keys;
for (k = 0, len1 = ref.length; k < len1; k++) {
ID = ref[k];
ref1 = this.posts.keys;
for (k = 0, len1 = ref1.length; k < len1; k++) {
ID = ref1[k];
if (+ID <= Unread.lastReadPost) {
Unread.readCount++;
}
@ -14369,7 +14320,7 @@
Unread.setLine(true);
Unread.read();
Unread.update();
if (Conf['Scroll to Last Read Post']) {
if (Conf['Remember Last Read Post'] && Conf['Scroll to Last Read Post']) {
Unread.scroll();
}
$.on(d, 'scroll visibilitychange', Unread.read);
@ -14519,11 +14470,11 @@
count++;
Unread.posts["delete"](ID);
Unread.postsQuotingYou["delete"](ID);
if (Conf['Mark Quotes of You'] && ((ref1 = QR.db) != null ? ref1.get({
if ((ref1 = QR.db) != null ? ref1.get({
boardID: data.board.ID,
threadID: data.thread.ID,
postID: ID
}) : void 0)) {
}) : void 0) {
QuoteYou.lastRead = root;
}
Unread.position = Unread.position.next;
@ -14544,6 +14495,10 @@
},
saveLastReadPost: $.debounce(2 * $.SECOND, function() {
var ID, i, k, postIDs, ref, ref1;
$.forceSync('Remember Last Read Post');
if (!(Conf['Remember Last Read Post'] && Unread.db)) {
return;
}
postIDs = Unread.thread.posts.keys;
for (i = k = ref = Unread.readCount, ref1 = postIDs.length; k < ref1; i = k += 1) {
ID = +postIDs[i];
@ -14588,7 +14543,8 @@
titleDead = Unread.thread.isDead ? Unread.title.replace('-', (Unread.thread.isArchived ? '- Archived -' : '- 404 -')) : Unread.title;
d.title = "" + titleQuotingYou + titleCount + titleDead;
}
if (!(Unread.thread.isDead && !Unread.thread.isArchived)) {
$.forceSync('Remember Last Read Post');
if (Conf['Remember Last Read Post'] && (!Unread.thread.isDead || Unread.thread.isArchived)) {
ThreadWatcher.update(Unread.thread.board.ID, Unread.thread.ID, {
isDead: Unread.thread.isDead,
unread: count,
@ -16081,13 +16037,13 @@
}
break;
case Conf['Previous Post Quoting You']:
if (!threadRoot) {
if (!(threadRoot && QR.db)) {
return;
}
QuoteYou.cb.seek('preceding');
break;
case Conf['Next Post Quoting You']:
if (!threadRoot) {
if (!(threadRoot && QR.db)) {
return;
}
QuoteYou.cb.seek('following');
@ -18745,6 +18701,10 @@
"body > div:last-of-type {\n" +
" transition: none !important;\n" +
"}\n" +
"/* Fix captcha scrolling to top of page. */\n" +
"body > div[style*=\" top: -10000px;\"] {\n" +
" visibility: hidden !important;\n" +
"}\n" +
"/* Anti-autoplay */\n" +
"audio.controls-added {\n" +
" display: block;\n" +
@ -19938,8 +19898,18 @@
"#qr .captcha-root {\n" +
" position: relative;\n" +
"}\n" +
"#qr .captcha-container > div > div {\n" +
"#qr .captcha-container > div {\n" +
" margin: auto;\n" +
" width: 304px;\n" +
"}\n" +
"/* scrollable with scroll bar hidden; prevents scroll on space press */\n" +
":root.blink #qr .captcha-container > div {\n" +
" overflow: hidden;\n" +
"}\n" +
":root.blink #qr .captcha-container > div > div:first-of-type {\n" +
" overflow-y: scroll;\n" +
" overflow-x: hidden;\n" +
" padding-right: 15px;\n" +
"}\n" +
"#qr .captcha-counter {\n" +
" display: block;\n" +

Binary file not shown.

View File

@ -1,7 +1,7 @@
<?xml version='1.0' encoding='UTF-8'?>
<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>
<app appid='lacclbnghgdicfifcamcmcnilckjamag'>
<updatecheck codebase='https://www.4chan-x.net/builds/4chan-X-beta.crx' version='1.11.18.7' />
<updatecheck codebase='https://www.4chan-x.net/builds/4chan-X-beta.crx' version='1.11.19.0' />
</app>
</gupdate>

View File

@ -1,7 +1,7 @@
<?xml version='1.0' encoding='UTF-8'?>
<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>
<app appid='lacclbnghgdicfifcamcmcnilckjamag'>
<updatecheck codebase='https://www.4chan-x.net/builds/4chan-X.crx' version='1.11.18.7' />
<updatecheck codebase='https://www.4chan-x.net/builds/4chan-X.crx' version='1.11.19.0' />
</app>
</gupdate>

View File

@ -1,4 +1,4 @@
{
"version": "1.11.18.7",
"date": "2015-11-29T02:37:45.797Z"
"version": "1.11.19.0",
"date": "2015-11-30T01:27:49.597Z"
}