Release 4chan X v1.14.5.2.

This commit is contained in:
ccd0 2018-12-06 22:57:49 -08:00
parent 99a653f7f2
commit 558407e2db
15 changed files with 562 additions and 224 deletions

View File

@ -4,6 +4,11 @@
### v1.14.5 ### v1.14.5
**v1.14.5.2** *(2018-12-07)* - [[Userscript](https://raw.githubusercontent.com/ccd0/4chan-x/1.14.5.2/builds/4chan-X-noupdate.user.js)] [[Chrome extension](https://raw.githubusercontent.com/ccd0/4chan-x/1.14.5.2/builds/4chan-X-noupdate.crx)]
- All Thread Watcher functionality is now supported on and across Tinyboard/vichan sites, including auto-updating, the unread count, and lighting up upon replies, with the exception that threads from sites without JSON APIs will not be updated when the thread watcher is refreshed.
- The `Unread Count`, `Unread Line`, `Scroll to Last Read Post`, and `Desktop Notifications` are now supported on Tinyboard/vichan sites.
- Replies made AJAX on Tinyboard/vichan sites are now marked as yours.
**v1.14.5.1** *(2018-12-06)* - [[Userscript](https://raw.githubusercontent.com/ccd0/4chan-x/1.14.5.1/builds/4chan-X-noupdate.user.js)] [[Chrome extension](https://raw.githubusercontent.com/ccd0/4chan-x/1.14.5.1/builds/4chan-X-noupdate.crx)] **v1.14.5.1** *(2018-12-06)* - [[Userscript](https://raw.githubusercontent.com/ccd0/4chan-x/1.14.5.1/builds/4chan-X-noupdate.user.js)] [[Chrome extension](https://raw.githubusercontent.com/ccd0/4chan-x/1.14.5.1/builds/4chan-X-noupdate.crx)]
- Support style switcher and non-default styles on Tinyboard. - Support style switcher and non-default styles on Tinyboard.

Binary file not shown.

View File

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

View File

@ -1,6 +1,6 @@
// ==UserScript== // ==UserScript==
// @name 4chan X beta // @name 4chan X beta
// @version 1.14.5.1 // @version 1.14.5.2
// @minGMVer 1.14 // @minGMVer 1.14
// @minFFVer 26 // @minFFVer 26
// @namespace 4chan-X // @namespace 4chan-X
@ -183,7 +183,7 @@
'use strict'; 'use strict';
var $, $$, Anonymize, AntiAutoplay, ArchiveLink, Banner, Board, BoardConfig, Build, CSS, Callbacks, Captcha, CatalogLinks, CatalogThread, Config, Connection, CopyTextLink, CrossOrigin, CustomCSS, DataBoard, DeleteLink, DownloadLink, Embedding, ExpandComment, ExpandThread, FappeTyme, Favicon, Fetcher, FileInfo, Filter, Flash, Fourchan, Gallery, Get, Header, IDColor, IDHighlight, IDPostCount, ImageCommon, ImageExpand, ImageHost, ImageHover, ImageLoader, Index, Keybinds, Linkify, Main, MarkNewIPs, Menu, Metadata, Nav, NormalizeURL, Notice, PSAHiding, PassLink, Polyfill, Post, PostHiding, PostSuccessful, QR, QuoteBacklink, QuoteCT, QuoteInline, QuoteOP, QuotePreview, QuoteStrikeThrough, QuoteThreading, QuoteYou, Quotify, RandomAccessList, Recursive, Redirect, RelativeDates, RemoveSpoilers, ReplyPruning, Report, ReportLink, RevealSpoilers, SW, Sauce, Settings, ShimSet, SimpleDict, Site, Thread, ThreadHiding, ThreadLinks, ThreadStats, ThreadUpdater, ThreadWatcher, Time, UI, Unread, UnreadIndex, Volume; var $, $$, Anonymize, AntiAutoplay, ArchiveLink, Banner, Board, BoardConfig, Build, CSS, Callbacks, Captcha, CatalogLinks, CatalogThread, Config, Connection, CopyTextLink, CrossOrigin, CustomCSS, DataBoard, DeleteLink, DownloadLink, Embedding, ExpandComment, ExpandThread, FappeTyme, Favicon, Fetcher, FileInfo, Filter, Flash, Fourchan, Gallery, Get, Header, IDColor, IDHighlight, IDPostCount, ImageCommon, ImageExpand, ImageHost, ImageHover, ImageLoader, Index, Keybinds, Linkify, Main, MarkNewIPs, Menu, Metadata, Nav, NormalizeURL, Notice, PSAHiding, PassLink, Polyfill, Post, PostHiding, PostSuccessful, QR, QuoteBacklink, QuoteCT, QuoteInline, QuoteOP, QuotePreview, QuoteStrikeThrough, QuoteThreading, QuoteYou, Quotify, RandomAccessList, Recursive, Redirect, RelativeDates, RemoveSpoilers, ReplyPruning, Report, ReportLink, RevealSpoilers, SW, Sauce, Settings, ShimSet, SimpleDict, Site, Thread, ThreadHiding, ThreadLinks, ThreadStats, ThreadUpdater, ThreadWatcher, Time, Tinyboard, UI, Unread, UnreadIndex, Volume;
var Conf, E, c, d, doc, docSet, g; var Conf, E, c, d, doc, docSet, g;
@ -198,7 +198,7 @@ docSet = function() {
}; };
g = { g = {
VERSION: '1.14.5.1', VERSION: '1.14.5.2',
NAMESPACE: '4chan X.', NAMESPACE: '4chan X.',
boards: {} boards: {}
}; };
@ -2317,6 +2317,9 @@ span.hide-announcement {\n\
margin: 0;\n\ margin: 0;\n\
border-color: rgb(255,0,0);\n\ border-color: rgb(255,0,0);\n\
}\n\ }\n\
.unread-line + br {\n\
display: none;\n\
}\n\
.unread-mark-read {\n\ .unread-mark-read {\n\
float: right;\n\ float: right;\n\
clear: both;\n\ clear: both;\n\
@ -2419,6 +2422,9 @@ span.hide-announcement {\n\
-webkit-flex: 0 1 auto;\n\ -webkit-flex: 0 1 auto;\n\
flex: 0 1 auto;\n\ flex: 0 1 auto;\n\
}\n\ }\n\
.replies-quoting-you > a, #watcher-link.replies-quoting-you {\n\
color: #F00;\n\
}\n\
#thread-watcher a {\n\ #thread-watcher a {\n\
text-decoration: none;\n\ text-decoration: none;\n\
}\n\ }\n\
@ -5472,7 +5478,7 @@ CrossOrigin = (function() {
} }
return delete callbacks[url]; return delete callbacks[url];
}; };
return function(url, cb, bypassCache) { return function(url, cb, bypassCache, timeout) {
var req; var req;
if (!(((typeof GM !== "undefined" && GM !== null ? GM.xmlHttpRequest : void 0) != null) || (typeof GM_xmlhttpRequest !== "undefined" && GM_xmlhttpRequest !== null))) { if (!(((typeof GM !== "undefined" && GM !== null ? GM.xmlHttpRequest : void 0) != null) || (typeof GM_xmlhttpRequest !== "undefined" && GM_xmlhttpRequest !== null))) {
if (bypassCache) { if (bypassCache) {
@ -5493,19 +5499,21 @@ CrossOrigin = (function() {
} }
if (bypassCache) { if (bypassCache) {
delete results[url]; delete results[url];
} } else {
if (results[url]) { if (results[url]) {
cb.call(results[url]); cb.call(results[url]);
return; return;
} }
if (callbacks[url]) { if (callbacks[url]) {
callbacks[url].push(cb); callbacks[url].push(cb);
return; return;
}
} }
callbacks[url] = [cb]; callbacks[url] = [cb];
return ((typeof GM !== "undefined" && GM !== null ? GM.xmlHttpRequest : void 0) || GM_xmlhttpRequest)({ return ((typeof GM !== "undefined" && GM !== null ? GM.xmlHttpRequest : void 0) || GM_xmlhttpRequest)({
method: "GET", method: "GET",
url: url + '', url: url + '',
timeout: timeout,
onload: function(xhr) { onload: function(xhr) {
var response, status, statusText; var response, status, statusText;
status = xhr.status, statusText = xhr.statusText; status = xhr.status, statusText = xhr.statusText;
@ -5525,6 +5533,9 @@ CrossOrigin = (function() {
}, },
onabort: function() { onabort: function() {
return failure(url); return failure(url);
},
ontimeout: function() {
return failure(url);
} }
}); });
}; };
@ -5928,13 +5939,10 @@ DataBoard = (function() {
})(this), cb); })(this), cb);
}; };
DataBoard.prototype.setLastChecked = function(siteID) { DataBoard.prototype.setLastChecked = function() {
if (siteID == null) {
siteID = Site.hostname;
}
return this.save((function(_this) { return this.save((function(_this) {
return function() { return function() {
return _this.data[siteID].lastChecked = Date.now(); return _this.data.lastChecked = Date.now();
}; };
})(this)); })(this));
}; };
@ -6504,9 +6512,10 @@ Post = (function() {
this.boardID = this.board.ID; this.boardID = this.board.ID;
this.fullID = this.board + "." + this.ID; this.fullID = this.board + "." + this.ID;
this.context = this; this.context = this;
this.isReply = this.ID !== this.threadID;
root.dataset.fullID = this.fullID; root.dataset.fullID = this.fullID;
this.nodes = this.parseNodes(root); this.nodes = this.parseNodes(root);
if (!(this.isReply = this.ID !== this.threadID)) { if (!this.isReply) {
this.thread.OP = this; this.thread.OP = this;
ref = ['isSticky', 'isClosed', 'isArchived']; ref = ['isSticky', 'isClosed', 'isArchived'];
for (j = 0, len = ref.length; j < len; j++) { for (j = 0, len = ref.length; j < len; j++) {
@ -6568,6 +6577,7 @@ Post = (function() {
info = $(s.infoRoot, post); info = $(s.infoRoot, post);
nodes = { nodes = {
root: root, root: root,
bottom: this.isReply || !Site.isOPContainerThread ? root : $(s.opBottom, root),
post: post, post: post,
info: info, info: info,
comment: $(s.comment, post), comment: $(s.comment, post),
@ -7280,7 +7290,8 @@ SW = {};
SW.tinyboard = { SW.tinyboard = {
isOPContainerThread: true, isOPContainerThread: true,
disabledFeatures: ['Board Configuration', 'Normalize URL', 'Captcha Configuration', 'Image Host Rewriting', 'Index Generator', 'Announcement Hiding', 'Fourchan thingies', 'Resurrect Quotes', 'Quick Reply Personas', 'Quick Reply', 'Cooldown', 'Pass Link', 'Index Generator (Menu)', 'Report Link', 'Delete Link', 'Edit Link', 'Archive Link', 'Quote Inlining', 'Quote Previewing', 'Quote Backlinks', 'File Info Formatting', 'Fappe Tyme', 'Image Expansion', 'Image Expansion (Menu)', 'Comment Expansion', 'Thread Expansion', 'Favicon', 'Unread', 'Quote Threading', 'Thread Stats', 'Thread Updater', 'Mark New IPs', 'Banner', 'Flash Features', 'Reply Pruning'], mayLackJSON: true,
disabledFeatures: ['Board Configuration', 'Normalize URL', 'Captcha Configuration', 'Image Host Rewriting', 'Index Generator', 'Announcement Hiding', 'Fourchan thingies', 'Resurrect Quotes', 'Quick Reply Personas', 'Quick Reply', 'Cooldown', 'Pass Link', 'Index Generator (Menu)', 'Report Link', 'Delete Link', 'Edit Link', 'Archive Link', 'Quote Inlining', 'Quote Previewing', 'Quote Backlinks', 'File Info Formatting', 'Fappe Tyme', 'Image Expansion', 'Image Expansion (Menu)', 'Comment Expansion', 'Thread Expansion', 'Favicon', 'Quote Threading', 'Thread Stats', 'Thread Updater', 'Mark New IPs', 'Banner', 'Flash Features', 'Reply Pruning'],
detect: function() { detect: function() {
var i, len, m, properties, ref, root, script; var i, len, m, properties, ref, root, script;
ref = $$('script:not([src])', d.head); ref = $$('script:not([src])', d.head);
@ -7306,6 +7317,16 @@ SW = {};
var boardID, ref, siteID, threadID; var boardID, ref, siteID, threadID;
siteID = arg.siteID, boardID = arg.boardID, threadID = arg.threadID; siteID = arg.siteID, boardID = arg.boardID, threadID = arg.threadID;
return "" + (((ref = Conf['siteProperties'][siteID]) != null ? ref.root : void 0) || ("http://" + siteID + "/")) + boardID + "/res/" + threadID + ".html"; return "" + (((ref = Conf['siteProperties'][siteID]) != null ? ref.root : void 0) || ("http://" + siteID + "/")) + boardID + "/res/" + threadID + ".html";
},
threadJSON: function(arg) {
var boardID, ref, root, siteID, threadID;
siteID = arg.siteID, boardID = arg.boardID, threadID = arg.threadID;
root = (ref = Conf['siteProperties'][siteID]) != null ? ref.root : void 0;
if (root) {
return "" + root + boardID + "/res/" + threadID + ".json";
} else {
return '';
}
} }
}, },
selectors: { selectors: {
@ -7314,6 +7335,7 @@ SW = {};
threadDivider: 'div[id^="thread_"] > hr:last-of-type', threadDivider: 'div[id^="thread_"] > hr:last-of-type',
summary: '.omitted', summary: '.omitted',
postContainer: '.reply', postContainer: '.reply',
opBottom: '.op',
infoRoot: '.intro', infoRoot: '.intro',
info: { info: {
subject: '.subject', subject: '.subject',
@ -7348,7 +7370,8 @@ SW = {};
postContainer: 'div[starts-with(@id,"reply_") or starts-with(@id,"thread_")]' postContainer: 'div[starts-with(@id,"reply_") or starts-with(@id,"thread_")]'
}, },
regexp: { regexp: {
quotelink: /\/([^\/]+)\/res\/(\d+)\.html#(\d+)$/ quotelink: /\/([^\/]+)\/res\/(\d+)\.html#(\d+)$/,
quotelinkHTML: /<a [^>]*\bhref="[^"]*\/([^\/]+)\/res\/(\d+)\.html#(\d+)"/g
}, },
bgColoredEl: function() { bgColoredEl: function() {
return $.el('div', { return $.el('div', {
@ -7415,6 +7438,11 @@ SW = {};
var boardID, threadID; var boardID, threadID;
boardID = arg.boardID, threadID = arg.threadID; boardID = arg.boardID, threadID = arg.threadID;
return location.protocol + "//" + (BoardConfig.domain(boardID)) + "/" + boardID + "/thread/" + threadID; return location.protocol + "//" + (BoardConfig.domain(boardID)) + "/" + boardID + "/thread/" + threadID;
},
threadJSON: function(arg) {
var boardID, threadID;
boardID = arg.boardID, threadID = arg.threadID;
return location.protocol + "//a.4cdn.org/" + boardID + "/thread/" + threadID + ".json";
} }
}, },
selectors: { selectors: {
@ -7462,7 +7490,8 @@ SW = {};
postContainer: 'div[contains(@class,"postContainer")]' postContainer: 'div[contains(@class,"postContainer")]'
}, },
regexp: { regexp: {
quotelink: /^https?:\/\/boards\.4chan(?:nel)?\.org\/+([^\/]+)\/+thread\/+(\d+)(?:[\/?][^#]*)?(?:#p(\d+))?$/ quotelink: /^https?:\/\/boards\.4chan(?:nel)?\.org\/+([^\/]+)\/+thread\/+(\d+)(?:[\/?][^#]*)?(?:#p(\d+))?$/,
quotelinkHTML: /<a [^>]*\bhref="(?:(?:\/\/boards\.4chan(?:nel)?\.org)?\/([^\/]+)\/thread\/)?(\d+)?(?:#p(\d+))?"/g
}, },
bgColoredEl: function() { bgColoredEl: function() {
return $.el('div', { return $.el('div', {
@ -7588,6 +7617,9 @@ SW = {};
node = ref1[k]; node = ref1[k];
$.replace(node, [$.tn('[code]')].concat(slice.call(node.childNodes), [$.tn('[/code]')])); $.replace(node, [$.tn('[code]')].concat(slice.call(node.childNodes), [$.tn('[/code]')]));
} }
},
hasCORS: function(url) {
return url.split('/').slice(0, 3).join('/') === location.protocol + '//a.4cdn.org';
} }
}; };
@ -18874,6 +18906,47 @@ Time = (function() {
}).call(this); }).call(this);
Tinyboard = (function() {
var Tinyboard;
Tinyboard = {
init: function() {
if (Site.software !== 'tinyboard') {
return;
}
if (g.VIEW === 'thread') {
return Main.ready(function() {
return $.global(function() {
var boardID, ref, threadID;
ref = document.currentScript.dataset, boardID = ref.boardID, threadID = ref.threadID;
threadID = +threadID;
return window.$(document).on('new_post', function(e, post) {
var detail, event, postID;
postID = +post.id.match(/\d*$/)[0];
detail = {
boardID: boardID,
threadID: threadID,
postID: postID
};
event = new CustomEvent('QRPostSuccessful', {
bubbles: true,
detail: detail
});
return document.dispatchEvent(event);
});
}, {
boardID: g.BOARD.ID,
threadID: g.THREADID
});
});
}
}
};
return Tinyboard;
}).call(this);
Favicon = (function() { Favicon = (function() {
var Favicon; var Favicon;
@ -19764,9 +19837,6 @@ ThreadWatcher = (function() {
$.on(sc, 'click', this.toggleWatcher); $.on(sc, 'click', this.toggleWatcher);
$.on(this.refreshButton, 'click', this.buttonFetchAll); $.on(this.refreshButton, 'click', this.buttonFetchAll);
$.on(this.closeButton, 'click', this.toggleWatcher); $.on(this.closeButton, 'click', this.toggleWatcher);
if (Site.software !== 'yotsuba') {
this.refreshButton.hidden = true;
}
this.menu.addHeaderMenuEntry(); this.menu.addHeaderMenuEntry();
$.onExists(doc, 'body', this.addDialog); $.onExists(doc, 'body', this.addDialog);
switch (g.VIEW) { switch (g.VIEW) {
@ -20039,9 +20109,6 @@ ThreadWatcher = (function() {
}, },
fetchAuto: function() { fetchAuto: function() {
var db, interval, now, ref; var db, interval, now, ref;
if (Site.software !== 'yotsuba') {
return;
}
clearTimeout(ThreadWatcher.timeout); clearTimeout(ThreadWatcher.timeout);
if (!Conf['Auto Update Thread Watcher']) { if (!Conf['Auto Update Thread Watcher']) {
return; return;
@ -20049,7 +20116,7 @@ ThreadWatcher = (function() {
db = ThreadWatcher.db; db = ThreadWatcher.db;
interval = ThreadWatcher.unreadEnabled && Conf['Show Unread Count'] ? 5 * $.MINUTE : 2 * $.HOUR; interval = ThreadWatcher.unreadEnabled && Conf['Show Unread Count'] ? 5 * $.MINUTE : 2 * $.HOUR;
now = Date.now(); now = Date.now();
if (!((now - interval < (ref = db.data[Site.hostname].lastChecked || 0) && ref <= now) || d.hidden || !d.hasFocus())) { if (!((now - interval < (ref = db.data.lastChecked || 0) && ref <= now) || d.hidden || !d.hasFocus())) {
ThreadWatcher.fetchAllStatus(); ThreadWatcher.fetchAllStatus();
db.setLastChecked(); db.setLastChecked();
} }
@ -20064,9 +20131,6 @@ ThreadWatcher = (function() {
}, },
fetchAllStatus: function() { fetchAllStatus: function() {
var db, dbs, i, len1, n, results; var db, dbs, i, len1, n, results;
if (Site.software !== 'yotsuba') {
return;
}
dbs = [ThreadWatcher.db, ThreadWatcher.unreaddb, QuoteYou.db].filter(function(x) { dbs = [ThreadWatcher.db, ThreadWatcher.unreaddb, QuoteYou.db].filter(function(x) {
return x; return x;
}); });
@ -20088,66 +20152,96 @@ ThreadWatcher = (function() {
return results; return results;
}, },
fetchStatus: function(thread, force) { fetchStatus: function(thread, force) {
var boardID, data, req, siteID, threadID; var base, boardID, data, ref, ref1, req, siteID, software, threadID, url;
siteID = thread.siteID, boardID = thread.boardID, threadID = thread.threadID, data = thread.data; siteID = thread.siteID, boardID = thread.boardID, threadID = thread.threadID, data = thread.data;
if (!(Site.software === 'yotsuba' && siteID === Site.hostname)) { software = (ref = Conf['siteProperties'][siteID]) != null ? ref.software : void 0;
url = (ref1 = SW[software]) != null ? typeof (base = ref1.urls).threadJSON === "function" ? base.threadJSON({
siteID: siteID,
boardID: boardID,
threadID: threadID
}) : void 0 : void 0;
if (!url) {
return; return;
} }
if (data.isDead && !force) { if (data.isDead && !force) {
return; return;
} }
if (data.last === -1) {
return;
}
if (ThreadWatcher.requests.length === 0) { if (ThreadWatcher.requests.length === 0) {
ThreadWatcher.status.textContent = '...'; ThreadWatcher.status.textContent = '...';
$.addClass(ThreadWatcher.refreshButton, 'fa-spin'); $.addClass(ThreadWatcher.refreshButton, 'fa-spin');
} }
req = $.ajax(location.protocol + "//a.4cdn.org/" + boardID + "/thread/" + threadID + ".json", { if ((typeof Site.hasCORS === "function" ? Site.hasCORS(url) : void 0) || url.split('/').slice(0, 3).join('/') === location.origin) {
onloadend: function() { req = $.ajax(url, {
onloadend: function() {
return ThreadWatcher.parseStatus.call(this, thread);
},
timeout: $.MINUTE
});
} else {
req = {
abort: function() {
return req.aborted = true;
}
};
CrossOrigin.json(url, function() {
if (req.aborted) {
return;
}
return ThreadWatcher.parseStatus.call(this, thread); return ThreadWatcher.parseStatus.call(this, thread);
}, }, true, $.MINUTE);
timeout: $.MINUTE }
}, {
whenModified: force ? false : 'ThreadWatcher'
});
return ThreadWatcher.requests.push(req); return ThreadWatcher.requests.push(req);
}, },
parseStatus: function(arg) { parseStatus: function(arg) {
var boardID, data, i, isDead, lastReadPost, len1, match, postObj, quotesYou, quotingYou, ref, ref1, ref2, regexp, threadID, unread, youOP; var boardID, data, i, isDead, last, lastReadPost, len1, match, postObj, quotesYou, quotingYou, ref, ref1, ref2, ref3, regexp, siteID, software, threadID, unread, updated, youOP;
boardID = arg.boardID, threadID = arg.threadID, data = arg.data; siteID = arg.siteID, boardID = arg.boardID, threadID = arg.threadID, data = arg.data;
ThreadWatcher.fetched++; ThreadWatcher.fetched++;
if (ThreadWatcher.fetched === ThreadWatcher.requests.length) { if (ThreadWatcher.fetched === ThreadWatcher.requests.length) {
ThreadWatcher.clearRequests(); ThreadWatcher.clearRequests();
} else { } else {
ThreadWatcher.status.textContent = (Math.round(ThreadWatcher.fetched / ThreadWatcher.requests.length * 100)) + "%"; ThreadWatcher.status.textContent = (Math.round(ThreadWatcher.fetched / ThreadWatcher.requests.length * 100)) + "%";
} }
software = (ref = Conf['siteProperties'][siteID]) != null ? ref.software : void 0;
if (this.status === 200 && this.response) { if (this.status === 200 && this.response) {
last = this.response.posts[this.response.posts.length - 1].no;
isDead = !!this.response.posts[0].archived; isDead = !!this.response.posts[0].archived;
if (isDead && Conf['Auto Prune']) { if (isDead && Conf['Auto Prune']) {
ThreadWatcher.db["delete"]({ ThreadWatcher.db["delete"]({
siteID: siteID,
boardID: boardID, boardID: boardID,
threadID: threadID threadID: threadID
}); });
ThreadWatcher.refresh(); ThreadWatcher.refresh();
return; return;
} }
if (last === data.last && isDead === data.isDead) {
return;
}
lastReadPost = ThreadWatcher.unreaddb.get({ lastReadPost = ThreadWatcher.unreaddb.get({
siteID: siteID,
boardID: boardID, boardID: boardID,
threadID: threadID, threadID: threadID,
defaultValue: 0 defaultValue: 0
}); });
unread = 0; unread = 0;
quotingYou = false; quotingYou = false;
youOP = !!((ref = QuoteYou.db) != null ? ref.get({ youOP = !!((ref1 = QuoteYou.db) != null ? ref1.get({
siteID: siteID,
boardID: boardID, boardID: boardID,
threadID: threadID, threadID: threadID,
postID: threadID postID: threadID
}) : void 0); }) : void 0);
ref1 = this.response.posts; ref2 = this.response.posts;
for (i = 0, len1 = ref1.length; i < len1; i++) { for (i = 0, len1 = ref2.length; i < len1; i++) {
postObj = ref1[i]; postObj = ref2[i];
if (!(postObj.no > lastReadPost)) { if (!(postObj.no > lastReadPost)) {
continue; continue;
} }
if ((ref2 = QuoteYou.db) != null ? ref2.get({ if ((ref3 = QuoteYou.db) != null ? ref3.get({
siteID: siteID,
boardID: boardID, boardID: boardID,
threadID: threadID, threadID: threadID,
postID: postObj.no postID: postObj.no
@ -20163,9 +20257,11 @@ ThreadWatcher = (function() {
continue; continue;
} }
quotesYou = false; quotesYou = false;
regexp = /<a [^>]*\bhref="(?:(?:\/\/boards\.4chan(?:nel)?\.org)?\/([^\/]+)\/thread\/)?(\d+)?(?:#p(\d+))?"/g; regexp = SW[software].regexp.quotelinkHTML;
regexp.lastIndex = 0;
while (match = regexp.exec(postObj.com)) { while (match = regexp.exec(postObj.com)) {
if (QuoteYou.db.get({ if (QuoteYou.db.get({
siteID: siteID,
boardID: match[1] || boardID, boardID: match[1] || boardID,
threadID: match[2] || threadID, threadID: match[2] || threadID,
postID: match[3] || match[2] || threadID postID: match[3] || match[2] || threadID
@ -20178,26 +20274,41 @@ ThreadWatcher = (function() {
quotingYou = true; quotingYou = true;
} }
} }
if (isDead !== data.isDead || unread !== data.unread || quotingYou !== data.quotingYou) { updated = isDead !== data.isDead || unread !== data.unread || quotingYou !== data.quotingYou;
ThreadWatcher.db.extend({ ThreadWatcher.db.extend({
boardID: boardID, siteID: siteID,
threadID: threadID, boardID: boardID,
val: { threadID: threadID,
isDead: isDead, val: {
unread: unread, last: last,
quotingYou: quotingYou isDead: isDead,
} unread: unread,
}); quotingYou: quotingYou
}
});
if (updated) {
return ThreadWatcher.refresh(); return ThreadWatcher.refresh();
} }
} else if (this.status === 404) { } else if (this.status === 404) {
if (Conf['Auto Prune']) { if (SW[software].mayLackJSON && (data.last == null)) {
ThreadWatcher.db.extend({
siteID: siteID,
boardID: boardID,
threadID: threadID,
val: {
last: -1
},
rm: ['unread', 'quotingYou']
});
} else if (Conf['Auto Prune']) {
ThreadWatcher.db["delete"]({ ThreadWatcher.db["delete"]({
siteID: siteID,
boardID: boardID, boardID: boardID,
threadID: threadID threadID: threadID
}); });
} else { } else {
ThreadWatcher.db.extend({ ThreadWatcher.db.extend({
siteID: siteID,
boardID: boardID, boardID: boardID,
threadID: threadID, threadID: threadID,
val: { val: {
@ -20258,7 +20369,7 @@ ThreadWatcher = (function() {
title: excerpt, title: excerpt,
className: 'watcher-link' className: 'watcher-link'
}); });
if (ThreadWatcher.unreadEnabled && Conf['Show Unread Count'] && software === 'yotsuba' && (data.unread != null)) { if (ThreadWatcher.unreadEnabled && Conf['Show Unread Count'] && (data.unread != null)) {
count = $.el('span', { count = $.el('span', {
textContent: "(" + data.unread + ")", textContent: "(" + data.unread + ")",
className: 'watcher-unread' className: 'watcher-unread'
@ -20280,7 +20391,7 @@ ThreadWatcher = (function() {
if (data.isDead) { if (data.isDead) {
$.addClass(div, 'dead-thread'); $.addClass(div, 'dead-thread');
} }
if (ThreadWatcher.unreadEnabled && Conf['Show Unread Count'] && software === 'yotsuba') { if (ThreadWatcher.unreadEnabled && Conf['Show Unread Count']) {
if (data.unread === 0) { if (data.unread === 0) {
$.addClass(div, 'replies-read'); $.addClass(div, 'replies-read');
} }
@ -20701,17 +20812,17 @@ Unread = (function() {
} }
}, },
scroll: function() { scroll: function() {
var hash, position, root; var bottom, hash, position;
if ((hash = location.hash.match(/\d+/)) && hash[0] in Unread.thread.posts) { if ((hash = location.hash.match(/\d+/)) && hash[0] in Unread.thread.posts) {
return; return;
} }
position = Unread.positionPrev(); position = Unread.positionPrev();
while (position) { while (position) {
root = position.data.nodes.root; bottom = position.data.nodes.bottom;
if (!root.getBoundingClientRect().height) { if (!bottom.getBoundingClientRect().height) {
position = position.prev; position = position.prev;
} else { } else {
Header.scrollToIfNeeded(root, true); Header.scrollToIfNeeded(bottom, true);
break; break;
} }
} }
@ -20781,7 +20892,7 @@ Unread = (function() {
icon: Favicon.logo icon: Favicon.logo
}); });
notif.onclick = function() { notif.onclick = function() {
Header.scrollToIfNeeded(post.nodes.root, true); Header.scrollToIfNeeded(post.nodes.bottom, true);
return window.focus(); return window.focus();
}; };
return notif.onshow = function() { return notif.onshow = function() {
@ -20810,7 +20921,7 @@ Unread = (function() {
return Unread.update(); return Unread.update();
}, },
read: $.debounce(100, function(e) { read: $.debounce(100, function(e) {
var ID, count, data, ref, root; var ID, bottom, count, data, ref;
if (!Unread.posts.size && Unread.readCount !== Unread.thread.posts.keys.length) { if (!Unread.posts.size && Unread.readCount !== Unread.thread.posts.keys.length) {
Unread.saveLastReadPost(); Unread.saveLastReadPost();
} }
@ -20820,8 +20931,8 @@ Unread = (function() {
count = 0; count = 0;
while (Unread.position) { while (Unread.position) {
ref = Unread.position, ID = ref.ID, data = ref.data; ref = Unread.position, ID = ref.ID, data = ref.data;
root = data.nodes.root; bottom = data.nodes.bottom;
if (!(!root.getBoundingClientRect().height || Header.getBottomOf(root) > -1)) { if (!(!bottom.getBoundingClientRect().height || Header.getBottomOf(bottom) > -1)) {
break; break;
} }
count++; count++;
@ -20875,7 +20986,7 @@ Unread = (function() {
} }
if (Unread.hr.hidden || d.hidden || (force === true)) { if (Unread.hr.hidden || d.hidden || (force === true)) {
if ((Unread.linePosition = Unread.positionPrev())) { if ((Unread.linePosition = Unread.positionPrev())) {
$.after(Unread.linePosition.data.nodes.root, Unread.hr); $.after(Unread.linePosition.data.nodes.bottom, Unread.hr);
} else { } else {
$.rm(Unread.hr); $.rm(Unread.hr);
} }
@ -20893,7 +21004,7 @@ Unread = (function() {
d.title = "" + titleQuotingYou + titleCount + titleDead; d.title = "" + titleQuotingYou + titleCount + titleDead;
} }
Unread.saveThreadWatcherCount(); Unread.saveThreadWatcherCount();
if (Conf['Unread Favicon']) { if (Conf['Unread Favicon'] && Site.software === 'yotsuba') {
isDead = Unread.thread.isDead; isDead = Unread.thread.isDead;
Favicon.el.href = countQuotingYou ? Favicon[isDead ? 'unreadDeadY' : 'unreadY'] : count ? Favicon[isDead ? 'unreadDead' : 'unread'] : Favicon[isDead ? 'dead' : 'default']; Favicon.el.href = countQuotingYou ? Favicon[isDead ? 'unreadDeadY' : 'unreadY'] : count ? Favicon[isDead ? 'unreadDead' : 'unread'] : Favicon[isDead ? 'dead' : 'default'];
return $.add(d.head, Favicon.el); return $.add(d.head, Favicon.el);
@ -25580,7 +25691,7 @@ Main = (function() {
} }
}); });
}, },
features: [['Polyfill', Polyfill], ['Board Configuration', BoardConfig], ['Normalize URL', NormalizeURL], ['Captcha Configuration', Captcha.replace], ['Image Host Rewriting', ImageHost], ['Redirect', Redirect], ['Header', Header], ['Catalog Links', CatalogLinks], ['Settings', Settings], ['Index Generator', Index], ['Disable Autoplay', AntiAutoplay], ['Announcement Hiding', PSAHiding], ['Fourchan thingies', Fourchan], ['Color User IDs', IDColor], ['Highlight by User ID', IDHighlight], ['Count Posts by ID', IDPostCount], ['Custom CSS', CustomCSS], ['Thread Links', ThreadLinks], ['Linkify', Linkify], ['Reveal Spoilers', RemoveSpoilers], ['Resurrect Quotes', Quotify], ['Filter', Filter], ['Thread Hiding Buttons', ThreadHiding], ['Reply Hiding Buttons', PostHiding], ['Recursive', Recursive], ['Strike-through Quotes', QuoteStrikeThrough], ['Quick Reply Personas', QR.persona], ['Quick Reply', QR], ['Cooldown', QR.cooldown], ['Pass Link', PassLink], ['Menu', Menu], ['Index Generator (Menu)', Index.menu], ['Report Link', ReportLink], ['Copy Text Link', CopyTextLink], ['Thread Hiding (Menu)', ThreadHiding.menu], ['Reply Hiding (Menu)', PostHiding.menu], ['Delete Link', DeleteLink], ['Filter (Menu)', Filter.menu], ['Edit Link', QR.oekaki.menu], ['Download Link', DownloadLink], ['Archive Link', ArchiveLink], ['Quote Inlining', QuoteInline], ['Quote Previewing', QuotePreview], ['Quote Backlinks', QuoteBacklink], ['Mark Quotes of You', QuoteYou], ['Mark OP Quotes', QuoteOP], ['Mark Cross-thread Quotes', QuoteCT], ['Anonymize', Anonymize], ['Time Formatting', Time], ['Relative Post Dates', RelativeDates], ['File Info Formatting', FileInfo], ['Fappe Tyme', FappeTyme], ['Gallery', Gallery], ['Gallery (menu)', Gallery.menu], ['Sauce', Sauce], ['Image Expansion', ImageExpand], ['Image Expansion (Menu)', ImageExpand.menu], ['Reveal Spoiler Thumbnails', RevealSpoilers], ['Image Loading', ImageLoader], ['Image Hover', ImageHover], ['Volume Control', Volume], ['WEBM Metadata', Metadata], ['Comment Expansion', ExpandComment], ['Thread Expansion', ExpandThread], ['Favicon', Favicon], ['Unread', Unread], ['Unread Line in Index', UnreadIndex], ['Quote Threading', QuoteThreading], ['Thread Stats', ThreadStats], ['Thread Updater', ThreadUpdater], ['Thread Watcher', ThreadWatcher], ['Thread Watcher (Menu)', ThreadWatcher.menu], ['Mark New IPs', MarkNewIPs], ['Index Navigation', Nav], ['Keybinds', Keybinds], ['Banner', Banner], ['Flash Features', Flash], ['Reply Pruning', ReplyPruning]] features: [['Polyfill', Polyfill], ['Board Configuration', BoardConfig], ['Normalize URL', NormalizeURL], ['Captcha Configuration', Captcha.replace], ['Image Host Rewriting', ImageHost], ['Redirect', Redirect], ['Header', Header], ['Catalog Links', CatalogLinks], ['Settings', Settings], ['Index Generator', Index], ['Disable Autoplay', AntiAutoplay], ['Announcement Hiding', PSAHiding], ['Fourchan thingies', Fourchan], ['Tinyboard Glue', Tinyboard], ['Color User IDs', IDColor], ['Highlight by User ID', IDHighlight], ['Count Posts by ID', IDPostCount], ['Custom CSS', CustomCSS], ['Thread Links', ThreadLinks], ['Linkify', Linkify], ['Reveal Spoilers', RemoveSpoilers], ['Resurrect Quotes', Quotify], ['Filter', Filter], ['Thread Hiding Buttons', ThreadHiding], ['Reply Hiding Buttons', PostHiding], ['Recursive', Recursive], ['Strike-through Quotes', QuoteStrikeThrough], ['Quick Reply Personas', QR.persona], ['Quick Reply', QR], ['Cooldown', QR.cooldown], ['Pass Link', PassLink], ['Menu', Menu], ['Index Generator (Menu)', Index.menu], ['Report Link', ReportLink], ['Copy Text Link', CopyTextLink], ['Thread Hiding (Menu)', ThreadHiding.menu], ['Reply Hiding (Menu)', PostHiding.menu], ['Delete Link', DeleteLink], ['Filter (Menu)', Filter.menu], ['Edit Link', QR.oekaki.menu], ['Download Link', DownloadLink], ['Archive Link', ArchiveLink], ['Quote Inlining', QuoteInline], ['Quote Previewing', QuotePreview], ['Quote Backlinks', QuoteBacklink], ['Mark Quotes of You', QuoteYou], ['Mark OP Quotes', QuoteOP], ['Mark Cross-thread Quotes', QuoteCT], ['Anonymize', Anonymize], ['Time Formatting', Time], ['Relative Post Dates', RelativeDates], ['File Info Formatting', FileInfo], ['Fappe Tyme', FappeTyme], ['Gallery', Gallery], ['Gallery (menu)', Gallery.menu], ['Sauce', Sauce], ['Image Expansion', ImageExpand], ['Image Expansion (Menu)', ImageExpand.menu], ['Reveal Spoiler Thumbnails', RevealSpoilers], ['Image Loading', ImageLoader], ['Image Hover', ImageHover], ['Volume Control', Volume], ['WEBM Metadata', Metadata], ['Comment Expansion', ExpandComment], ['Thread Expansion', ExpandThread], ['Favicon', Favicon], ['Unread', Unread], ['Unread Line in Index', UnreadIndex], ['Quote Threading', QuoteThreading], ['Thread Stats', ThreadStats], ['Thread Updater', ThreadUpdater], ['Thread Watcher', ThreadWatcher], ['Thread Watcher (Menu)', ThreadWatcher.menu], ['Mark New IPs', MarkNewIPs], ['Index Navigation', Nav], ['Keybinds', Keybinds], ['Banner', Banner], ['Flash Features', Flash], ['Reply Pruning', ReplyPruning]]
}; };
return Main; return Main;

Binary file not shown.

View File

@ -1,6 +1,6 @@
// ==UserScript== // ==UserScript==
// @name 4chan X // @name 4chan X
// @version 1.14.5.1 // @version 1.14.5.2
// @minGMVer 1.14 // @minGMVer 1.14
// @minFFVer 26 // @minFFVer 26
// @namespace 4chan-X // @namespace 4chan-X
@ -183,7 +183,7 @@
'use strict'; 'use strict';
var $, $$, Anonymize, AntiAutoplay, ArchiveLink, Banner, Board, BoardConfig, Build, CSS, Callbacks, Captcha, CatalogLinks, CatalogThread, Config, Connection, CopyTextLink, CrossOrigin, CustomCSS, DataBoard, DeleteLink, DownloadLink, Embedding, ExpandComment, ExpandThread, FappeTyme, Favicon, Fetcher, FileInfo, Filter, Flash, Fourchan, Gallery, Get, Header, IDColor, IDHighlight, IDPostCount, ImageCommon, ImageExpand, ImageHost, ImageHover, ImageLoader, Index, Keybinds, Linkify, Main, MarkNewIPs, Menu, Metadata, Nav, NormalizeURL, Notice, PSAHiding, PassLink, Polyfill, Post, PostHiding, PostSuccessful, QR, QuoteBacklink, QuoteCT, QuoteInline, QuoteOP, QuotePreview, QuoteStrikeThrough, QuoteThreading, QuoteYou, Quotify, RandomAccessList, Recursive, Redirect, RelativeDates, RemoveSpoilers, ReplyPruning, Report, ReportLink, RevealSpoilers, SW, Sauce, Settings, ShimSet, SimpleDict, Site, Thread, ThreadHiding, ThreadLinks, ThreadStats, ThreadUpdater, ThreadWatcher, Time, UI, Unread, UnreadIndex, Volume; var $, $$, Anonymize, AntiAutoplay, ArchiveLink, Banner, Board, BoardConfig, Build, CSS, Callbacks, Captcha, CatalogLinks, CatalogThread, Config, Connection, CopyTextLink, CrossOrigin, CustomCSS, DataBoard, DeleteLink, DownloadLink, Embedding, ExpandComment, ExpandThread, FappeTyme, Favicon, Fetcher, FileInfo, Filter, Flash, Fourchan, Gallery, Get, Header, IDColor, IDHighlight, IDPostCount, ImageCommon, ImageExpand, ImageHost, ImageHover, ImageLoader, Index, Keybinds, Linkify, Main, MarkNewIPs, Menu, Metadata, Nav, NormalizeURL, Notice, PSAHiding, PassLink, Polyfill, Post, PostHiding, PostSuccessful, QR, QuoteBacklink, QuoteCT, QuoteInline, QuoteOP, QuotePreview, QuoteStrikeThrough, QuoteThreading, QuoteYou, Quotify, RandomAccessList, Recursive, Redirect, RelativeDates, RemoveSpoilers, ReplyPruning, Report, ReportLink, RevealSpoilers, SW, Sauce, Settings, ShimSet, SimpleDict, Site, Thread, ThreadHiding, ThreadLinks, ThreadStats, ThreadUpdater, ThreadWatcher, Time, Tinyboard, UI, Unread, UnreadIndex, Volume;
var Conf, E, c, d, doc, docSet, g; var Conf, E, c, d, doc, docSet, g;
@ -198,7 +198,7 @@ docSet = function() {
}; };
g = { g = {
VERSION: '1.14.5.1', VERSION: '1.14.5.2',
NAMESPACE: '4chan X.', NAMESPACE: '4chan X.',
boards: {} boards: {}
}; };
@ -2317,6 +2317,9 @@ span.hide-announcement {\n\
margin: 0;\n\ margin: 0;\n\
border-color: rgb(255,0,0);\n\ border-color: rgb(255,0,0);\n\
}\n\ }\n\
.unread-line + br {\n\
display: none;\n\
}\n\
.unread-mark-read {\n\ .unread-mark-read {\n\
float: right;\n\ float: right;\n\
clear: both;\n\ clear: both;\n\
@ -2419,6 +2422,9 @@ span.hide-announcement {\n\
-webkit-flex: 0 1 auto;\n\ -webkit-flex: 0 1 auto;\n\
flex: 0 1 auto;\n\ flex: 0 1 auto;\n\
}\n\ }\n\
.replies-quoting-you > a, #watcher-link.replies-quoting-you {\n\
color: #F00;\n\
}\n\
#thread-watcher a {\n\ #thread-watcher a {\n\
text-decoration: none;\n\ text-decoration: none;\n\
}\n\ }\n\
@ -5472,7 +5478,7 @@ CrossOrigin = (function() {
} }
return delete callbacks[url]; return delete callbacks[url];
}; };
return function(url, cb, bypassCache) { return function(url, cb, bypassCache, timeout) {
var req; var req;
if (!(((typeof GM !== "undefined" && GM !== null ? GM.xmlHttpRequest : void 0) != null) || (typeof GM_xmlhttpRequest !== "undefined" && GM_xmlhttpRequest !== null))) { if (!(((typeof GM !== "undefined" && GM !== null ? GM.xmlHttpRequest : void 0) != null) || (typeof GM_xmlhttpRequest !== "undefined" && GM_xmlhttpRequest !== null))) {
if (bypassCache) { if (bypassCache) {
@ -5493,19 +5499,21 @@ CrossOrigin = (function() {
} }
if (bypassCache) { if (bypassCache) {
delete results[url]; delete results[url];
} } else {
if (results[url]) { if (results[url]) {
cb.call(results[url]); cb.call(results[url]);
return; return;
} }
if (callbacks[url]) { if (callbacks[url]) {
callbacks[url].push(cb); callbacks[url].push(cb);
return; return;
}
} }
callbacks[url] = [cb]; callbacks[url] = [cb];
return ((typeof GM !== "undefined" && GM !== null ? GM.xmlHttpRequest : void 0) || GM_xmlhttpRequest)({ return ((typeof GM !== "undefined" && GM !== null ? GM.xmlHttpRequest : void 0) || GM_xmlhttpRequest)({
method: "GET", method: "GET",
url: url + '', url: url + '',
timeout: timeout,
onload: function(xhr) { onload: function(xhr) {
var response, status, statusText; var response, status, statusText;
status = xhr.status, statusText = xhr.statusText; status = xhr.status, statusText = xhr.statusText;
@ -5525,6 +5533,9 @@ CrossOrigin = (function() {
}, },
onabort: function() { onabort: function() {
return failure(url); return failure(url);
},
ontimeout: function() {
return failure(url);
} }
}); });
}; };
@ -5928,13 +5939,10 @@ DataBoard = (function() {
})(this), cb); })(this), cb);
}; };
DataBoard.prototype.setLastChecked = function(siteID) { DataBoard.prototype.setLastChecked = function() {
if (siteID == null) {
siteID = Site.hostname;
}
return this.save((function(_this) { return this.save((function(_this) {
return function() { return function() {
return _this.data[siteID].lastChecked = Date.now(); return _this.data.lastChecked = Date.now();
}; };
})(this)); })(this));
}; };
@ -6504,9 +6512,10 @@ Post = (function() {
this.boardID = this.board.ID; this.boardID = this.board.ID;
this.fullID = this.board + "." + this.ID; this.fullID = this.board + "." + this.ID;
this.context = this; this.context = this;
this.isReply = this.ID !== this.threadID;
root.dataset.fullID = this.fullID; root.dataset.fullID = this.fullID;
this.nodes = this.parseNodes(root); this.nodes = this.parseNodes(root);
if (!(this.isReply = this.ID !== this.threadID)) { if (!this.isReply) {
this.thread.OP = this; this.thread.OP = this;
ref = ['isSticky', 'isClosed', 'isArchived']; ref = ['isSticky', 'isClosed', 'isArchived'];
for (j = 0, len = ref.length; j < len; j++) { for (j = 0, len = ref.length; j < len; j++) {
@ -6568,6 +6577,7 @@ Post = (function() {
info = $(s.infoRoot, post); info = $(s.infoRoot, post);
nodes = { nodes = {
root: root, root: root,
bottom: this.isReply || !Site.isOPContainerThread ? root : $(s.opBottom, root),
post: post, post: post,
info: info, info: info,
comment: $(s.comment, post), comment: $(s.comment, post),
@ -7280,7 +7290,8 @@ SW = {};
SW.tinyboard = { SW.tinyboard = {
isOPContainerThread: true, isOPContainerThread: true,
disabledFeatures: ['Board Configuration', 'Normalize URL', 'Captcha Configuration', 'Image Host Rewriting', 'Index Generator', 'Announcement Hiding', 'Fourchan thingies', 'Resurrect Quotes', 'Quick Reply Personas', 'Quick Reply', 'Cooldown', 'Pass Link', 'Index Generator (Menu)', 'Report Link', 'Delete Link', 'Edit Link', 'Archive Link', 'Quote Inlining', 'Quote Previewing', 'Quote Backlinks', 'File Info Formatting', 'Fappe Tyme', 'Image Expansion', 'Image Expansion (Menu)', 'Comment Expansion', 'Thread Expansion', 'Favicon', 'Unread', 'Quote Threading', 'Thread Stats', 'Thread Updater', 'Mark New IPs', 'Banner', 'Flash Features', 'Reply Pruning'], mayLackJSON: true,
disabledFeatures: ['Board Configuration', 'Normalize URL', 'Captcha Configuration', 'Image Host Rewriting', 'Index Generator', 'Announcement Hiding', 'Fourchan thingies', 'Resurrect Quotes', 'Quick Reply Personas', 'Quick Reply', 'Cooldown', 'Pass Link', 'Index Generator (Menu)', 'Report Link', 'Delete Link', 'Edit Link', 'Archive Link', 'Quote Inlining', 'Quote Previewing', 'Quote Backlinks', 'File Info Formatting', 'Fappe Tyme', 'Image Expansion', 'Image Expansion (Menu)', 'Comment Expansion', 'Thread Expansion', 'Favicon', 'Quote Threading', 'Thread Stats', 'Thread Updater', 'Mark New IPs', 'Banner', 'Flash Features', 'Reply Pruning'],
detect: function() { detect: function() {
var i, len, m, properties, ref, root, script; var i, len, m, properties, ref, root, script;
ref = $$('script:not([src])', d.head); ref = $$('script:not([src])', d.head);
@ -7306,6 +7317,16 @@ SW = {};
var boardID, ref, siteID, threadID; var boardID, ref, siteID, threadID;
siteID = arg.siteID, boardID = arg.boardID, threadID = arg.threadID; siteID = arg.siteID, boardID = arg.boardID, threadID = arg.threadID;
return "" + (((ref = Conf['siteProperties'][siteID]) != null ? ref.root : void 0) || ("http://" + siteID + "/")) + boardID + "/res/" + threadID + ".html"; return "" + (((ref = Conf['siteProperties'][siteID]) != null ? ref.root : void 0) || ("http://" + siteID + "/")) + boardID + "/res/" + threadID + ".html";
},
threadJSON: function(arg) {
var boardID, ref, root, siteID, threadID;
siteID = arg.siteID, boardID = arg.boardID, threadID = arg.threadID;
root = (ref = Conf['siteProperties'][siteID]) != null ? ref.root : void 0;
if (root) {
return "" + root + boardID + "/res/" + threadID + ".json";
} else {
return '';
}
} }
}, },
selectors: { selectors: {
@ -7314,6 +7335,7 @@ SW = {};
threadDivider: 'div[id^="thread_"] > hr:last-of-type', threadDivider: 'div[id^="thread_"] > hr:last-of-type',
summary: '.omitted', summary: '.omitted',
postContainer: '.reply', postContainer: '.reply',
opBottom: '.op',
infoRoot: '.intro', infoRoot: '.intro',
info: { info: {
subject: '.subject', subject: '.subject',
@ -7348,7 +7370,8 @@ SW = {};
postContainer: 'div[starts-with(@id,"reply_") or starts-with(@id,"thread_")]' postContainer: 'div[starts-with(@id,"reply_") or starts-with(@id,"thread_")]'
}, },
regexp: { regexp: {
quotelink: /\/([^\/]+)\/res\/(\d+)\.html#(\d+)$/ quotelink: /\/([^\/]+)\/res\/(\d+)\.html#(\d+)$/,
quotelinkHTML: /<a [^>]*\bhref="[^"]*\/([^\/]+)\/res\/(\d+)\.html#(\d+)"/g
}, },
bgColoredEl: function() { bgColoredEl: function() {
return $.el('div', { return $.el('div', {
@ -7415,6 +7438,11 @@ SW = {};
var boardID, threadID; var boardID, threadID;
boardID = arg.boardID, threadID = arg.threadID; boardID = arg.boardID, threadID = arg.threadID;
return location.protocol + "//" + (BoardConfig.domain(boardID)) + "/" + boardID + "/thread/" + threadID; return location.protocol + "//" + (BoardConfig.domain(boardID)) + "/" + boardID + "/thread/" + threadID;
},
threadJSON: function(arg) {
var boardID, threadID;
boardID = arg.boardID, threadID = arg.threadID;
return location.protocol + "//a.4cdn.org/" + boardID + "/thread/" + threadID + ".json";
} }
}, },
selectors: { selectors: {
@ -7462,7 +7490,8 @@ SW = {};
postContainer: 'div[contains(@class,"postContainer")]' postContainer: 'div[contains(@class,"postContainer")]'
}, },
regexp: { regexp: {
quotelink: /^https?:\/\/boards\.4chan(?:nel)?\.org\/+([^\/]+)\/+thread\/+(\d+)(?:[\/?][^#]*)?(?:#p(\d+))?$/ quotelink: /^https?:\/\/boards\.4chan(?:nel)?\.org\/+([^\/]+)\/+thread\/+(\d+)(?:[\/?][^#]*)?(?:#p(\d+))?$/,
quotelinkHTML: /<a [^>]*\bhref="(?:(?:\/\/boards\.4chan(?:nel)?\.org)?\/([^\/]+)\/thread\/)?(\d+)?(?:#p(\d+))?"/g
}, },
bgColoredEl: function() { bgColoredEl: function() {
return $.el('div', { return $.el('div', {
@ -7588,6 +7617,9 @@ SW = {};
node = ref1[k]; node = ref1[k];
$.replace(node, [$.tn('[code]')].concat(slice.call(node.childNodes), [$.tn('[/code]')])); $.replace(node, [$.tn('[code]')].concat(slice.call(node.childNodes), [$.tn('[/code]')]));
} }
},
hasCORS: function(url) {
return url.split('/').slice(0, 3).join('/') === location.protocol + '//a.4cdn.org';
} }
}; };
@ -18874,6 +18906,47 @@ Time = (function() {
}).call(this); }).call(this);
Tinyboard = (function() {
var Tinyboard;
Tinyboard = {
init: function() {
if (Site.software !== 'tinyboard') {
return;
}
if (g.VIEW === 'thread') {
return Main.ready(function() {
return $.global(function() {
var boardID, ref, threadID;
ref = document.currentScript.dataset, boardID = ref.boardID, threadID = ref.threadID;
threadID = +threadID;
return window.$(document).on('new_post', function(e, post) {
var detail, event, postID;
postID = +post.id.match(/\d*$/)[0];
detail = {
boardID: boardID,
threadID: threadID,
postID: postID
};
event = new CustomEvent('QRPostSuccessful', {
bubbles: true,
detail: detail
});
return document.dispatchEvent(event);
});
}, {
boardID: g.BOARD.ID,
threadID: g.THREADID
});
});
}
}
};
return Tinyboard;
}).call(this);
Favicon = (function() { Favicon = (function() {
var Favicon; var Favicon;
@ -19764,9 +19837,6 @@ ThreadWatcher = (function() {
$.on(sc, 'click', this.toggleWatcher); $.on(sc, 'click', this.toggleWatcher);
$.on(this.refreshButton, 'click', this.buttonFetchAll); $.on(this.refreshButton, 'click', this.buttonFetchAll);
$.on(this.closeButton, 'click', this.toggleWatcher); $.on(this.closeButton, 'click', this.toggleWatcher);
if (Site.software !== 'yotsuba') {
this.refreshButton.hidden = true;
}
this.menu.addHeaderMenuEntry(); this.menu.addHeaderMenuEntry();
$.onExists(doc, 'body', this.addDialog); $.onExists(doc, 'body', this.addDialog);
switch (g.VIEW) { switch (g.VIEW) {
@ -20039,9 +20109,6 @@ ThreadWatcher = (function() {
}, },
fetchAuto: function() { fetchAuto: function() {
var db, interval, now, ref; var db, interval, now, ref;
if (Site.software !== 'yotsuba') {
return;
}
clearTimeout(ThreadWatcher.timeout); clearTimeout(ThreadWatcher.timeout);
if (!Conf['Auto Update Thread Watcher']) { if (!Conf['Auto Update Thread Watcher']) {
return; return;
@ -20049,7 +20116,7 @@ ThreadWatcher = (function() {
db = ThreadWatcher.db; db = ThreadWatcher.db;
interval = ThreadWatcher.unreadEnabled && Conf['Show Unread Count'] ? 5 * $.MINUTE : 2 * $.HOUR; interval = ThreadWatcher.unreadEnabled && Conf['Show Unread Count'] ? 5 * $.MINUTE : 2 * $.HOUR;
now = Date.now(); now = Date.now();
if (!((now - interval < (ref = db.data[Site.hostname].lastChecked || 0) && ref <= now) || d.hidden || !d.hasFocus())) { if (!((now - interval < (ref = db.data.lastChecked || 0) && ref <= now) || d.hidden || !d.hasFocus())) {
ThreadWatcher.fetchAllStatus(); ThreadWatcher.fetchAllStatus();
db.setLastChecked(); db.setLastChecked();
} }
@ -20064,9 +20131,6 @@ ThreadWatcher = (function() {
}, },
fetchAllStatus: function() { fetchAllStatus: function() {
var db, dbs, i, len1, n, results; var db, dbs, i, len1, n, results;
if (Site.software !== 'yotsuba') {
return;
}
dbs = [ThreadWatcher.db, ThreadWatcher.unreaddb, QuoteYou.db].filter(function(x) { dbs = [ThreadWatcher.db, ThreadWatcher.unreaddb, QuoteYou.db].filter(function(x) {
return x; return x;
}); });
@ -20088,66 +20152,96 @@ ThreadWatcher = (function() {
return results; return results;
}, },
fetchStatus: function(thread, force) { fetchStatus: function(thread, force) {
var boardID, data, req, siteID, threadID; var base, boardID, data, ref, ref1, req, siteID, software, threadID, url;
siteID = thread.siteID, boardID = thread.boardID, threadID = thread.threadID, data = thread.data; siteID = thread.siteID, boardID = thread.boardID, threadID = thread.threadID, data = thread.data;
if (!(Site.software === 'yotsuba' && siteID === Site.hostname)) { software = (ref = Conf['siteProperties'][siteID]) != null ? ref.software : void 0;
url = (ref1 = SW[software]) != null ? typeof (base = ref1.urls).threadJSON === "function" ? base.threadJSON({
siteID: siteID,
boardID: boardID,
threadID: threadID
}) : void 0 : void 0;
if (!url) {
return; return;
} }
if (data.isDead && !force) { if (data.isDead && !force) {
return; return;
} }
if (data.last === -1) {
return;
}
if (ThreadWatcher.requests.length === 0) { if (ThreadWatcher.requests.length === 0) {
ThreadWatcher.status.textContent = '...'; ThreadWatcher.status.textContent = '...';
$.addClass(ThreadWatcher.refreshButton, 'fa-spin'); $.addClass(ThreadWatcher.refreshButton, 'fa-spin');
} }
req = $.ajax(location.protocol + "//a.4cdn.org/" + boardID + "/thread/" + threadID + ".json", { if ((typeof Site.hasCORS === "function" ? Site.hasCORS(url) : void 0) || url.split('/').slice(0, 3).join('/') === location.origin) {
onloadend: function() { req = $.ajax(url, {
onloadend: function() {
return ThreadWatcher.parseStatus.call(this, thread);
},
timeout: $.MINUTE
});
} else {
req = {
abort: function() {
return req.aborted = true;
}
};
CrossOrigin.json(url, function() {
if (req.aborted) {
return;
}
return ThreadWatcher.parseStatus.call(this, thread); return ThreadWatcher.parseStatus.call(this, thread);
}, }, true, $.MINUTE);
timeout: $.MINUTE }
}, {
whenModified: force ? false : 'ThreadWatcher'
});
return ThreadWatcher.requests.push(req); return ThreadWatcher.requests.push(req);
}, },
parseStatus: function(arg) { parseStatus: function(arg) {
var boardID, data, i, isDead, lastReadPost, len1, match, postObj, quotesYou, quotingYou, ref, ref1, ref2, regexp, threadID, unread, youOP; var boardID, data, i, isDead, last, lastReadPost, len1, match, postObj, quotesYou, quotingYou, ref, ref1, ref2, ref3, regexp, siteID, software, threadID, unread, updated, youOP;
boardID = arg.boardID, threadID = arg.threadID, data = arg.data; siteID = arg.siteID, boardID = arg.boardID, threadID = arg.threadID, data = arg.data;
ThreadWatcher.fetched++; ThreadWatcher.fetched++;
if (ThreadWatcher.fetched === ThreadWatcher.requests.length) { if (ThreadWatcher.fetched === ThreadWatcher.requests.length) {
ThreadWatcher.clearRequests(); ThreadWatcher.clearRequests();
} else { } else {
ThreadWatcher.status.textContent = (Math.round(ThreadWatcher.fetched / ThreadWatcher.requests.length * 100)) + "%"; ThreadWatcher.status.textContent = (Math.round(ThreadWatcher.fetched / ThreadWatcher.requests.length * 100)) + "%";
} }
software = (ref = Conf['siteProperties'][siteID]) != null ? ref.software : void 0;
if (this.status === 200 && this.response) { if (this.status === 200 && this.response) {
last = this.response.posts[this.response.posts.length - 1].no;
isDead = !!this.response.posts[0].archived; isDead = !!this.response.posts[0].archived;
if (isDead && Conf['Auto Prune']) { if (isDead && Conf['Auto Prune']) {
ThreadWatcher.db["delete"]({ ThreadWatcher.db["delete"]({
siteID: siteID,
boardID: boardID, boardID: boardID,
threadID: threadID threadID: threadID
}); });
ThreadWatcher.refresh(); ThreadWatcher.refresh();
return; return;
} }
if (last === data.last && isDead === data.isDead) {
return;
}
lastReadPost = ThreadWatcher.unreaddb.get({ lastReadPost = ThreadWatcher.unreaddb.get({
siteID: siteID,
boardID: boardID, boardID: boardID,
threadID: threadID, threadID: threadID,
defaultValue: 0 defaultValue: 0
}); });
unread = 0; unread = 0;
quotingYou = false; quotingYou = false;
youOP = !!((ref = QuoteYou.db) != null ? ref.get({ youOP = !!((ref1 = QuoteYou.db) != null ? ref1.get({
siteID: siteID,
boardID: boardID, boardID: boardID,
threadID: threadID, threadID: threadID,
postID: threadID postID: threadID
}) : void 0); }) : void 0);
ref1 = this.response.posts; ref2 = this.response.posts;
for (i = 0, len1 = ref1.length; i < len1; i++) { for (i = 0, len1 = ref2.length; i < len1; i++) {
postObj = ref1[i]; postObj = ref2[i];
if (!(postObj.no > lastReadPost)) { if (!(postObj.no > lastReadPost)) {
continue; continue;
} }
if ((ref2 = QuoteYou.db) != null ? ref2.get({ if ((ref3 = QuoteYou.db) != null ? ref3.get({
siteID: siteID,
boardID: boardID, boardID: boardID,
threadID: threadID, threadID: threadID,
postID: postObj.no postID: postObj.no
@ -20163,9 +20257,11 @@ ThreadWatcher = (function() {
continue; continue;
} }
quotesYou = false; quotesYou = false;
regexp = /<a [^>]*\bhref="(?:(?:\/\/boards\.4chan(?:nel)?\.org)?\/([^\/]+)\/thread\/)?(\d+)?(?:#p(\d+))?"/g; regexp = SW[software].regexp.quotelinkHTML;
regexp.lastIndex = 0;
while (match = regexp.exec(postObj.com)) { while (match = regexp.exec(postObj.com)) {
if (QuoteYou.db.get({ if (QuoteYou.db.get({
siteID: siteID,
boardID: match[1] || boardID, boardID: match[1] || boardID,
threadID: match[2] || threadID, threadID: match[2] || threadID,
postID: match[3] || match[2] || threadID postID: match[3] || match[2] || threadID
@ -20178,26 +20274,41 @@ ThreadWatcher = (function() {
quotingYou = true; quotingYou = true;
} }
} }
if (isDead !== data.isDead || unread !== data.unread || quotingYou !== data.quotingYou) { updated = isDead !== data.isDead || unread !== data.unread || quotingYou !== data.quotingYou;
ThreadWatcher.db.extend({ ThreadWatcher.db.extend({
boardID: boardID, siteID: siteID,
threadID: threadID, boardID: boardID,
val: { threadID: threadID,
isDead: isDead, val: {
unread: unread, last: last,
quotingYou: quotingYou isDead: isDead,
} unread: unread,
}); quotingYou: quotingYou
}
});
if (updated) {
return ThreadWatcher.refresh(); return ThreadWatcher.refresh();
} }
} else if (this.status === 404) { } else if (this.status === 404) {
if (Conf['Auto Prune']) { if (SW[software].mayLackJSON && (data.last == null)) {
ThreadWatcher.db.extend({
siteID: siteID,
boardID: boardID,
threadID: threadID,
val: {
last: -1
},
rm: ['unread', 'quotingYou']
});
} else if (Conf['Auto Prune']) {
ThreadWatcher.db["delete"]({ ThreadWatcher.db["delete"]({
siteID: siteID,
boardID: boardID, boardID: boardID,
threadID: threadID threadID: threadID
}); });
} else { } else {
ThreadWatcher.db.extend({ ThreadWatcher.db.extend({
siteID: siteID,
boardID: boardID, boardID: boardID,
threadID: threadID, threadID: threadID,
val: { val: {
@ -20258,7 +20369,7 @@ ThreadWatcher = (function() {
title: excerpt, title: excerpt,
className: 'watcher-link' className: 'watcher-link'
}); });
if (ThreadWatcher.unreadEnabled && Conf['Show Unread Count'] && software === 'yotsuba' && (data.unread != null)) { if (ThreadWatcher.unreadEnabled && Conf['Show Unread Count'] && (data.unread != null)) {
count = $.el('span', { count = $.el('span', {
textContent: "(" + data.unread + ")", textContent: "(" + data.unread + ")",
className: 'watcher-unread' className: 'watcher-unread'
@ -20280,7 +20391,7 @@ ThreadWatcher = (function() {
if (data.isDead) { if (data.isDead) {
$.addClass(div, 'dead-thread'); $.addClass(div, 'dead-thread');
} }
if (ThreadWatcher.unreadEnabled && Conf['Show Unread Count'] && software === 'yotsuba') { if (ThreadWatcher.unreadEnabled && Conf['Show Unread Count']) {
if (data.unread === 0) { if (data.unread === 0) {
$.addClass(div, 'replies-read'); $.addClass(div, 'replies-read');
} }
@ -20701,17 +20812,17 @@ Unread = (function() {
} }
}, },
scroll: function() { scroll: function() {
var hash, position, root; var bottom, hash, position;
if ((hash = location.hash.match(/\d+/)) && hash[0] in Unread.thread.posts) { if ((hash = location.hash.match(/\d+/)) && hash[0] in Unread.thread.posts) {
return; return;
} }
position = Unread.positionPrev(); position = Unread.positionPrev();
while (position) { while (position) {
root = position.data.nodes.root; bottom = position.data.nodes.bottom;
if (!root.getBoundingClientRect().height) { if (!bottom.getBoundingClientRect().height) {
position = position.prev; position = position.prev;
} else { } else {
Header.scrollToIfNeeded(root, true); Header.scrollToIfNeeded(bottom, true);
break; break;
} }
} }
@ -20781,7 +20892,7 @@ Unread = (function() {
icon: Favicon.logo icon: Favicon.logo
}); });
notif.onclick = function() { notif.onclick = function() {
Header.scrollToIfNeeded(post.nodes.root, true); Header.scrollToIfNeeded(post.nodes.bottom, true);
return window.focus(); return window.focus();
}; };
return notif.onshow = function() { return notif.onshow = function() {
@ -20810,7 +20921,7 @@ Unread = (function() {
return Unread.update(); return Unread.update();
}, },
read: $.debounce(100, function(e) { read: $.debounce(100, function(e) {
var ID, count, data, ref, root; var ID, bottom, count, data, ref;
if (!Unread.posts.size && Unread.readCount !== Unread.thread.posts.keys.length) { if (!Unread.posts.size && Unread.readCount !== Unread.thread.posts.keys.length) {
Unread.saveLastReadPost(); Unread.saveLastReadPost();
} }
@ -20820,8 +20931,8 @@ Unread = (function() {
count = 0; count = 0;
while (Unread.position) { while (Unread.position) {
ref = Unread.position, ID = ref.ID, data = ref.data; ref = Unread.position, ID = ref.ID, data = ref.data;
root = data.nodes.root; bottom = data.nodes.bottom;
if (!(!root.getBoundingClientRect().height || Header.getBottomOf(root) > -1)) { if (!(!bottom.getBoundingClientRect().height || Header.getBottomOf(bottom) > -1)) {
break; break;
} }
count++; count++;
@ -20875,7 +20986,7 @@ Unread = (function() {
} }
if (Unread.hr.hidden || d.hidden || (force === true)) { if (Unread.hr.hidden || d.hidden || (force === true)) {
if ((Unread.linePosition = Unread.positionPrev())) { if ((Unread.linePosition = Unread.positionPrev())) {
$.after(Unread.linePosition.data.nodes.root, Unread.hr); $.after(Unread.linePosition.data.nodes.bottom, Unread.hr);
} else { } else {
$.rm(Unread.hr); $.rm(Unread.hr);
} }
@ -20893,7 +21004,7 @@ Unread = (function() {
d.title = "" + titleQuotingYou + titleCount + titleDead; d.title = "" + titleQuotingYou + titleCount + titleDead;
} }
Unread.saveThreadWatcherCount(); Unread.saveThreadWatcherCount();
if (Conf['Unread Favicon']) { if (Conf['Unread Favicon'] && Site.software === 'yotsuba') {
isDead = Unread.thread.isDead; isDead = Unread.thread.isDead;
Favicon.el.href = countQuotingYou ? Favicon[isDead ? 'unreadDeadY' : 'unreadY'] : count ? Favicon[isDead ? 'unreadDead' : 'unread'] : Favicon[isDead ? 'dead' : 'default']; Favicon.el.href = countQuotingYou ? Favicon[isDead ? 'unreadDeadY' : 'unreadY'] : count ? Favicon[isDead ? 'unreadDead' : 'unread'] : Favicon[isDead ? 'dead' : 'default'];
return $.add(d.head, Favicon.el); return $.add(d.head, Favicon.el);
@ -25580,7 +25691,7 @@ Main = (function() {
} }
}); });
}, },
features: [['Polyfill', Polyfill], ['Board Configuration', BoardConfig], ['Normalize URL', NormalizeURL], ['Captcha Configuration', Captcha.replace], ['Image Host Rewriting', ImageHost], ['Redirect', Redirect], ['Header', Header], ['Catalog Links', CatalogLinks], ['Settings', Settings], ['Index Generator', Index], ['Disable Autoplay', AntiAutoplay], ['Announcement Hiding', PSAHiding], ['Fourchan thingies', Fourchan], ['Color User IDs', IDColor], ['Highlight by User ID', IDHighlight], ['Count Posts by ID', IDPostCount], ['Custom CSS', CustomCSS], ['Thread Links', ThreadLinks], ['Linkify', Linkify], ['Reveal Spoilers', RemoveSpoilers], ['Resurrect Quotes', Quotify], ['Filter', Filter], ['Thread Hiding Buttons', ThreadHiding], ['Reply Hiding Buttons', PostHiding], ['Recursive', Recursive], ['Strike-through Quotes', QuoteStrikeThrough], ['Quick Reply Personas', QR.persona], ['Quick Reply', QR], ['Cooldown', QR.cooldown], ['Pass Link', PassLink], ['Menu', Menu], ['Index Generator (Menu)', Index.menu], ['Report Link', ReportLink], ['Copy Text Link', CopyTextLink], ['Thread Hiding (Menu)', ThreadHiding.menu], ['Reply Hiding (Menu)', PostHiding.menu], ['Delete Link', DeleteLink], ['Filter (Menu)', Filter.menu], ['Edit Link', QR.oekaki.menu], ['Download Link', DownloadLink], ['Archive Link', ArchiveLink], ['Quote Inlining', QuoteInline], ['Quote Previewing', QuotePreview], ['Quote Backlinks', QuoteBacklink], ['Mark Quotes of You', QuoteYou], ['Mark OP Quotes', QuoteOP], ['Mark Cross-thread Quotes', QuoteCT], ['Anonymize', Anonymize], ['Time Formatting', Time], ['Relative Post Dates', RelativeDates], ['File Info Formatting', FileInfo], ['Fappe Tyme', FappeTyme], ['Gallery', Gallery], ['Gallery (menu)', Gallery.menu], ['Sauce', Sauce], ['Image Expansion', ImageExpand], ['Image Expansion (Menu)', ImageExpand.menu], ['Reveal Spoiler Thumbnails', RevealSpoilers], ['Image Loading', ImageLoader], ['Image Hover', ImageHover], ['Volume Control', Volume], ['WEBM Metadata', Metadata], ['Comment Expansion', ExpandComment], ['Thread Expansion', ExpandThread], ['Favicon', Favicon], ['Unread', Unread], ['Unread Line in Index', UnreadIndex], ['Quote Threading', QuoteThreading], ['Thread Stats', ThreadStats], ['Thread Updater', ThreadUpdater], ['Thread Watcher', ThreadWatcher], ['Thread Watcher (Menu)', ThreadWatcher.menu], ['Mark New IPs', MarkNewIPs], ['Index Navigation', Nav], ['Keybinds', Keybinds], ['Banner', Banner], ['Flash Features', Flash], ['Reply Pruning', ReplyPruning]] features: [['Polyfill', Polyfill], ['Board Configuration', BoardConfig], ['Normalize URL', NormalizeURL], ['Captcha Configuration', Captcha.replace], ['Image Host Rewriting', ImageHost], ['Redirect', Redirect], ['Header', Header], ['Catalog Links', CatalogLinks], ['Settings', Settings], ['Index Generator', Index], ['Disable Autoplay', AntiAutoplay], ['Announcement Hiding', PSAHiding], ['Fourchan thingies', Fourchan], ['Tinyboard Glue', Tinyboard], ['Color User IDs', IDColor], ['Highlight by User ID', IDHighlight], ['Count Posts by ID', IDPostCount], ['Custom CSS', CustomCSS], ['Thread Links', ThreadLinks], ['Linkify', Linkify], ['Reveal Spoilers', RemoveSpoilers], ['Resurrect Quotes', Quotify], ['Filter', Filter], ['Thread Hiding Buttons', ThreadHiding], ['Reply Hiding Buttons', PostHiding], ['Recursive', Recursive], ['Strike-through Quotes', QuoteStrikeThrough], ['Quick Reply Personas', QR.persona], ['Quick Reply', QR], ['Cooldown', QR.cooldown], ['Pass Link', PassLink], ['Menu', Menu], ['Index Generator (Menu)', Index.menu], ['Report Link', ReportLink], ['Copy Text Link', CopyTextLink], ['Thread Hiding (Menu)', ThreadHiding.menu], ['Reply Hiding (Menu)', PostHiding.menu], ['Delete Link', DeleteLink], ['Filter (Menu)', Filter.menu], ['Edit Link', QR.oekaki.menu], ['Download Link', DownloadLink], ['Archive Link', ArchiveLink], ['Quote Inlining', QuoteInline], ['Quote Previewing', QuotePreview], ['Quote Backlinks', QuoteBacklink], ['Mark Quotes of You', QuoteYou], ['Mark OP Quotes', QuoteOP], ['Mark Cross-thread Quotes', QuoteCT], ['Anonymize', Anonymize], ['Time Formatting', Time], ['Relative Post Dates', RelativeDates], ['File Info Formatting', FileInfo], ['Fappe Tyme', FappeTyme], ['Gallery', Gallery], ['Gallery (menu)', Gallery.menu], ['Sauce', Sauce], ['Image Expansion', ImageExpand], ['Image Expansion (Menu)', ImageExpand.menu], ['Reveal Spoiler Thumbnails', RevealSpoilers], ['Image Loading', ImageLoader], ['Image Hover', ImageHover], ['Volume Control', Volume], ['WEBM Metadata', Metadata], ['Comment Expansion', ExpandComment], ['Thread Expansion', ExpandThread], ['Favicon', Favicon], ['Unread', Unread], ['Unread Line in Index', UnreadIndex], ['Quote Threading', QuoteThreading], ['Thread Stats', ThreadStats], ['Thread Updater', ThreadUpdater], ['Thread Watcher', ThreadWatcher], ['Thread Watcher (Menu)', ThreadWatcher.menu], ['Mark New IPs', MarkNewIPs], ['Index Navigation', Nav], ['Keybinds', Keybinds], ['Banner', Banner], ['Flash Features', Flash], ['Reply Pruning', ReplyPruning]]
}; };
return Main; return Main;

Binary file not shown.

View File

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

View File

@ -1,6 +1,6 @@
// ==UserScript== // ==UserScript==
// @name 4chan X // @name 4chan X
// @version 1.14.5.1 // @version 1.14.5.2
// @minGMVer 1.14 // @minGMVer 1.14
// @minFFVer 26 // @minFFVer 26
// @namespace 4chan-X // @namespace 4chan-X
@ -183,7 +183,7 @@
'use strict'; 'use strict';
var $, $$, Anonymize, AntiAutoplay, ArchiveLink, Banner, Board, BoardConfig, Build, CSS, Callbacks, Captcha, CatalogLinks, CatalogThread, Config, Connection, CopyTextLink, CrossOrigin, CustomCSS, DataBoard, DeleteLink, DownloadLink, Embedding, ExpandComment, ExpandThread, FappeTyme, Favicon, Fetcher, FileInfo, Filter, Flash, Fourchan, Gallery, Get, Header, IDColor, IDHighlight, IDPostCount, ImageCommon, ImageExpand, ImageHost, ImageHover, ImageLoader, Index, Keybinds, Linkify, Main, MarkNewIPs, Menu, Metadata, Nav, NormalizeURL, Notice, PSAHiding, PassLink, Polyfill, Post, PostHiding, PostSuccessful, QR, QuoteBacklink, QuoteCT, QuoteInline, QuoteOP, QuotePreview, QuoteStrikeThrough, QuoteThreading, QuoteYou, Quotify, RandomAccessList, Recursive, Redirect, RelativeDates, RemoveSpoilers, ReplyPruning, Report, ReportLink, RevealSpoilers, SW, Sauce, Settings, ShimSet, SimpleDict, Site, Thread, ThreadHiding, ThreadLinks, ThreadStats, ThreadUpdater, ThreadWatcher, Time, UI, Unread, UnreadIndex, Volume; var $, $$, Anonymize, AntiAutoplay, ArchiveLink, Banner, Board, BoardConfig, Build, CSS, Callbacks, Captcha, CatalogLinks, CatalogThread, Config, Connection, CopyTextLink, CrossOrigin, CustomCSS, DataBoard, DeleteLink, DownloadLink, Embedding, ExpandComment, ExpandThread, FappeTyme, Favicon, Fetcher, FileInfo, Filter, Flash, Fourchan, Gallery, Get, Header, IDColor, IDHighlight, IDPostCount, ImageCommon, ImageExpand, ImageHost, ImageHover, ImageLoader, Index, Keybinds, Linkify, Main, MarkNewIPs, Menu, Metadata, Nav, NormalizeURL, Notice, PSAHiding, PassLink, Polyfill, Post, PostHiding, PostSuccessful, QR, QuoteBacklink, QuoteCT, QuoteInline, QuoteOP, QuotePreview, QuoteStrikeThrough, QuoteThreading, QuoteYou, Quotify, RandomAccessList, Recursive, Redirect, RelativeDates, RemoveSpoilers, ReplyPruning, Report, ReportLink, RevealSpoilers, SW, Sauce, Settings, ShimSet, SimpleDict, Site, Thread, ThreadHiding, ThreadLinks, ThreadStats, ThreadUpdater, ThreadWatcher, Time, Tinyboard, UI, Unread, UnreadIndex, Volume;
var Conf, E, c, d, doc, docSet, g; var Conf, E, c, d, doc, docSet, g;
@ -198,7 +198,7 @@ docSet = function() {
}; };
g = { g = {
VERSION: '1.14.5.1', VERSION: '1.14.5.2',
NAMESPACE: '4chan X.', NAMESPACE: '4chan X.',
boards: {} boards: {}
}; };
@ -2317,6 +2317,9 @@ span.hide-announcement {\n\
margin: 0;\n\ margin: 0;\n\
border-color: rgb(255,0,0);\n\ border-color: rgb(255,0,0);\n\
}\n\ }\n\
.unread-line + br {\n\
display: none;\n\
}\n\
.unread-mark-read {\n\ .unread-mark-read {\n\
float: right;\n\ float: right;\n\
clear: both;\n\ clear: both;\n\
@ -2419,6 +2422,9 @@ span.hide-announcement {\n\
-webkit-flex: 0 1 auto;\n\ -webkit-flex: 0 1 auto;\n\
flex: 0 1 auto;\n\ flex: 0 1 auto;\n\
}\n\ }\n\
.replies-quoting-you > a, #watcher-link.replies-quoting-you {\n\
color: #F00;\n\
}\n\
#thread-watcher a {\n\ #thread-watcher a {\n\
text-decoration: none;\n\ text-decoration: none;\n\
}\n\ }\n\
@ -5472,7 +5478,7 @@ CrossOrigin = (function() {
} }
return delete callbacks[url]; return delete callbacks[url];
}; };
return function(url, cb, bypassCache) { return function(url, cb, bypassCache, timeout) {
var req; var req;
if (!(((typeof GM !== "undefined" && GM !== null ? GM.xmlHttpRequest : void 0) != null) || (typeof GM_xmlhttpRequest !== "undefined" && GM_xmlhttpRequest !== null))) { if (!(((typeof GM !== "undefined" && GM !== null ? GM.xmlHttpRequest : void 0) != null) || (typeof GM_xmlhttpRequest !== "undefined" && GM_xmlhttpRequest !== null))) {
if (bypassCache) { if (bypassCache) {
@ -5493,19 +5499,21 @@ CrossOrigin = (function() {
} }
if (bypassCache) { if (bypassCache) {
delete results[url]; delete results[url];
} } else {
if (results[url]) { if (results[url]) {
cb.call(results[url]); cb.call(results[url]);
return; return;
} }
if (callbacks[url]) { if (callbacks[url]) {
callbacks[url].push(cb); callbacks[url].push(cb);
return; return;
}
} }
callbacks[url] = [cb]; callbacks[url] = [cb];
return ((typeof GM !== "undefined" && GM !== null ? GM.xmlHttpRequest : void 0) || GM_xmlhttpRequest)({ return ((typeof GM !== "undefined" && GM !== null ? GM.xmlHttpRequest : void 0) || GM_xmlhttpRequest)({
method: "GET", method: "GET",
url: url + '', url: url + '',
timeout: timeout,
onload: function(xhr) { onload: function(xhr) {
var response, status, statusText; var response, status, statusText;
status = xhr.status, statusText = xhr.statusText; status = xhr.status, statusText = xhr.statusText;
@ -5525,6 +5533,9 @@ CrossOrigin = (function() {
}, },
onabort: function() { onabort: function() {
return failure(url); return failure(url);
},
ontimeout: function() {
return failure(url);
} }
}); });
}; };
@ -5928,13 +5939,10 @@ DataBoard = (function() {
})(this), cb); })(this), cb);
}; };
DataBoard.prototype.setLastChecked = function(siteID) { DataBoard.prototype.setLastChecked = function() {
if (siteID == null) {
siteID = Site.hostname;
}
return this.save((function(_this) { return this.save((function(_this) {
return function() { return function() {
return _this.data[siteID].lastChecked = Date.now(); return _this.data.lastChecked = Date.now();
}; };
})(this)); })(this));
}; };
@ -6504,9 +6512,10 @@ Post = (function() {
this.boardID = this.board.ID; this.boardID = this.board.ID;
this.fullID = this.board + "." + this.ID; this.fullID = this.board + "." + this.ID;
this.context = this; this.context = this;
this.isReply = this.ID !== this.threadID;
root.dataset.fullID = this.fullID; root.dataset.fullID = this.fullID;
this.nodes = this.parseNodes(root); this.nodes = this.parseNodes(root);
if (!(this.isReply = this.ID !== this.threadID)) { if (!this.isReply) {
this.thread.OP = this; this.thread.OP = this;
ref = ['isSticky', 'isClosed', 'isArchived']; ref = ['isSticky', 'isClosed', 'isArchived'];
for (j = 0, len = ref.length; j < len; j++) { for (j = 0, len = ref.length; j < len; j++) {
@ -6568,6 +6577,7 @@ Post = (function() {
info = $(s.infoRoot, post); info = $(s.infoRoot, post);
nodes = { nodes = {
root: root, root: root,
bottom: this.isReply || !Site.isOPContainerThread ? root : $(s.opBottom, root),
post: post, post: post,
info: info, info: info,
comment: $(s.comment, post), comment: $(s.comment, post),
@ -7280,7 +7290,8 @@ SW = {};
SW.tinyboard = { SW.tinyboard = {
isOPContainerThread: true, isOPContainerThread: true,
disabledFeatures: ['Board Configuration', 'Normalize URL', 'Captcha Configuration', 'Image Host Rewriting', 'Index Generator', 'Announcement Hiding', 'Fourchan thingies', 'Resurrect Quotes', 'Quick Reply Personas', 'Quick Reply', 'Cooldown', 'Pass Link', 'Index Generator (Menu)', 'Report Link', 'Delete Link', 'Edit Link', 'Archive Link', 'Quote Inlining', 'Quote Previewing', 'Quote Backlinks', 'File Info Formatting', 'Fappe Tyme', 'Image Expansion', 'Image Expansion (Menu)', 'Comment Expansion', 'Thread Expansion', 'Favicon', 'Unread', 'Quote Threading', 'Thread Stats', 'Thread Updater', 'Mark New IPs', 'Banner', 'Flash Features', 'Reply Pruning'], mayLackJSON: true,
disabledFeatures: ['Board Configuration', 'Normalize URL', 'Captcha Configuration', 'Image Host Rewriting', 'Index Generator', 'Announcement Hiding', 'Fourchan thingies', 'Resurrect Quotes', 'Quick Reply Personas', 'Quick Reply', 'Cooldown', 'Pass Link', 'Index Generator (Menu)', 'Report Link', 'Delete Link', 'Edit Link', 'Archive Link', 'Quote Inlining', 'Quote Previewing', 'Quote Backlinks', 'File Info Formatting', 'Fappe Tyme', 'Image Expansion', 'Image Expansion (Menu)', 'Comment Expansion', 'Thread Expansion', 'Favicon', 'Quote Threading', 'Thread Stats', 'Thread Updater', 'Mark New IPs', 'Banner', 'Flash Features', 'Reply Pruning'],
detect: function() { detect: function() {
var i, len, m, properties, ref, root, script; var i, len, m, properties, ref, root, script;
ref = $$('script:not([src])', d.head); ref = $$('script:not([src])', d.head);
@ -7306,6 +7317,16 @@ SW = {};
var boardID, ref, siteID, threadID; var boardID, ref, siteID, threadID;
siteID = arg.siteID, boardID = arg.boardID, threadID = arg.threadID; siteID = arg.siteID, boardID = arg.boardID, threadID = arg.threadID;
return "" + (((ref = Conf['siteProperties'][siteID]) != null ? ref.root : void 0) || ("http://" + siteID + "/")) + boardID + "/res/" + threadID + ".html"; return "" + (((ref = Conf['siteProperties'][siteID]) != null ? ref.root : void 0) || ("http://" + siteID + "/")) + boardID + "/res/" + threadID + ".html";
},
threadJSON: function(arg) {
var boardID, ref, root, siteID, threadID;
siteID = arg.siteID, boardID = arg.boardID, threadID = arg.threadID;
root = (ref = Conf['siteProperties'][siteID]) != null ? ref.root : void 0;
if (root) {
return "" + root + boardID + "/res/" + threadID + ".json";
} else {
return '';
}
} }
}, },
selectors: { selectors: {
@ -7314,6 +7335,7 @@ SW = {};
threadDivider: 'div[id^="thread_"] > hr:last-of-type', threadDivider: 'div[id^="thread_"] > hr:last-of-type',
summary: '.omitted', summary: '.omitted',
postContainer: '.reply', postContainer: '.reply',
opBottom: '.op',
infoRoot: '.intro', infoRoot: '.intro',
info: { info: {
subject: '.subject', subject: '.subject',
@ -7348,7 +7370,8 @@ SW = {};
postContainer: 'div[starts-with(@id,"reply_") or starts-with(@id,"thread_")]' postContainer: 'div[starts-with(@id,"reply_") or starts-with(@id,"thread_")]'
}, },
regexp: { regexp: {
quotelink: /\/([^\/]+)\/res\/(\d+)\.html#(\d+)$/ quotelink: /\/([^\/]+)\/res\/(\d+)\.html#(\d+)$/,
quotelinkHTML: /<a [^>]*\bhref="[^"]*\/([^\/]+)\/res\/(\d+)\.html#(\d+)"/g
}, },
bgColoredEl: function() { bgColoredEl: function() {
return $.el('div', { return $.el('div', {
@ -7415,6 +7438,11 @@ SW = {};
var boardID, threadID; var boardID, threadID;
boardID = arg.boardID, threadID = arg.threadID; boardID = arg.boardID, threadID = arg.threadID;
return location.protocol + "//" + (BoardConfig.domain(boardID)) + "/" + boardID + "/thread/" + threadID; return location.protocol + "//" + (BoardConfig.domain(boardID)) + "/" + boardID + "/thread/" + threadID;
},
threadJSON: function(arg) {
var boardID, threadID;
boardID = arg.boardID, threadID = arg.threadID;
return location.protocol + "//a.4cdn.org/" + boardID + "/thread/" + threadID + ".json";
} }
}, },
selectors: { selectors: {
@ -7462,7 +7490,8 @@ SW = {};
postContainer: 'div[contains(@class,"postContainer")]' postContainer: 'div[contains(@class,"postContainer")]'
}, },
regexp: { regexp: {
quotelink: /^https?:\/\/boards\.4chan(?:nel)?\.org\/+([^\/]+)\/+thread\/+(\d+)(?:[\/?][^#]*)?(?:#p(\d+))?$/ quotelink: /^https?:\/\/boards\.4chan(?:nel)?\.org\/+([^\/]+)\/+thread\/+(\d+)(?:[\/?][^#]*)?(?:#p(\d+))?$/,
quotelinkHTML: /<a [^>]*\bhref="(?:(?:\/\/boards\.4chan(?:nel)?\.org)?\/([^\/]+)\/thread\/)?(\d+)?(?:#p(\d+))?"/g
}, },
bgColoredEl: function() { bgColoredEl: function() {
return $.el('div', { return $.el('div', {
@ -7588,6 +7617,9 @@ SW = {};
node = ref1[k]; node = ref1[k];
$.replace(node, [$.tn('[code]')].concat(slice.call(node.childNodes), [$.tn('[/code]')])); $.replace(node, [$.tn('[code]')].concat(slice.call(node.childNodes), [$.tn('[/code]')]));
} }
},
hasCORS: function(url) {
return url.split('/').slice(0, 3).join('/') === location.protocol + '//a.4cdn.org';
} }
}; };
@ -18874,6 +18906,47 @@ Time = (function() {
}).call(this); }).call(this);
Tinyboard = (function() {
var Tinyboard;
Tinyboard = {
init: function() {
if (Site.software !== 'tinyboard') {
return;
}
if (g.VIEW === 'thread') {
return Main.ready(function() {
return $.global(function() {
var boardID, ref, threadID;
ref = document.currentScript.dataset, boardID = ref.boardID, threadID = ref.threadID;
threadID = +threadID;
return window.$(document).on('new_post', function(e, post) {
var detail, event, postID;
postID = +post.id.match(/\d*$/)[0];
detail = {
boardID: boardID,
threadID: threadID,
postID: postID
};
event = new CustomEvent('QRPostSuccessful', {
bubbles: true,
detail: detail
});
return document.dispatchEvent(event);
});
}, {
boardID: g.BOARD.ID,
threadID: g.THREADID
});
});
}
}
};
return Tinyboard;
}).call(this);
Favicon = (function() { Favicon = (function() {
var Favicon; var Favicon;
@ -19764,9 +19837,6 @@ ThreadWatcher = (function() {
$.on(sc, 'click', this.toggleWatcher); $.on(sc, 'click', this.toggleWatcher);
$.on(this.refreshButton, 'click', this.buttonFetchAll); $.on(this.refreshButton, 'click', this.buttonFetchAll);
$.on(this.closeButton, 'click', this.toggleWatcher); $.on(this.closeButton, 'click', this.toggleWatcher);
if (Site.software !== 'yotsuba') {
this.refreshButton.hidden = true;
}
this.menu.addHeaderMenuEntry(); this.menu.addHeaderMenuEntry();
$.onExists(doc, 'body', this.addDialog); $.onExists(doc, 'body', this.addDialog);
switch (g.VIEW) { switch (g.VIEW) {
@ -20039,9 +20109,6 @@ ThreadWatcher = (function() {
}, },
fetchAuto: function() { fetchAuto: function() {
var db, interval, now, ref; var db, interval, now, ref;
if (Site.software !== 'yotsuba') {
return;
}
clearTimeout(ThreadWatcher.timeout); clearTimeout(ThreadWatcher.timeout);
if (!Conf['Auto Update Thread Watcher']) { if (!Conf['Auto Update Thread Watcher']) {
return; return;
@ -20049,7 +20116,7 @@ ThreadWatcher = (function() {
db = ThreadWatcher.db; db = ThreadWatcher.db;
interval = ThreadWatcher.unreadEnabled && Conf['Show Unread Count'] ? 5 * $.MINUTE : 2 * $.HOUR; interval = ThreadWatcher.unreadEnabled && Conf['Show Unread Count'] ? 5 * $.MINUTE : 2 * $.HOUR;
now = Date.now(); now = Date.now();
if (!((now - interval < (ref = db.data[Site.hostname].lastChecked || 0) && ref <= now) || d.hidden || !d.hasFocus())) { if (!((now - interval < (ref = db.data.lastChecked || 0) && ref <= now) || d.hidden || !d.hasFocus())) {
ThreadWatcher.fetchAllStatus(); ThreadWatcher.fetchAllStatus();
db.setLastChecked(); db.setLastChecked();
} }
@ -20064,9 +20131,6 @@ ThreadWatcher = (function() {
}, },
fetchAllStatus: function() { fetchAllStatus: function() {
var db, dbs, i, len1, n, results; var db, dbs, i, len1, n, results;
if (Site.software !== 'yotsuba') {
return;
}
dbs = [ThreadWatcher.db, ThreadWatcher.unreaddb, QuoteYou.db].filter(function(x) { dbs = [ThreadWatcher.db, ThreadWatcher.unreaddb, QuoteYou.db].filter(function(x) {
return x; return x;
}); });
@ -20088,66 +20152,96 @@ ThreadWatcher = (function() {
return results; return results;
}, },
fetchStatus: function(thread, force) { fetchStatus: function(thread, force) {
var boardID, data, req, siteID, threadID; var base, boardID, data, ref, ref1, req, siteID, software, threadID, url;
siteID = thread.siteID, boardID = thread.boardID, threadID = thread.threadID, data = thread.data; siteID = thread.siteID, boardID = thread.boardID, threadID = thread.threadID, data = thread.data;
if (!(Site.software === 'yotsuba' && siteID === Site.hostname)) { software = (ref = Conf['siteProperties'][siteID]) != null ? ref.software : void 0;
url = (ref1 = SW[software]) != null ? typeof (base = ref1.urls).threadJSON === "function" ? base.threadJSON({
siteID: siteID,
boardID: boardID,
threadID: threadID
}) : void 0 : void 0;
if (!url) {
return; return;
} }
if (data.isDead && !force) { if (data.isDead && !force) {
return; return;
} }
if (data.last === -1) {
return;
}
if (ThreadWatcher.requests.length === 0) { if (ThreadWatcher.requests.length === 0) {
ThreadWatcher.status.textContent = '...'; ThreadWatcher.status.textContent = '...';
$.addClass(ThreadWatcher.refreshButton, 'fa-spin'); $.addClass(ThreadWatcher.refreshButton, 'fa-spin');
} }
req = $.ajax(location.protocol + "//a.4cdn.org/" + boardID + "/thread/" + threadID + ".json", { if ((typeof Site.hasCORS === "function" ? Site.hasCORS(url) : void 0) || url.split('/').slice(0, 3).join('/') === location.origin) {
onloadend: function() { req = $.ajax(url, {
onloadend: function() {
return ThreadWatcher.parseStatus.call(this, thread);
},
timeout: $.MINUTE
});
} else {
req = {
abort: function() {
return req.aborted = true;
}
};
CrossOrigin.json(url, function() {
if (req.aborted) {
return;
}
return ThreadWatcher.parseStatus.call(this, thread); return ThreadWatcher.parseStatus.call(this, thread);
}, }, true, $.MINUTE);
timeout: $.MINUTE }
}, {
whenModified: force ? false : 'ThreadWatcher'
});
return ThreadWatcher.requests.push(req); return ThreadWatcher.requests.push(req);
}, },
parseStatus: function(arg) { parseStatus: function(arg) {
var boardID, data, i, isDead, lastReadPost, len1, match, postObj, quotesYou, quotingYou, ref, ref1, ref2, regexp, threadID, unread, youOP; var boardID, data, i, isDead, last, lastReadPost, len1, match, postObj, quotesYou, quotingYou, ref, ref1, ref2, ref3, regexp, siteID, software, threadID, unread, updated, youOP;
boardID = arg.boardID, threadID = arg.threadID, data = arg.data; siteID = arg.siteID, boardID = arg.boardID, threadID = arg.threadID, data = arg.data;
ThreadWatcher.fetched++; ThreadWatcher.fetched++;
if (ThreadWatcher.fetched === ThreadWatcher.requests.length) { if (ThreadWatcher.fetched === ThreadWatcher.requests.length) {
ThreadWatcher.clearRequests(); ThreadWatcher.clearRequests();
} else { } else {
ThreadWatcher.status.textContent = (Math.round(ThreadWatcher.fetched / ThreadWatcher.requests.length * 100)) + "%"; ThreadWatcher.status.textContent = (Math.round(ThreadWatcher.fetched / ThreadWatcher.requests.length * 100)) + "%";
} }
software = (ref = Conf['siteProperties'][siteID]) != null ? ref.software : void 0;
if (this.status === 200 && this.response) { if (this.status === 200 && this.response) {
last = this.response.posts[this.response.posts.length - 1].no;
isDead = !!this.response.posts[0].archived; isDead = !!this.response.posts[0].archived;
if (isDead && Conf['Auto Prune']) { if (isDead && Conf['Auto Prune']) {
ThreadWatcher.db["delete"]({ ThreadWatcher.db["delete"]({
siteID: siteID,
boardID: boardID, boardID: boardID,
threadID: threadID threadID: threadID
}); });
ThreadWatcher.refresh(); ThreadWatcher.refresh();
return; return;
} }
if (last === data.last && isDead === data.isDead) {
return;
}
lastReadPost = ThreadWatcher.unreaddb.get({ lastReadPost = ThreadWatcher.unreaddb.get({
siteID: siteID,
boardID: boardID, boardID: boardID,
threadID: threadID, threadID: threadID,
defaultValue: 0 defaultValue: 0
}); });
unread = 0; unread = 0;
quotingYou = false; quotingYou = false;
youOP = !!((ref = QuoteYou.db) != null ? ref.get({ youOP = !!((ref1 = QuoteYou.db) != null ? ref1.get({
siteID: siteID,
boardID: boardID, boardID: boardID,
threadID: threadID, threadID: threadID,
postID: threadID postID: threadID
}) : void 0); }) : void 0);
ref1 = this.response.posts; ref2 = this.response.posts;
for (i = 0, len1 = ref1.length; i < len1; i++) { for (i = 0, len1 = ref2.length; i < len1; i++) {
postObj = ref1[i]; postObj = ref2[i];
if (!(postObj.no > lastReadPost)) { if (!(postObj.no > lastReadPost)) {
continue; continue;
} }
if ((ref2 = QuoteYou.db) != null ? ref2.get({ if ((ref3 = QuoteYou.db) != null ? ref3.get({
siteID: siteID,
boardID: boardID, boardID: boardID,
threadID: threadID, threadID: threadID,
postID: postObj.no postID: postObj.no
@ -20163,9 +20257,11 @@ ThreadWatcher = (function() {
continue; continue;
} }
quotesYou = false; quotesYou = false;
regexp = /<a [^>]*\bhref="(?:(?:\/\/boards\.4chan(?:nel)?\.org)?\/([^\/]+)\/thread\/)?(\d+)?(?:#p(\d+))?"/g; regexp = SW[software].regexp.quotelinkHTML;
regexp.lastIndex = 0;
while (match = regexp.exec(postObj.com)) { while (match = regexp.exec(postObj.com)) {
if (QuoteYou.db.get({ if (QuoteYou.db.get({
siteID: siteID,
boardID: match[1] || boardID, boardID: match[1] || boardID,
threadID: match[2] || threadID, threadID: match[2] || threadID,
postID: match[3] || match[2] || threadID postID: match[3] || match[2] || threadID
@ -20178,26 +20274,41 @@ ThreadWatcher = (function() {
quotingYou = true; quotingYou = true;
} }
} }
if (isDead !== data.isDead || unread !== data.unread || quotingYou !== data.quotingYou) { updated = isDead !== data.isDead || unread !== data.unread || quotingYou !== data.quotingYou;
ThreadWatcher.db.extend({ ThreadWatcher.db.extend({
boardID: boardID, siteID: siteID,
threadID: threadID, boardID: boardID,
val: { threadID: threadID,
isDead: isDead, val: {
unread: unread, last: last,
quotingYou: quotingYou isDead: isDead,
} unread: unread,
}); quotingYou: quotingYou
}
});
if (updated) {
return ThreadWatcher.refresh(); return ThreadWatcher.refresh();
} }
} else if (this.status === 404) { } else if (this.status === 404) {
if (Conf['Auto Prune']) { if (SW[software].mayLackJSON && (data.last == null)) {
ThreadWatcher.db.extend({
siteID: siteID,
boardID: boardID,
threadID: threadID,
val: {
last: -1
},
rm: ['unread', 'quotingYou']
});
} else if (Conf['Auto Prune']) {
ThreadWatcher.db["delete"]({ ThreadWatcher.db["delete"]({
siteID: siteID,
boardID: boardID, boardID: boardID,
threadID: threadID threadID: threadID
}); });
} else { } else {
ThreadWatcher.db.extend({ ThreadWatcher.db.extend({
siteID: siteID,
boardID: boardID, boardID: boardID,
threadID: threadID, threadID: threadID,
val: { val: {
@ -20258,7 +20369,7 @@ ThreadWatcher = (function() {
title: excerpt, title: excerpt,
className: 'watcher-link' className: 'watcher-link'
}); });
if (ThreadWatcher.unreadEnabled && Conf['Show Unread Count'] && software === 'yotsuba' && (data.unread != null)) { if (ThreadWatcher.unreadEnabled && Conf['Show Unread Count'] && (data.unread != null)) {
count = $.el('span', { count = $.el('span', {
textContent: "(" + data.unread + ")", textContent: "(" + data.unread + ")",
className: 'watcher-unread' className: 'watcher-unread'
@ -20280,7 +20391,7 @@ ThreadWatcher = (function() {
if (data.isDead) { if (data.isDead) {
$.addClass(div, 'dead-thread'); $.addClass(div, 'dead-thread');
} }
if (ThreadWatcher.unreadEnabled && Conf['Show Unread Count'] && software === 'yotsuba') { if (ThreadWatcher.unreadEnabled && Conf['Show Unread Count']) {
if (data.unread === 0) { if (data.unread === 0) {
$.addClass(div, 'replies-read'); $.addClass(div, 'replies-read');
} }
@ -20701,17 +20812,17 @@ Unread = (function() {
} }
}, },
scroll: function() { scroll: function() {
var hash, position, root; var bottom, hash, position;
if ((hash = location.hash.match(/\d+/)) && hash[0] in Unread.thread.posts) { if ((hash = location.hash.match(/\d+/)) && hash[0] in Unread.thread.posts) {
return; return;
} }
position = Unread.positionPrev(); position = Unread.positionPrev();
while (position) { while (position) {
root = position.data.nodes.root; bottom = position.data.nodes.bottom;
if (!root.getBoundingClientRect().height) { if (!bottom.getBoundingClientRect().height) {
position = position.prev; position = position.prev;
} else { } else {
Header.scrollToIfNeeded(root, true); Header.scrollToIfNeeded(bottom, true);
break; break;
} }
} }
@ -20781,7 +20892,7 @@ Unread = (function() {
icon: Favicon.logo icon: Favicon.logo
}); });
notif.onclick = function() { notif.onclick = function() {
Header.scrollToIfNeeded(post.nodes.root, true); Header.scrollToIfNeeded(post.nodes.bottom, true);
return window.focus(); return window.focus();
}; };
return notif.onshow = function() { return notif.onshow = function() {
@ -20810,7 +20921,7 @@ Unread = (function() {
return Unread.update(); return Unread.update();
}, },
read: $.debounce(100, function(e) { read: $.debounce(100, function(e) {
var ID, count, data, ref, root; var ID, bottom, count, data, ref;
if (!Unread.posts.size && Unread.readCount !== Unread.thread.posts.keys.length) { if (!Unread.posts.size && Unread.readCount !== Unread.thread.posts.keys.length) {
Unread.saveLastReadPost(); Unread.saveLastReadPost();
} }
@ -20820,8 +20931,8 @@ Unread = (function() {
count = 0; count = 0;
while (Unread.position) { while (Unread.position) {
ref = Unread.position, ID = ref.ID, data = ref.data; ref = Unread.position, ID = ref.ID, data = ref.data;
root = data.nodes.root; bottom = data.nodes.bottom;
if (!(!root.getBoundingClientRect().height || Header.getBottomOf(root) > -1)) { if (!(!bottom.getBoundingClientRect().height || Header.getBottomOf(bottom) > -1)) {
break; break;
} }
count++; count++;
@ -20875,7 +20986,7 @@ Unread = (function() {
} }
if (Unread.hr.hidden || d.hidden || (force === true)) { if (Unread.hr.hidden || d.hidden || (force === true)) {
if ((Unread.linePosition = Unread.positionPrev())) { if ((Unread.linePosition = Unread.positionPrev())) {
$.after(Unread.linePosition.data.nodes.root, Unread.hr); $.after(Unread.linePosition.data.nodes.bottom, Unread.hr);
} else { } else {
$.rm(Unread.hr); $.rm(Unread.hr);
} }
@ -20893,7 +21004,7 @@ Unread = (function() {
d.title = "" + titleQuotingYou + titleCount + titleDead; d.title = "" + titleQuotingYou + titleCount + titleDead;
} }
Unread.saveThreadWatcherCount(); Unread.saveThreadWatcherCount();
if (Conf['Unread Favicon']) { if (Conf['Unread Favicon'] && Site.software === 'yotsuba') {
isDead = Unread.thread.isDead; isDead = Unread.thread.isDead;
Favicon.el.href = countQuotingYou ? Favicon[isDead ? 'unreadDeadY' : 'unreadY'] : count ? Favicon[isDead ? 'unreadDead' : 'unread'] : Favicon[isDead ? 'dead' : 'default']; Favicon.el.href = countQuotingYou ? Favicon[isDead ? 'unreadDeadY' : 'unreadY'] : count ? Favicon[isDead ? 'unreadDead' : 'unread'] : Favicon[isDead ? 'dead' : 'default'];
return $.add(d.head, Favicon.el); return $.add(d.head, Favicon.el);
@ -25580,7 +25691,7 @@ Main = (function() {
} }
}); });
}, },
features: [['Polyfill', Polyfill], ['Board Configuration', BoardConfig], ['Normalize URL', NormalizeURL], ['Captcha Configuration', Captcha.replace], ['Image Host Rewriting', ImageHost], ['Redirect', Redirect], ['Header', Header], ['Catalog Links', CatalogLinks], ['Settings', Settings], ['Index Generator', Index], ['Disable Autoplay', AntiAutoplay], ['Announcement Hiding', PSAHiding], ['Fourchan thingies', Fourchan], ['Color User IDs', IDColor], ['Highlight by User ID', IDHighlight], ['Count Posts by ID', IDPostCount], ['Custom CSS', CustomCSS], ['Thread Links', ThreadLinks], ['Linkify', Linkify], ['Reveal Spoilers', RemoveSpoilers], ['Resurrect Quotes', Quotify], ['Filter', Filter], ['Thread Hiding Buttons', ThreadHiding], ['Reply Hiding Buttons', PostHiding], ['Recursive', Recursive], ['Strike-through Quotes', QuoteStrikeThrough], ['Quick Reply Personas', QR.persona], ['Quick Reply', QR], ['Cooldown', QR.cooldown], ['Pass Link', PassLink], ['Menu', Menu], ['Index Generator (Menu)', Index.menu], ['Report Link', ReportLink], ['Copy Text Link', CopyTextLink], ['Thread Hiding (Menu)', ThreadHiding.menu], ['Reply Hiding (Menu)', PostHiding.menu], ['Delete Link', DeleteLink], ['Filter (Menu)', Filter.menu], ['Edit Link', QR.oekaki.menu], ['Download Link', DownloadLink], ['Archive Link', ArchiveLink], ['Quote Inlining', QuoteInline], ['Quote Previewing', QuotePreview], ['Quote Backlinks', QuoteBacklink], ['Mark Quotes of You', QuoteYou], ['Mark OP Quotes', QuoteOP], ['Mark Cross-thread Quotes', QuoteCT], ['Anonymize', Anonymize], ['Time Formatting', Time], ['Relative Post Dates', RelativeDates], ['File Info Formatting', FileInfo], ['Fappe Tyme', FappeTyme], ['Gallery', Gallery], ['Gallery (menu)', Gallery.menu], ['Sauce', Sauce], ['Image Expansion', ImageExpand], ['Image Expansion (Menu)', ImageExpand.menu], ['Reveal Spoiler Thumbnails', RevealSpoilers], ['Image Loading', ImageLoader], ['Image Hover', ImageHover], ['Volume Control', Volume], ['WEBM Metadata', Metadata], ['Comment Expansion', ExpandComment], ['Thread Expansion', ExpandThread], ['Favicon', Favicon], ['Unread', Unread], ['Unread Line in Index', UnreadIndex], ['Quote Threading', QuoteThreading], ['Thread Stats', ThreadStats], ['Thread Updater', ThreadUpdater], ['Thread Watcher', ThreadWatcher], ['Thread Watcher (Menu)', ThreadWatcher.menu], ['Mark New IPs', MarkNewIPs], ['Index Navigation', Nav], ['Keybinds', Keybinds], ['Banner', Banner], ['Flash Features', Flash], ['Reply Pruning', ReplyPruning]] features: [['Polyfill', Polyfill], ['Board Configuration', BoardConfig], ['Normalize URL', NormalizeURL], ['Captcha Configuration', Captcha.replace], ['Image Host Rewriting', ImageHost], ['Redirect', Redirect], ['Header', Header], ['Catalog Links', CatalogLinks], ['Settings', Settings], ['Index Generator', Index], ['Disable Autoplay', AntiAutoplay], ['Announcement Hiding', PSAHiding], ['Fourchan thingies', Fourchan], ['Tinyboard Glue', Tinyboard], ['Color User IDs', IDColor], ['Highlight by User ID', IDHighlight], ['Count Posts by ID', IDPostCount], ['Custom CSS', CustomCSS], ['Thread Links', ThreadLinks], ['Linkify', Linkify], ['Reveal Spoilers', RemoveSpoilers], ['Resurrect Quotes', Quotify], ['Filter', Filter], ['Thread Hiding Buttons', ThreadHiding], ['Reply Hiding Buttons', PostHiding], ['Recursive', Recursive], ['Strike-through Quotes', QuoteStrikeThrough], ['Quick Reply Personas', QR.persona], ['Quick Reply', QR], ['Cooldown', QR.cooldown], ['Pass Link', PassLink], ['Menu', Menu], ['Index Generator (Menu)', Index.menu], ['Report Link', ReportLink], ['Copy Text Link', CopyTextLink], ['Thread Hiding (Menu)', ThreadHiding.menu], ['Reply Hiding (Menu)', PostHiding.menu], ['Delete Link', DeleteLink], ['Filter (Menu)', Filter.menu], ['Edit Link', QR.oekaki.menu], ['Download Link', DownloadLink], ['Archive Link', ArchiveLink], ['Quote Inlining', QuoteInline], ['Quote Previewing', QuotePreview], ['Quote Backlinks', QuoteBacklink], ['Mark Quotes of You', QuoteYou], ['Mark OP Quotes', QuoteOP], ['Mark Cross-thread Quotes', QuoteCT], ['Anonymize', Anonymize], ['Time Formatting', Time], ['Relative Post Dates', RelativeDates], ['File Info Formatting', FileInfo], ['Fappe Tyme', FappeTyme], ['Gallery', Gallery], ['Gallery (menu)', Gallery.menu], ['Sauce', Sauce], ['Image Expansion', ImageExpand], ['Image Expansion (Menu)', ImageExpand.menu], ['Reveal Spoiler Thumbnails', RevealSpoilers], ['Image Loading', ImageLoader], ['Image Hover', ImageHover], ['Volume Control', Volume], ['WEBM Metadata', Metadata], ['Comment Expansion', ExpandComment], ['Thread Expansion', ExpandThread], ['Favicon', Favicon], ['Unread', Unread], ['Unread Line in Index', UnreadIndex], ['Quote Threading', QuoteThreading], ['Thread Stats', ThreadStats], ['Thread Updater', ThreadUpdater], ['Thread Watcher', ThreadWatcher], ['Thread Watcher (Menu)', ThreadWatcher.menu], ['Mark New IPs', MarkNewIPs], ['Index Navigation', Nav], ['Keybinds', Keybinds], ['Banner', Banner], ['Flash Features', Flash], ['Reply Pruning', ReplyPruning]]
}; };
return Main; return Main;

Binary file not shown.

View File

@ -3,7 +3,7 @@
"4chan-x@4chan-x.net": { "4chan-x@4chan-x.net": {
"updates": [ "updates": [
{ {
"version": "1.14.5.1", "version": "1.14.5.2",
"update_link": "https://www.4chan-x.net/builds/4chan-X-beta.crx" "update_link": "https://www.4chan-x.net/builds/4chan-X-beta.crx"
} }
] ]

View File

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

View File

@ -3,7 +3,7 @@
"4chan-x@4chan-x.net": { "4chan-x@4chan-x.net": {
"updates": [ "updates": [
{ {
"version": "1.14.5.1", "version": "1.14.5.2",
"update_link": "https://www.4chan-x.net/builds/4chan-X.crx" "update_link": "https://www.4chan-x.net/builds/4chan-X.crx"
} }
] ]

View File

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

View File

@ -1,4 +1,4 @@
{ {
"version": "1.14.5.1", "version": "1.14.5.2",
"date": "2018-12-06T17:15:24.488Z" "date": "2018-12-07T05:18:16.194Z"
} }