Release 4chan X v1.10.4.0.

This commit is contained in:
ccd0 2015-03-09 02:50:29 -07:00
parent 0c45d35da6
commit 2e9980fee4
13 changed files with 467 additions and 609 deletions

View File

@ -2,6 +2,14 @@ Sometimes the changelog has notes (not comprehensive) acknowledging people's wor
The links to individual versions below are to copies of the script with the update URL removed. If you want automatic updates, install the script from the links on the [main page](https://github.com/ccd0/4chan-x). The links to individual versions below are to copies of the script with the update URL removed. If you want automatic updates, install the script from the links on the [main page](https://github.com/ccd0/4chan-x).
### v1.10.4
**v1.10.4.0** *(2015-03-09)* - [[Firefox](https://raw.githubusercontent.com/ccd0/4chan-x/1.10.4.0/builds/4chan-X-noupdate.user.js "Firefox version")] [[Chromium](https://raw.githubusercontent.com/ccd0/4chan-x/1.10.4.0/builds/4chan-X-noupdate.crx "Chromium version")]
- Based on v1.10.3.9.
- Add `Ignore Offline Status` option in the Updater header submenu to continue auto-updating even when your browser reports you are offline.
- Fix `Auto Scroll` not scrolling to the first new post.
- Restore `deletedPosts` and `deletedFiles` fields of the `ThreadUpdate` event, which will now each contain an array of the relevant posts' full IDs.
### v1.10.3 ### v1.10.3
**v1.10.3.9** *(2015-03-07)* - [[Firefox](https://raw.githubusercontent.com/ccd0/4chan-x/1.10.3.9/builds/4chan-X-noupdate.user.js "Firefox version")] [[Chromium](https://raw.githubusercontent.com/ccd0/4chan-x/1.10.3.9/builds/4chan-X-noupdate.crx "Chromium version")] **v1.10.3.9** *(2015-03-07)* - [[Firefox](https://raw.githubusercontent.com/ccd0/4chan-x/1.10.3.9/builds/4chan-X-noupdate.user.js "Firefox version")] [[Chromium](https://raw.githubusercontent.com/ccd0/4chan-x/1.10.3.9/builds/4chan-X-noupdate.crx "Chromium version")]

Binary file not shown.

View File

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

View File

@ -1,7 +1,7 @@
// Generated by CoffeeScript // Generated by CoffeeScript
// ==UserScript== // ==UserScript==
// @name 4chan X beta // @name 4chan X beta
// @version 1.10.3.9 // @version 1.10.4.0
// @minGMVer 1.14 // @minGMVer 1.14
// @minFFVer 26 // @minFFVer 26
// @namespace 4chan-X // @namespace 4chan-X
@ -377,6 +377,7 @@
'Bottom Scroll': [false, 'Always scroll to the bottom, not the first new post. Useful for event threads.'], 'Bottom Scroll': [false, 'Always scroll to the bottom, not the first new post. Useful for event threads.'],
'Scroll BG': [false, 'Auto-scroll background tabs.'], 'Scroll BG': [false, 'Auto-scroll background tabs.'],
'Auto Update': [true, 'Automatically fetch new posts.'], 'Auto Update': [true, 'Automatically fetch new posts.'],
'Ignore Offline Status': [false, 'Update even if your browser reports you are offline.'],
'Optional Increase': [false, 'Increase the intervals between updates on threads without new posts.'] 'Optional Increase': [false, 'Increase the intervals between updates on threads without new posts.']
}, },
'Interval': 30 'Interval': 30
@ -394,7 +395,7 @@
doc = d.documentElement; doc = d.documentElement;
g = { g = {
VERSION: '1.10.3.9', VERSION: '1.10.4.0',
NAMESPACE: '4chan X.', NAMESPACE: '4chan X.',
NAME: '4chan X', NAME: '4chan X',
FAQ: 'https://github.com/ccd0/4chan-x/wiki/Frequently-Asked-Questions', FAQ: 'https://github.com/ccd0/4chan-x/wiki/Frequently-Asked-Questions',
@ -1418,35 +1419,6 @@
} }
}; };
Post.prototype.resurrect = function() {
var clone, k, len1, len2, q, quotelink, ref, ref1, strong;
delete this.isDead;
$.rmClass(this.nodes.root, 'deleted-post');
strong = $('strong.warning', this.nodes.info);
if (this.file && this.file.isDead) {
strong.textContent = '[File deleted]';
} else {
$.rm(strong);
}
if (this.isClone) {
return;
}
ref = this.clones;
for (k = 0, len1 = ref.length; k < len1; k++) {
clone = ref[k];
clone.resurrect();
}
ref1 = Get.allQuotelinksLinkingTo(this);
for (q = 0, len2 = ref1.length; q < len2; q++) {
quotelink = ref1[q];
if (!($.hasClass(quotelink, 'deadlink'))) {
continue;
}
quotelink.textContent = quotelink.textContent.replace('\u00A0(Dead)', '');
$.rmClass(quotelink, 'deadlink');
}
};
Post.prototype.collect = function() { Post.prototype.collect = function() {
this.kill(); this.kill();
g.posts.rm(this.fullID); g.posts.rm(this.fullID);
@ -3565,9 +3537,6 @@
}, },
update: function(state) { update: function(state) {
var now, ref, ref1; var now, ref, ref1;
if (!navigator.onLine) {
return;
}
delete Index.pageNum; delete Index.pageNum;
if ((ref = Index.req) != null) { if ((ref = Index.req) != null) {
ref.abort(); ref.abort();
@ -7591,7 +7560,6 @@
postID: postID, postID: postID,
val: true val: true
}); });
ThreadUpdater.postID = postID;
$.event('QRPostSuccessful', { $.event('QRPostSuccessful', {
boardID: g.BOARD.ID, boardID: g.BOARD.ID,
threadID: threadID, threadID: threadID,
@ -11808,59 +11776,30 @@
}); });
}, },
node: function() { node: function() {
var x;
MarkNewIPs.ipCount = this.ipCount; MarkNewIPs.ipCount = this.ipCount;
MarkNewIPs.postIDs = (function() {
var k, len1, ref, results;
ref = this.posts.keys;
results = [];
for (k = 0, len1 = ref.length; k < len1; k++) {
x = ref[k];
results.push(+x);
}
return results;
}).call(this);
return $.on(d, 'ThreadUpdate', MarkNewIPs.onUpdate); return $.on(d, 'ThreadUpdate', MarkNewIPs.onUpdate);
}, },
onUpdate: function(e) { onUpdate: function(e) {
var added, fullID, i, ipCount, k, len1, len2, len3, len4, newPosts, obj, postIDs, q, ref, ref1, removed, u, w, x; var deletedPosts, fullID, i, ipCount, k, len1, len2, newPosts, q, ref;
ref = e.detail, ipCount = ref.ipCount, newPosts = ref.newPosts; ref = e.detail, ipCount = ref.ipCount, newPosts = ref.newPosts, deletedPosts = ref.deletedPosts;
postIDs = ThreadUpdater.postIDs;
if (ipCount == null) { if (ipCount == null) {
return; return;
} }
if (newPosts.length) { switch (ipCount - MarkNewIPs.ipCount) {
obj = {}; case newPosts.length:
ref1 = MarkNewIPs.postIDs; i = MarkNewIPs.ipCount;
for (k = 0, len1 = ref1.length; k < len1; k++) { for (k = 0, len1 = newPosts.length; k < len1; k++) {
x = ref1[k]; fullID = newPosts[k];
obj[x] = true; MarkNewIPs.markNew(g.posts[fullID], ++i);
} }
added = 0; break;
for (q = 0, len2 = postIDs.length; q < len2; q++) { case -deletedPosts.length:
x = postIDs[q]; for (q = 0, len2 = newPosts.length; q < len2; q++) {
if (!(x in obj)) { fullID = newPosts[q];
added++; MarkNewIPs.markOld(g.posts[fullID]);
} }
}
removed = MarkNewIPs.postIDs.length + added - postIDs.length;
switch (ipCount - MarkNewIPs.ipCount) {
case added:
i = MarkNewIPs.ipCount;
for (u = 0, len3 = newPosts.length; u < len3; u++) {
fullID = newPosts[u];
MarkNewIPs.markNew(g.posts[fullID], ++i);
}
break;
case -removed:
for (w = 0, len4 = newPosts.length; w < len4; w++) {
fullID = newPosts[w];
MarkNewIPs.markOld(g.posts[fullID]);
}
}
} }
MarkNewIPs.ipCount = ipCount; return MarkNewIPs.ipCount = ipCount;
return MarkNewIPs.postIDs = postIDs;
}, },
markNew: function(post, ipCount) { markNew: function(post, ipCount) {
var counter, suffix; var counter, suffix;
@ -12040,7 +11979,7 @@
id: 'updater' id: 'updater'
}); });
$.extend(sc, { $.extend(sc, {
innerHTML: "<span id=\"update-status\"></span><span id=\"update-timer\" title=\"Update now\"></span>" innerHTML: "<span id=\"update-status\" class=\"empty\"></span><span id=\"update-timer\" class=\"empty\" title=\"Update now\"></span>"
}); });
$.ready(function() { $.ready(function() {
return Header.addShortcut(sc); return Header.addShortcut(sc);
@ -12057,7 +11996,6 @@
this.checkPostCount = 0; this.checkPostCount = 0;
this.timer = $('#update-timer', sc); this.timer = $('#update-timer', sc);
this.status = $('#update-status', sc); this.status = $('#update-status', sc);
this.isUpdating = Conf['Auto Update'];
$.on(this.timer, 'click', this.update); $.on(this.timer, 'click', this.update);
$.on(this.status, 'click', this.update); $.on(this.status, 'click', this.update);
updateLink = $.el('span', { updateLink = $.el('span', {
@ -12082,7 +12020,7 @@
$.on(input, 'change', this.cb.scrollBG); $.on(input, 'change', this.cb.scrollBG);
this.cb.scrollBG(); this.cb.scrollBG();
} else if (input.name === 'Auto Update') { } else if (input.name === 'Auto Update') {
$.on(input, 'change', this.cb.autoUpdate); $.on(input, 'change', this.setInterval);
} }
subEntries.push({ subEntries.push({
el: el el: el
@ -12112,17 +12050,21 @@
ThreadUpdater.root = this.OP.nodes.root.parentNode; ThreadUpdater.root = this.OP.nodes.root.parentNode;
ThreadUpdater.lastPost = +this.posts.keys[this.posts.keys.length - 1]; ThreadUpdater.lastPost = +this.posts.keys[this.posts.keys.length - 1];
ThreadUpdater.outdateCount = 0; ThreadUpdater.outdateCount = 0;
ThreadUpdater.postIDs = [];
ThreadUpdater.fileIDs = [];
this.posts.forEach(function(post) {
ThreadUpdater.postIDs.push(post.ID);
if (post.file && !post.file.isDead) {
return ThreadUpdater.fileIDs.push(post.ID);
}
});
ThreadUpdater.cb.interval.call($.el('input', { ThreadUpdater.cb.interval.call($.el('input', {
value: Conf['Interval'] value: Conf['Interval']
})); }));
$.on(window, 'online offline', ThreadUpdater.cb.online); $.on(window, 'online offline', ThreadUpdater.cb.online);
$.on(d, 'QRPostSuccessful', ThreadUpdater.cb.checkpost); $.on(d, 'QRPostSuccessful', ThreadUpdater.cb.checkpost);
$.on(d, 'visibilitychange', ThreadUpdater.cb.visibility); $.on(d, 'visibilitychange', ThreadUpdater.cb.visibility);
if (ThreadUpdater.thread.isArchived) { return ThreadUpdater.setInterval();
return ThreadUpdater.set('status', 'Archived', 'warning');
} else {
return ThreadUpdater.cb.online();
}
}, },
/* /*
@ -12135,32 +12077,24 @@
if (ThreadUpdater.thread.isDead) { if (ThreadUpdater.thread.isDead) {
return; return;
} }
if (ThreadUpdater.online = navigator.onLine) { if (navigator.onLine) {
ThreadUpdater.outdateCount = 0; ThreadUpdater.set('status', '');
ThreadUpdater.setInterval();
return ThreadUpdater.set('status', '', '');
} else { } else {
ThreadUpdater.set('timer', '');
ThreadUpdater.set('status', 'Offline', 'warning'); ThreadUpdater.set('status', 'Offline', 'warning');
return clearTimeout(ThreadUpdater.timeoutID); }
if (Conf['Auto Update'] && !Conf['Ignore Offline Status']) {
ThreadUpdater.outdateCount = 0;
return ThreadUpdater.setInterval();
} }
}, },
checkpost: function(e) { checkpost: function(e) {
if (!ThreadUpdater.checkPostCount) { if (e.detail.threadID !== ThreadUpdater.thread.ID) {
if (e && e.detail.threadID !== ThreadUpdater.thread.ID) { return;
return;
}
ThreadUpdater.seconds = 0;
ThreadUpdater.outdateCount = 0;
ThreadUpdater.set('timer', '...');
} }
if (!(ThreadUpdater.thread.isDead || ThreadUpdater.foundPost || ThreadUpdater.checkPostCount >= 5)) { ThreadUpdater.postID = e.detail.postID;
return setTimeout(ThreadUpdater.update, ++ThreadUpdater.checkPostCount * $.SECOND);
}
ThreadUpdater.setInterval();
ThreadUpdater.checkPostCount = 0; ThreadUpdater.checkPostCount = 0;
delete ThreadUpdater.foundPost; ThreadUpdater.outdateCount = 0;
return delete ThreadUpdater.postID; return ThreadUpdater.setInterval();
}, },
visibility: function() { visibility: function() {
if (d.hidden) { if (d.hidden) {
@ -12178,9 +12112,6 @@
return !d.hidden; return !d.hidden;
}; };
}, },
autoUpdate: function() {
return ThreadUpdater.count(ThreadUpdater.isUpdating = this.checked);
},
interval: function(e) { interval: function(e) {
var val; var val;
val = parseInt(this.value, 10); val = parseInt(this.value, 10);
@ -12197,16 +12128,15 @@
req = ThreadUpdater.req; req = ThreadUpdater.req;
switch (req.status) { switch (req.status) {
case 200: case 200:
ThreadUpdater.parse(req.response.posts); ThreadUpdater.parse(req);
if (ThreadUpdater.thread.isArchived) { if (ThreadUpdater.thread.isArchived) {
ThreadUpdater.set('status', 'Archived', 'warning'); return ThreadUpdater.kill();
ThreadUpdater.kill();
} else { } else {
ThreadUpdater.setInterval(); return ThreadUpdater.setInterval();
} }
break; break;
case 404: case 404:
$.ajax("//a.4cdn.org/" + ThreadUpdater.thread.board + "/catalog.json", { return $.ajax("//a.4cdn.org/" + ThreadUpdater.thread.board + "/catalog.json", {
onloadend: function() { onloadend: function() {
var confirmed, k, len1, len2, page, q, ref, ref1, thread; var confirmed, k, len1, len2, page, q, ref, ref1, thread;
if (this.status === 200) { if (this.status === 200) {
@ -12227,51 +12157,70 @@
confirmed = false; confirmed = false;
} }
if (confirmed) { if (confirmed) {
ThreadUpdater.set('status', '404', 'warning');
return ThreadUpdater.kill(); return ThreadUpdater.kill();
} else { } else {
return ThreadUpdater.error(req); return ThreadUpdater.error(req);
} }
} }
}); });
break;
default: default:
ThreadUpdater.error(req); return ThreadUpdater.error(req);
}
if (ThreadUpdater.postID) {
return ThreadUpdater.cb.checkpost();
} }
} }
}, },
kill: function() { kill: function() {
ThreadUpdater.set('timer', '');
clearTimeout(ThreadUpdater.timeoutID);
ThreadUpdater.thread.kill(); ThreadUpdater.thread.kill();
ThreadUpdater.setInterval();
return $.event('ThreadUpdate', { return $.event('ThreadUpdate', {
404: true, 404: true,
threadID: ThreadUpdater.thread.fullID threadID: ThreadUpdater.thread.fullID
}); });
}, },
error: function(req) { error: function(req) {
var klass, ref, text; if (req.status === 304) {
ThreadUpdater.set('status', '');
}
ThreadUpdater.setInterval(); ThreadUpdater.setInterval();
ref = req.status === 304 ? ['', ''] : [req.statusText + " (" + req.status + ")", 'warning'], text = ref[0], klass = ref[1]; if (!req.status) {
return ThreadUpdater.set('status', text, klass); return ThreadUpdater.set('status', 'Connection Failed', 'warning');
} else if (req.status !== 304) {
return ThreadUpdater.set('status', req.statusText + " (" + req.status + ")", 'warning');
}
}, },
setInterval: function() { setInterval: function() {
var cur, i, j, limit; var cur, interval, j, limit;
i = ThreadUpdater.interval + 1; clearTimeout(ThreadUpdater.timeoutID);
if (Conf['Optional Increase']) { if (ThreadUpdater.thread.isDead) {
cur = ThreadUpdater.outdateCount || 1; ThreadUpdater.set('status', (ThreadUpdater.thread.isArchived ? 'Archived' : '404'), 'warning');
limit = d.hidden ? 7 : 10; ThreadUpdater.set('timer', '');
j = cur <= limit ? cur : limit; return;
cur = (Math.floor(i * 0.1) || 1) * j * j;
ThreadUpdater.seconds = cur > i ? cur <= 300 ? cur : 300 : i;
} else {
ThreadUpdater.seconds = i;
} }
ThreadUpdater.set('timer', ThreadUpdater.seconds); if (ThreadUpdater.postID && ThreadUpdater.checkPostCount < 5) {
return ThreadUpdater.count(true); ThreadUpdater.set('timer', '...', 'loading');
ThreadUpdater.timeoutID = setTimeout(ThreadUpdater.update, ++ThreadUpdater.checkPostCount * $.SECOND);
return;
}
if (!Conf['Auto Update']) {
ThreadUpdater.set('timer', 'Update');
return;
}
if (!navigator.onLine) {
ThreadUpdater.set('status', 'Offline', 'warning');
if (!Conf['Ignore Offline Status']) {
ThreadUpdater.set('timer', '');
return;
}
}
interval = ThreadUpdater.interval;
if (Conf['Optional Increase']) {
limit = d.hidden ? 7 : 10;
j = Math.min(ThreadUpdater.outdateCount, limit);
cur = (Math.floor(interval * 0.1) || 1) * j * j;
ThreadUpdater.seconds = $.minmax(cur, interval, 300);
} else {
ThreadUpdater.seconds = interval;
}
return ThreadUpdater.timeout();
}, },
intervalShortcut: function() { intervalShortcut: function() {
var settings; var settings;
@ -12287,40 +12236,22 @@
} else { } else {
el.textContent = text; el.textContent = text;
} }
if (klass !== void 0) { return el.className = klass != null ? klass : (text === '' ? 'empty' : '');
return el.className = klass;
}
},
count: function(start) {
clearTimeout(ThreadUpdater.timeoutID);
if (start && ThreadUpdater.isUpdating && navigator.onLine) {
return ThreadUpdater.timeout();
}
}, },
timeout: function() { timeout: function() {
var n; if (ThreadUpdater.seconds) {
ThreadUpdater.timeoutID = setTimeout(ThreadUpdater.timeout, 1000); ThreadUpdater.set('timer', ThreadUpdater.seconds);
if (!(n = --ThreadUpdater.seconds)) { ThreadUpdater.timeoutID = setTimeout(ThreadUpdater.timeout, 1000);
} else {
ThreadUpdater.outdateCount++; ThreadUpdater.outdateCount++;
return ThreadUpdater.update(); ThreadUpdater.update();
} else if (n <= -60) {
ThreadUpdater.set('status', 'Retrying', '');
return ThreadUpdater.update();
} else if (n > 0) {
return ThreadUpdater.set('timer', n);
} }
return ThreadUpdater.seconds--;
}, },
update: function() { update: function() {
var ref; var ref;
if (!navigator.onLine) { clearTimeout(ThreadUpdater.timeoutID);
return; ThreadUpdater.set('timer', '...', 'loading');
}
ThreadUpdater.count();
if (Conf['Auto Update']) {
ThreadUpdater.set('timer', '...');
} else {
ThreadUpdater.set('timer', 'Update');
}
if ((ref = ThreadUpdater.req) != null) { if ((ref = ThreadUpdater.req) != null) {
ref.abort(); ref.abort();
} }
@ -12343,17 +12274,25 @@
change = type === 'Sticky' ? status ? 'now a sticky' : 'not a sticky anymore' : status ? 'now closed' : 'not closed anymore'; change = type === 'Sticky' ? status ? 'now a sticky' : 'not a sticky anymore' : status ? 'now closed' : 'not closed anymore';
return new Notice('info', "The thread is " + change + ".", 30); return new Notice('info', "The thread is " + change + ".", 30);
}, },
parse: function(postObjects) { parse: function(req) {
var OP, count, files, index, ipCountEl, k, len1, len2, node, num, post, postObject, posts, q, root, scroll; var ID, OP, board, count, deletedFiles, deletedPosts, files, firstPost, index, ipCountEl, k, lastModified, len1, len2, len3, len4, node, num, post, postObject, postObjects, posts, q, ref, ref1, ref2, scroll, thread, u, w;
lastModified = new Date(req.getResponseHeader('Last-Modified'));
if (ThreadUpdater.lastModified && lastModified < ThreadUpdater.lastModified) {
return;
}
ThreadUpdater.lastModified = lastModified;
postObjects = req.response.posts;
OP = postObjects[0]; OP = postObjects[0];
Build.spoilerRange[ThreadUpdater.thread.board] = OP.custom_spoiler; thread = ThreadUpdater.thread;
ThreadUpdater.thread.setStatus('Archived', !!+OP.archived); board = thread.board;
Build.spoilerRange[board] = OP.custom_spoiler;
thread.setStatus('Archived', !!+OP.archived);
ThreadUpdater.updateThreadStatus('Sticky', !!OP.sticky); ThreadUpdater.updateThreadStatus('Sticky', !!OP.sticky);
ThreadUpdater.updateThreadStatus('Closed', !!OP.closed); ThreadUpdater.updateThreadStatus('Closed', !!OP.closed);
ThreadUpdater.thread.postLimit = !!OP.bumplimit; thread.postLimit = !!OP.bumplimit;
ThreadUpdater.thread.fileLimit = !!OP.imagelimit; thread.fileLimit = !!OP.imagelimit;
if (OP.unique_ips != null) { if (OP.unique_ips != null) {
ThreadUpdater.thread.ipCount = OP.unique_ips; thread.ipCount = OP.unique_ips;
} }
posts = []; posts = [];
index = []; index = [];
@ -12370,27 +12309,36 @@
continue; continue;
} }
count++; count++;
node = Build.postFromObject(postObject, ThreadUpdater.thread.board.ID); node = Build.postFromObject(postObject, board.ID);
posts.push(new Post(node, ThreadUpdater.thread, ThreadUpdater.thread.board)); posts.push(new Post(node, thread, board));
if (ThreadUpdater.postID === num) {
delete ThreadUpdater.postID;
}
} }
ThreadUpdater.thread.posts.forEach(function(post) { deletedPosts = [];
var ID; ref = ThreadUpdater.postIDs;
ID = +post.ID; for (q = 0, len2 = ref.length; q < len2; q++) {
if (!(post.info.date > Date.now() - 60 * $.SECOND)) { ID = ref[q];
if (indexOf.call(index, ID) < 0) { if (!(indexOf.call(index, ID) < 0)) {
post.kill(); continue;
} else if (post.isDead) {
post.resurrect();
} else if (post.file && !(post.file.isDead || indexOf.call(files, ID) >= 0)) {
post.kill(true);
}
} }
if (ThreadUpdater.postID && ThreadUpdater.postID === ID) { thread.posts[ID].kill();
return ThreadUpdater.foundPost = true; deletedPosts.push(board + "." + ID);
}
ThreadUpdater.postIDs = index;
deletedFiles = [];
ref1 = ThreadUpdater.fileIDs;
for (u = 0, len3 = ref1.length; u < len3; u++) {
ID = ref1[u];
if (!(!(indexOf.call(files, ID) >= 0 || (ref2 = board + "." + ID, indexOf.call(deletedPosts, ref2) >= 0)))) {
continue;
} }
}); thread.posts[ID].kill(true);
deletedFiles.push(board + "." + ID);
}
ThreadUpdater.fileIDs = files;
if (!count) { if (!count) {
ThreadUpdater.set('status', '', ''); ThreadUpdater.set('status', '');
} else { } else {
ThreadUpdater.set('status', "+" + count, 'new'); ThreadUpdater.set('status', "+" + count, 'new');
ThreadUpdater.outdateCount = 0; ThreadUpdater.outdateCount = 0;
@ -12405,10 +12353,11 @@
ThreadUpdater.lastPost = posts[count - 1].ID; ThreadUpdater.lastPost = posts[count - 1].ID;
Main.callbackNodes(Post, posts); Main.callbackNodes(Post, posts);
scroll = Conf['Auto Scroll'] && ThreadUpdater.scrollBG() && ThreadUpdater.root.getBoundingClientRect().bottom - doc.clientHeight < 25; scroll = Conf['Auto Scroll'] && ThreadUpdater.scrollBG() && ThreadUpdater.root.getBoundingClientRect().bottom - doc.clientHeight < 25;
for (q = 0, len2 = posts.length; q < len2; q++) { firstPost = null;
post = posts[q]; for (w = 0, len4 = posts.length; w < len4; w++) {
root = post.nodes.root; post = posts[w];
if (!QuoteThreading.insert(post)) { if (!QuoteThreading.insert(post)) {
firstPost || (firstPost = post.nodes.root);
$.add(ThreadUpdater.root, post.nodes.root); $.add(ThreadUpdater.root, post.nodes.root);
} }
} }
@ -12417,8 +12366,8 @@
if (Conf['Bottom Scroll']) { if (Conf['Bottom Scroll']) {
window.scrollTo(0, d.body.clientHeight); window.scrollTo(0, d.body.clientHeight);
} else { } else {
if (root) { if (firstPost) {
Header.scrollTo(root); Header.scrollTo(firstPost);
} }
} }
} }
@ -12428,21 +12377,22 @@
ipCountEl.previousSibling.textContent = ipCountEl.previousSibling.textContent.replace(/\b(?:is|are)\b/, OP.unique_ips === 1 ? 'is' : 'are'); ipCountEl.previousSibling.textContent = ipCountEl.previousSibling.textContent.replace(/\b(?:is|are)\b/, OP.unique_ips === 1 ? 'is' : 'are');
ipCountEl.nextSibling.textContent = ipCountEl.nextSibling.textContent.replace(/\bposters?\b/, OP.unique_ips === 1 ? 'poster' : 'posters'); ipCountEl.nextSibling.textContent = ipCountEl.nextSibling.textContent.replace(/\bposters?\b/, OP.unique_ips === 1 ? 'poster' : 'posters');
} }
ThreadUpdater.postIDs = index;
return $.event('ThreadUpdate', { return $.event('ThreadUpdate', {
404: false, 404: false,
threadID: ThreadUpdater.thread.fullID, threadID: thread.fullID,
newPosts: (function() { newPosts: (function() {
var len3, results, u; var len5, results, y;
results = []; results = [];
for (u = 0, len3 = posts.length; u < len3; u++) { for (y = 0, len5 = posts.length; y < len5; y++) {
post = posts[u]; post = posts[y];
results.push(post.fullID); results.push(post.fullID);
} }
return results; return results;
})(), })(),
deletedPosts: deletedPosts,
deletedFiles: deletedFiles,
postCount: OP.replies + 1, postCount: OP.replies + 1,
fileCount: OP.images + (!!ThreadUpdater.thread.OP.file && !ThreadUpdater.thread.OP.file.isDead), fileCount: OP.images + (!!thread.OP.file && !thread.OP.file.isDead),
ipCount: OP.unique_ips ipCount: OP.unique_ips
}); });
} }
@ -17769,8 +17719,8 @@
".new {\n" + ".new {\n" +
" color: limegreen;\n" + " color: limegreen;\n" +
"}\n" + "}\n" +
"#update-status.new {\n" + "#update-status:not(.empty) + #update-timer:not(.empty):not(.loading) {\n" +
" margin-right: 5px;\n" + " margin-left: 5px;\n" +
"}\n" + "}\n" +
"#update-timer {\n" + "#update-timer {\n" +
" cursor: pointer;\n" + " cursor: pointer;\n" +

Binary file not shown.

View File

@ -1,7 +1,7 @@
// Generated by CoffeeScript // Generated by CoffeeScript
// ==UserScript== // ==UserScript==
// @name 4chan X // @name 4chan X
// @version 1.10.3.9 // @version 1.10.4.0
// @minGMVer 1.14 // @minGMVer 1.14
// @minFFVer 26 // @minFFVer 26
// @namespace 4chan-X // @namespace 4chan-X
@ -376,6 +376,7 @@
'Bottom Scroll': [false, 'Always scroll to the bottom, not the first new post. Useful for event threads.'], 'Bottom Scroll': [false, 'Always scroll to the bottom, not the first new post. Useful for event threads.'],
'Scroll BG': [false, 'Auto-scroll background tabs.'], 'Scroll BG': [false, 'Auto-scroll background tabs.'],
'Auto Update': [true, 'Automatically fetch new posts.'], 'Auto Update': [true, 'Automatically fetch new posts.'],
'Ignore Offline Status': [false, 'Update even if your browser reports you are offline.'],
'Optional Increase': [false, 'Increase the intervals between updates on threads without new posts.'] 'Optional Increase': [false, 'Increase the intervals between updates on threads without new posts.']
}, },
'Interval': 30 'Interval': 30
@ -393,7 +394,7 @@
doc = d.documentElement; doc = d.documentElement;
g = { g = {
VERSION: '1.10.3.9', VERSION: '1.10.4.0',
NAMESPACE: '4chan X.', NAMESPACE: '4chan X.',
NAME: '4chan X', NAME: '4chan X',
FAQ: 'https://github.com/ccd0/4chan-x/wiki/Frequently-Asked-Questions', FAQ: 'https://github.com/ccd0/4chan-x/wiki/Frequently-Asked-Questions',
@ -1417,35 +1418,6 @@
} }
}; };
Post.prototype.resurrect = function() {
var clone, k, len1, len2, q, quotelink, ref, ref1, strong;
delete this.isDead;
$.rmClass(this.nodes.root, 'deleted-post');
strong = $('strong.warning', this.nodes.info);
if (this.file && this.file.isDead) {
strong.textContent = '[File deleted]';
} else {
$.rm(strong);
}
if (this.isClone) {
return;
}
ref = this.clones;
for (k = 0, len1 = ref.length; k < len1; k++) {
clone = ref[k];
clone.resurrect();
}
ref1 = Get.allQuotelinksLinkingTo(this);
for (q = 0, len2 = ref1.length; q < len2; q++) {
quotelink = ref1[q];
if (!($.hasClass(quotelink, 'deadlink'))) {
continue;
}
quotelink.textContent = quotelink.textContent.replace('\u00A0(Dead)', '');
$.rmClass(quotelink, 'deadlink');
}
};
Post.prototype.collect = function() { Post.prototype.collect = function() {
this.kill(); this.kill();
g.posts.rm(this.fullID); g.posts.rm(this.fullID);
@ -3564,9 +3536,6 @@
}, },
update: function(state) { update: function(state) {
var now, ref, ref1; var now, ref, ref1;
if (!navigator.onLine) {
return;
}
delete Index.pageNum; delete Index.pageNum;
if ((ref = Index.req) != null) { if ((ref = Index.req) != null) {
ref.abort(); ref.abort();
@ -7590,7 +7559,6 @@
postID: postID, postID: postID,
val: true val: true
}); });
ThreadUpdater.postID = postID;
$.event('QRPostSuccessful', { $.event('QRPostSuccessful', {
boardID: g.BOARD.ID, boardID: g.BOARD.ID,
threadID: threadID, threadID: threadID,
@ -11807,59 +11775,30 @@
}); });
}, },
node: function() { node: function() {
var x;
MarkNewIPs.ipCount = this.ipCount; MarkNewIPs.ipCount = this.ipCount;
MarkNewIPs.postIDs = (function() {
var k, len1, ref, results;
ref = this.posts.keys;
results = [];
for (k = 0, len1 = ref.length; k < len1; k++) {
x = ref[k];
results.push(+x);
}
return results;
}).call(this);
return $.on(d, 'ThreadUpdate', MarkNewIPs.onUpdate); return $.on(d, 'ThreadUpdate', MarkNewIPs.onUpdate);
}, },
onUpdate: function(e) { onUpdate: function(e) {
var added, fullID, i, ipCount, k, len1, len2, len3, len4, newPosts, obj, postIDs, q, ref, ref1, removed, u, w, x; var deletedPosts, fullID, i, ipCount, k, len1, len2, newPosts, q, ref;
ref = e.detail, ipCount = ref.ipCount, newPosts = ref.newPosts; ref = e.detail, ipCount = ref.ipCount, newPosts = ref.newPosts, deletedPosts = ref.deletedPosts;
postIDs = ThreadUpdater.postIDs;
if (ipCount == null) { if (ipCount == null) {
return; return;
} }
if (newPosts.length) { switch (ipCount - MarkNewIPs.ipCount) {
obj = {}; case newPosts.length:
ref1 = MarkNewIPs.postIDs; i = MarkNewIPs.ipCount;
for (k = 0, len1 = ref1.length; k < len1; k++) { for (k = 0, len1 = newPosts.length; k < len1; k++) {
x = ref1[k]; fullID = newPosts[k];
obj[x] = true; MarkNewIPs.markNew(g.posts[fullID], ++i);
} }
added = 0; break;
for (q = 0, len2 = postIDs.length; q < len2; q++) { case -deletedPosts.length:
x = postIDs[q]; for (q = 0, len2 = newPosts.length; q < len2; q++) {
if (!(x in obj)) { fullID = newPosts[q];
added++; MarkNewIPs.markOld(g.posts[fullID]);
} }
}
removed = MarkNewIPs.postIDs.length + added - postIDs.length;
switch (ipCount - MarkNewIPs.ipCount) {
case added:
i = MarkNewIPs.ipCount;
for (u = 0, len3 = newPosts.length; u < len3; u++) {
fullID = newPosts[u];
MarkNewIPs.markNew(g.posts[fullID], ++i);
}
break;
case -removed:
for (w = 0, len4 = newPosts.length; w < len4; w++) {
fullID = newPosts[w];
MarkNewIPs.markOld(g.posts[fullID]);
}
}
} }
MarkNewIPs.ipCount = ipCount; return MarkNewIPs.ipCount = ipCount;
return MarkNewIPs.postIDs = postIDs;
}, },
markNew: function(post, ipCount) { markNew: function(post, ipCount) {
var counter, suffix; var counter, suffix;
@ -12039,7 +11978,7 @@
id: 'updater' id: 'updater'
}); });
$.extend(sc, { $.extend(sc, {
innerHTML: "<span id=\"update-status\"></span><span id=\"update-timer\" title=\"Update now\"></span>" innerHTML: "<span id=\"update-status\" class=\"empty\"></span><span id=\"update-timer\" class=\"empty\" title=\"Update now\"></span>"
}); });
$.ready(function() { $.ready(function() {
return Header.addShortcut(sc); return Header.addShortcut(sc);
@ -12056,7 +11995,6 @@
this.checkPostCount = 0; this.checkPostCount = 0;
this.timer = $('#update-timer', sc); this.timer = $('#update-timer', sc);
this.status = $('#update-status', sc); this.status = $('#update-status', sc);
this.isUpdating = Conf['Auto Update'];
$.on(this.timer, 'click', this.update); $.on(this.timer, 'click', this.update);
$.on(this.status, 'click', this.update); $.on(this.status, 'click', this.update);
updateLink = $.el('span', { updateLink = $.el('span', {
@ -12081,7 +12019,7 @@
$.on(input, 'change', this.cb.scrollBG); $.on(input, 'change', this.cb.scrollBG);
this.cb.scrollBG(); this.cb.scrollBG();
} else if (input.name === 'Auto Update') { } else if (input.name === 'Auto Update') {
$.on(input, 'change', this.cb.autoUpdate); $.on(input, 'change', this.setInterval);
} }
subEntries.push({ subEntries.push({
el: el el: el
@ -12111,17 +12049,21 @@
ThreadUpdater.root = this.OP.nodes.root.parentNode; ThreadUpdater.root = this.OP.nodes.root.parentNode;
ThreadUpdater.lastPost = +this.posts.keys[this.posts.keys.length - 1]; ThreadUpdater.lastPost = +this.posts.keys[this.posts.keys.length - 1];
ThreadUpdater.outdateCount = 0; ThreadUpdater.outdateCount = 0;
ThreadUpdater.postIDs = [];
ThreadUpdater.fileIDs = [];
this.posts.forEach(function(post) {
ThreadUpdater.postIDs.push(post.ID);
if (post.file && !post.file.isDead) {
return ThreadUpdater.fileIDs.push(post.ID);
}
});
ThreadUpdater.cb.interval.call($.el('input', { ThreadUpdater.cb.interval.call($.el('input', {
value: Conf['Interval'] value: Conf['Interval']
})); }));
$.on(window, 'online offline', ThreadUpdater.cb.online); $.on(window, 'online offline', ThreadUpdater.cb.online);
$.on(d, 'QRPostSuccessful', ThreadUpdater.cb.checkpost); $.on(d, 'QRPostSuccessful', ThreadUpdater.cb.checkpost);
$.on(d, 'visibilitychange', ThreadUpdater.cb.visibility); $.on(d, 'visibilitychange', ThreadUpdater.cb.visibility);
if (ThreadUpdater.thread.isArchived) { return ThreadUpdater.setInterval();
return ThreadUpdater.set('status', 'Archived', 'warning');
} else {
return ThreadUpdater.cb.online();
}
}, },
/* /*
@ -12134,32 +12076,24 @@
if (ThreadUpdater.thread.isDead) { if (ThreadUpdater.thread.isDead) {
return; return;
} }
if (ThreadUpdater.online = navigator.onLine) { if (navigator.onLine) {
ThreadUpdater.outdateCount = 0; ThreadUpdater.set('status', '');
ThreadUpdater.setInterval();
return ThreadUpdater.set('status', '', '');
} else { } else {
ThreadUpdater.set('timer', '');
ThreadUpdater.set('status', 'Offline', 'warning'); ThreadUpdater.set('status', 'Offline', 'warning');
return clearTimeout(ThreadUpdater.timeoutID); }
if (Conf['Auto Update'] && !Conf['Ignore Offline Status']) {
ThreadUpdater.outdateCount = 0;
return ThreadUpdater.setInterval();
} }
}, },
checkpost: function(e) { checkpost: function(e) {
if (!ThreadUpdater.checkPostCount) { if (e.detail.threadID !== ThreadUpdater.thread.ID) {
if (e && e.detail.threadID !== ThreadUpdater.thread.ID) { return;
return;
}
ThreadUpdater.seconds = 0;
ThreadUpdater.outdateCount = 0;
ThreadUpdater.set('timer', '...');
} }
if (!(ThreadUpdater.thread.isDead || ThreadUpdater.foundPost || ThreadUpdater.checkPostCount >= 5)) { ThreadUpdater.postID = e.detail.postID;
return setTimeout(ThreadUpdater.update, ++ThreadUpdater.checkPostCount * $.SECOND);
}
ThreadUpdater.setInterval();
ThreadUpdater.checkPostCount = 0; ThreadUpdater.checkPostCount = 0;
delete ThreadUpdater.foundPost; ThreadUpdater.outdateCount = 0;
return delete ThreadUpdater.postID; return ThreadUpdater.setInterval();
}, },
visibility: function() { visibility: function() {
if (d.hidden) { if (d.hidden) {
@ -12177,9 +12111,6 @@
return !d.hidden; return !d.hidden;
}; };
}, },
autoUpdate: function() {
return ThreadUpdater.count(ThreadUpdater.isUpdating = this.checked);
},
interval: function(e) { interval: function(e) {
var val; var val;
val = parseInt(this.value, 10); val = parseInt(this.value, 10);
@ -12196,16 +12127,15 @@
req = ThreadUpdater.req; req = ThreadUpdater.req;
switch (req.status) { switch (req.status) {
case 200: case 200:
ThreadUpdater.parse(req.response.posts); ThreadUpdater.parse(req);
if (ThreadUpdater.thread.isArchived) { if (ThreadUpdater.thread.isArchived) {
ThreadUpdater.set('status', 'Archived', 'warning'); return ThreadUpdater.kill();
ThreadUpdater.kill();
} else { } else {
ThreadUpdater.setInterval(); return ThreadUpdater.setInterval();
} }
break; break;
case 404: case 404:
$.ajax("//a.4cdn.org/" + ThreadUpdater.thread.board + "/catalog.json", { return $.ajax("//a.4cdn.org/" + ThreadUpdater.thread.board + "/catalog.json", {
onloadend: function() { onloadend: function() {
var confirmed, k, len1, len2, page, q, ref, ref1, thread; var confirmed, k, len1, len2, page, q, ref, ref1, thread;
if (this.status === 200) { if (this.status === 200) {
@ -12226,51 +12156,70 @@
confirmed = false; confirmed = false;
} }
if (confirmed) { if (confirmed) {
ThreadUpdater.set('status', '404', 'warning');
return ThreadUpdater.kill(); return ThreadUpdater.kill();
} else { } else {
return ThreadUpdater.error(req); return ThreadUpdater.error(req);
} }
} }
}); });
break;
default: default:
ThreadUpdater.error(req); return ThreadUpdater.error(req);
}
if (ThreadUpdater.postID) {
return ThreadUpdater.cb.checkpost();
} }
} }
}, },
kill: function() { kill: function() {
ThreadUpdater.set('timer', '');
clearTimeout(ThreadUpdater.timeoutID);
ThreadUpdater.thread.kill(); ThreadUpdater.thread.kill();
ThreadUpdater.setInterval();
return $.event('ThreadUpdate', { return $.event('ThreadUpdate', {
404: true, 404: true,
threadID: ThreadUpdater.thread.fullID threadID: ThreadUpdater.thread.fullID
}); });
}, },
error: function(req) { error: function(req) {
var klass, ref, text; if (req.status === 304) {
ThreadUpdater.set('status', '');
}
ThreadUpdater.setInterval(); ThreadUpdater.setInterval();
ref = req.status === 304 ? ['', ''] : [req.statusText + " (" + req.status + ")", 'warning'], text = ref[0], klass = ref[1]; if (!req.status) {
return ThreadUpdater.set('status', text, klass); return ThreadUpdater.set('status', 'Connection Failed', 'warning');
} else if (req.status !== 304) {
return ThreadUpdater.set('status', req.statusText + " (" + req.status + ")", 'warning');
}
}, },
setInterval: function() { setInterval: function() {
var cur, i, j, limit; var cur, interval, j, limit;
i = ThreadUpdater.interval + 1; clearTimeout(ThreadUpdater.timeoutID);
if (Conf['Optional Increase']) { if (ThreadUpdater.thread.isDead) {
cur = ThreadUpdater.outdateCount || 1; ThreadUpdater.set('status', (ThreadUpdater.thread.isArchived ? 'Archived' : '404'), 'warning');
limit = d.hidden ? 7 : 10; ThreadUpdater.set('timer', '');
j = cur <= limit ? cur : limit; return;
cur = (Math.floor(i * 0.1) || 1) * j * j;
ThreadUpdater.seconds = cur > i ? cur <= 300 ? cur : 300 : i;
} else {
ThreadUpdater.seconds = i;
} }
ThreadUpdater.set('timer', ThreadUpdater.seconds); if (ThreadUpdater.postID && ThreadUpdater.checkPostCount < 5) {
return ThreadUpdater.count(true); ThreadUpdater.set('timer', '...', 'loading');
ThreadUpdater.timeoutID = setTimeout(ThreadUpdater.update, ++ThreadUpdater.checkPostCount * $.SECOND);
return;
}
if (!Conf['Auto Update']) {
ThreadUpdater.set('timer', 'Update');
return;
}
if (!navigator.onLine) {
ThreadUpdater.set('status', 'Offline', 'warning');
if (!Conf['Ignore Offline Status']) {
ThreadUpdater.set('timer', '');
return;
}
}
interval = ThreadUpdater.interval;
if (Conf['Optional Increase']) {
limit = d.hidden ? 7 : 10;
j = Math.min(ThreadUpdater.outdateCount, limit);
cur = (Math.floor(interval * 0.1) || 1) * j * j;
ThreadUpdater.seconds = $.minmax(cur, interval, 300);
} else {
ThreadUpdater.seconds = interval;
}
return ThreadUpdater.timeout();
}, },
intervalShortcut: function() { intervalShortcut: function() {
var settings; var settings;
@ -12286,40 +12235,22 @@
} else { } else {
el.textContent = text; el.textContent = text;
} }
if (klass !== void 0) { return el.className = klass != null ? klass : (text === '' ? 'empty' : '');
return el.className = klass;
}
},
count: function(start) {
clearTimeout(ThreadUpdater.timeoutID);
if (start && ThreadUpdater.isUpdating && navigator.onLine) {
return ThreadUpdater.timeout();
}
}, },
timeout: function() { timeout: function() {
var n; if (ThreadUpdater.seconds) {
ThreadUpdater.timeoutID = setTimeout(ThreadUpdater.timeout, 1000); ThreadUpdater.set('timer', ThreadUpdater.seconds);
if (!(n = --ThreadUpdater.seconds)) { ThreadUpdater.timeoutID = setTimeout(ThreadUpdater.timeout, 1000);
} else {
ThreadUpdater.outdateCount++; ThreadUpdater.outdateCount++;
return ThreadUpdater.update(); ThreadUpdater.update();
} else if (n <= -60) {
ThreadUpdater.set('status', 'Retrying', '');
return ThreadUpdater.update();
} else if (n > 0) {
return ThreadUpdater.set('timer', n);
} }
return ThreadUpdater.seconds--;
}, },
update: function() { update: function() {
var ref; var ref;
if (!navigator.onLine) { clearTimeout(ThreadUpdater.timeoutID);
return; ThreadUpdater.set('timer', '...', 'loading');
}
ThreadUpdater.count();
if (Conf['Auto Update']) {
ThreadUpdater.set('timer', '...');
} else {
ThreadUpdater.set('timer', 'Update');
}
if ((ref = ThreadUpdater.req) != null) { if ((ref = ThreadUpdater.req) != null) {
ref.abort(); ref.abort();
} }
@ -12342,17 +12273,25 @@
change = type === 'Sticky' ? status ? 'now a sticky' : 'not a sticky anymore' : status ? 'now closed' : 'not closed anymore'; change = type === 'Sticky' ? status ? 'now a sticky' : 'not a sticky anymore' : status ? 'now closed' : 'not closed anymore';
return new Notice('info', "The thread is " + change + ".", 30); return new Notice('info', "The thread is " + change + ".", 30);
}, },
parse: function(postObjects) { parse: function(req) {
var OP, count, files, index, ipCountEl, k, len1, len2, node, num, post, postObject, posts, q, root, scroll; var ID, OP, board, count, deletedFiles, deletedPosts, files, firstPost, index, ipCountEl, k, lastModified, len1, len2, len3, len4, node, num, post, postObject, postObjects, posts, q, ref, ref1, ref2, scroll, thread, u, w;
lastModified = new Date(req.getResponseHeader('Last-Modified'));
if (ThreadUpdater.lastModified && lastModified < ThreadUpdater.lastModified) {
return;
}
ThreadUpdater.lastModified = lastModified;
postObjects = req.response.posts;
OP = postObjects[0]; OP = postObjects[0];
Build.spoilerRange[ThreadUpdater.thread.board] = OP.custom_spoiler; thread = ThreadUpdater.thread;
ThreadUpdater.thread.setStatus('Archived', !!+OP.archived); board = thread.board;
Build.spoilerRange[board] = OP.custom_spoiler;
thread.setStatus('Archived', !!+OP.archived);
ThreadUpdater.updateThreadStatus('Sticky', !!OP.sticky); ThreadUpdater.updateThreadStatus('Sticky', !!OP.sticky);
ThreadUpdater.updateThreadStatus('Closed', !!OP.closed); ThreadUpdater.updateThreadStatus('Closed', !!OP.closed);
ThreadUpdater.thread.postLimit = !!OP.bumplimit; thread.postLimit = !!OP.bumplimit;
ThreadUpdater.thread.fileLimit = !!OP.imagelimit; thread.fileLimit = !!OP.imagelimit;
if (OP.unique_ips != null) { if (OP.unique_ips != null) {
ThreadUpdater.thread.ipCount = OP.unique_ips; thread.ipCount = OP.unique_ips;
} }
posts = []; posts = [];
index = []; index = [];
@ -12369,27 +12308,36 @@
continue; continue;
} }
count++; count++;
node = Build.postFromObject(postObject, ThreadUpdater.thread.board.ID); node = Build.postFromObject(postObject, board.ID);
posts.push(new Post(node, ThreadUpdater.thread, ThreadUpdater.thread.board)); posts.push(new Post(node, thread, board));
if (ThreadUpdater.postID === num) {
delete ThreadUpdater.postID;
}
} }
ThreadUpdater.thread.posts.forEach(function(post) { deletedPosts = [];
var ID; ref = ThreadUpdater.postIDs;
ID = +post.ID; for (q = 0, len2 = ref.length; q < len2; q++) {
if (!(post.info.date > Date.now() - 60 * $.SECOND)) { ID = ref[q];
if (indexOf.call(index, ID) < 0) { if (!(indexOf.call(index, ID) < 0)) {
post.kill(); continue;
} else if (post.isDead) {
post.resurrect();
} else if (post.file && !(post.file.isDead || indexOf.call(files, ID) >= 0)) {
post.kill(true);
}
} }
if (ThreadUpdater.postID && ThreadUpdater.postID === ID) { thread.posts[ID].kill();
return ThreadUpdater.foundPost = true; deletedPosts.push(board + "." + ID);
}
ThreadUpdater.postIDs = index;
deletedFiles = [];
ref1 = ThreadUpdater.fileIDs;
for (u = 0, len3 = ref1.length; u < len3; u++) {
ID = ref1[u];
if (!(!(indexOf.call(files, ID) >= 0 || (ref2 = board + "." + ID, indexOf.call(deletedPosts, ref2) >= 0)))) {
continue;
} }
}); thread.posts[ID].kill(true);
deletedFiles.push(board + "." + ID);
}
ThreadUpdater.fileIDs = files;
if (!count) { if (!count) {
ThreadUpdater.set('status', '', ''); ThreadUpdater.set('status', '');
} else { } else {
ThreadUpdater.set('status', "+" + count, 'new'); ThreadUpdater.set('status', "+" + count, 'new');
ThreadUpdater.outdateCount = 0; ThreadUpdater.outdateCount = 0;
@ -12404,10 +12352,11 @@
ThreadUpdater.lastPost = posts[count - 1].ID; ThreadUpdater.lastPost = posts[count - 1].ID;
Main.callbackNodes(Post, posts); Main.callbackNodes(Post, posts);
scroll = Conf['Auto Scroll'] && ThreadUpdater.scrollBG() && ThreadUpdater.root.getBoundingClientRect().bottom - doc.clientHeight < 25; scroll = Conf['Auto Scroll'] && ThreadUpdater.scrollBG() && ThreadUpdater.root.getBoundingClientRect().bottom - doc.clientHeight < 25;
for (q = 0, len2 = posts.length; q < len2; q++) { firstPost = null;
post = posts[q]; for (w = 0, len4 = posts.length; w < len4; w++) {
root = post.nodes.root; post = posts[w];
if (!QuoteThreading.insert(post)) { if (!QuoteThreading.insert(post)) {
firstPost || (firstPost = post.nodes.root);
$.add(ThreadUpdater.root, post.nodes.root); $.add(ThreadUpdater.root, post.nodes.root);
} }
} }
@ -12416,8 +12365,8 @@
if (Conf['Bottom Scroll']) { if (Conf['Bottom Scroll']) {
window.scrollTo(0, d.body.clientHeight); window.scrollTo(0, d.body.clientHeight);
} else { } else {
if (root) { if (firstPost) {
Header.scrollTo(root); Header.scrollTo(firstPost);
} }
} }
} }
@ -12427,21 +12376,22 @@
ipCountEl.previousSibling.textContent = ipCountEl.previousSibling.textContent.replace(/\b(?:is|are)\b/, OP.unique_ips === 1 ? 'is' : 'are'); ipCountEl.previousSibling.textContent = ipCountEl.previousSibling.textContent.replace(/\b(?:is|are)\b/, OP.unique_ips === 1 ? 'is' : 'are');
ipCountEl.nextSibling.textContent = ipCountEl.nextSibling.textContent.replace(/\bposters?\b/, OP.unique_ips === 1 ? 'poster' : 'posters'); ipCountEl.nextSibling.textContent = ipCountEl.nextSibling.textContent.replace(/\bposters?\b/, OP.unique_ips === 1 ? 'poster' : 'posters');
} }
ThreadUpdater.postIDs = index;
return $.event('ThreadUpdate', { return $.event('ThreadUpdate', {
404: false, 404: false,
threadID: ThreadUpdater.thread.fullID, threadID: thread.fullID,
newPosts: (function() { newPosts: (function() {
var len3, results, u; var len5, results, y;
results = []; results = [];
for (u = 0, len3 = posts.length; u < len3; u++) { for (y = 0, len5 = posts.length; y < len5; y++) {
post = posts[u]; post = posts[y];
results.push(post.fullID); results.push(post.fullID);
} }
return results; return results;
})(), })(),
deletedPosts: deletedPosts,
deletedFiles: deletedFiles,
postCount: OP.replies + 1, postCount: OP.replies + 1,
fileCount: OP.images + (!!ThreadUpdater.thread.OP.file && !ThreadUpdater.thread.OP.file.isDead), fileCount: OP.images + (!!thread.OP.file && !thread.OP.file.isDead),
ipCount: OP.unique_ips ipCount: OP.unique_ips
}); });
} }
@ -17768,8 +17718,8 @@
".new {\n" + ".new {\n" +
" color: limegreen;\n" + " color: limegreen;\n" +
"}\n" + "}\n" +
"#update-status.new {\n" + "#update-status:not(.empty) + #update-timer:not(.empty):not(.loading) {\n" +
" margin-right: 5px;\n" + " margin-left: 5px;\n" +
"}\n" + "}\n" +
"#update-timer {\n" + "#update-timer {\n" +
" cursor: pointer;\n" + " cursor: pointer;\n" +

Binary file not shown.

View File

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

View File

@ -1,7 +1,7 @@
// Generated by CoffeeScript // Generated by CoffeeScript
// ==UserScript== // ==UserScript==
// @name 4chan X // @name 4chan X
// @version 1.10.3.9 // @version 1.10.4.0
// @minGMVer 1.14 // @minGMVer 1.14
// @minFFVer 26 // @minFFVer 26
// @namespace 4chan-X // @namespace 4chan-X
@ -377,6 +377,7 @@
'Bottom Scroll': [false, 'Always scroll to the bottom, not the first new post. Useful for event threads.'], 'Bottom Scroll': [false, 'Always scroll to the bottom, not the first new post. Useful for event threads.'],
'Scroll BG': [false, 'Auto-scroll background tabs.'], 'Scroll BG': [false, 'Auto-scroll background tabs.'],
'Auto Update': [true, 'Automatically fetch new posts.'], 'Auto Update': [true, 'Automatically fetch new posts.'],
'Ignore Offline Status': [false, 'Update even if your browser reports you are offline.'],
'Optional Increase': [false, 'Increase the intervals between updates on threads without new posts.'] 'Optional Increase': [false, 'Increase the intervals between updates on threads without new posts.']
}, },
'Interval': 30 'Interval': 30
@ -394,7 +395,7 @@
doc = d.documentElement; doc = d.documentElement;
g = { g = {
VERSION: '1.10.3.9', VERSION: '1.10.4.0',
NAMESPACE: '4chan X.', NAMESPACE: '4chan X.',
NAME: '4chan X', NAME: '4chan X',
FAQ: 'https://github.com/ccd0/4chan-x/wiki/Frequently-Asked-Questions', FAQ: 'https://github.com/ccd0/4chan-x/wiki/Frequently-Asked-Questions',
@ -1418,35 +1419,6 @@
} }
}; };
Post.prototype.resurrect = function() {
var clone, k, len1, len2, q, quotelink, ref, ref1, strong;
delete this.isDead;
$.rmClass(this.nodes.root, 'deleted-post');
strong = $('strong.warning', this.nodes.info);
if (this.file && this.file.isDead) {
strong.textContent = '[File deleted]';
} else {
$.rm(strong);
}
if (this.isClone) {
return;
}
ref = this.clones;
for (k = 0, len1 = ref.length; k < len1; k++) {
clone = ref[k];
clone.resurrect();
}
ref1 = Get.allQuotelinksLinkingTo(this);
for (q = 0, len2 = ref1.length; q < len2; q++) {
quotelink = ref1[q];
if (!($.hasClass(quotelink, 'deadlink'))) {
continue;
}
quotelink.textContent = quotelink.textContent.replace('\u00A0(Dead)', '');
$.rmClass(quotelink, 'deadlink');
}
};
Post.prototype.collect = function() { Post.prototype.collect = function() {
this.kill(); this.kill();
g.posts.rm(this.fullID); g.posts.rm(this.fullID);
@ -3565,9 +3537,6 @@
}, },
update: function(state) { update: function(state) {
var now, ref, ref1; var now, ref, ref1;
if (!navigator.onLine) {
return;
}
delete Index.pageNum; delete Index.pageNum;
if ((ref = Index.req) != null) { if ((ref = Index.req) != null) {
ref.abort(); ref.abort();
@ -7591,7 +7560,6 @@
postID: postID, postID: postID,
val: true val: true
}); });
ThreadUpdater.postID = postID;
$.event('QRPostSuccessful', { $.event('QRPostSuccessful', {
boardID: g.BOARD.ID, boardID: g.BOARD.ID,
threadID: threadID, threadID: threadID,
@ -11808,59 +11776,30 @@
}); });
}, },
node: function() { node: function() {
var x;
MarkNewIPs.ipCount = this.ipCount; MarkNewIPs.ipCount = this.ipCount;
MarkNewIPs.postIDs = (function() {
var k, len1, ref, results;
ref = this.posts.keys;
results = [];
for (k = 0, len1 = ref.length; k < len1; k++) {
x = ref[k];
results.push(+x);
}
return results;
}).call(this);
return $.on(d, 'ThreadUpdate', MarkNewIPs.onUpdate); return $.on(d, 'ThreadUpdate', MarkNewIPs.onUpdate);
}, },
onUpdate: function(e) { onUpdate: function(e) {
var added, fullID, i, ipCount, k, len1, len2, len3, len4, newPosts, obj, postIDs, q, ref, ref1, removed, u, w, x; var deletedPosts, fullID, i, ipCount, k, len1, len2, newPosts, q, ref;
ref = e.detail, ipCount = ref.ipCount, newPosts = ref.newPosts; ref = e.detail, ipCount = ref.ipCount, newPosts = ref.newPosts, deletedPosts = ref.deletedPosts;
postIDs = ThreadUpdater.postIDs;
if (ipCount == null) { if (ipCount == null) {
return; return;
} }
if (newPosts.length) { switch (ipCount - MarkNewIPs.ipCount) {
obj = {}; case newPosts.length:
ref1 = MarkNewIPs.postIDs; i = MarkNewIPs.ipCount;
for (k = 0, len1 = ref1.length; k < len1; k++) { for (k = 0, len1 = newPosts.length; k < len1; k++) {
x = ref1[k]; fullID = newPosts[k];
obj[x] = true; MarkNewIPs.markNew(g.posts[fullID], ++i);
} }
added = 0; break;
for (q = 0, len2 = postIDs.length; q < len2; q++) { case -deletedPosts.length:
x = postIDs[q]; for (q = 0, len2 = newPosts.length; q < len2; q++) {
if (!(x in obj)) { fullID = newPosts[q];
added++; MarkNewIPs.markOld(g.posts[fullID]);
} }
}
removed = MarkNewIPs.postIDs.length + added - postIDs.length;
switch (ipCount - MarkNewIPs.ipCount) {
case added:
i = MarkNewIPs.ipCount;
for (u = 0, len3 = newPosts.length; u < len3; u++) {
fullID = newPosts[u];
MarkNewIPs.markNew(g.posts[fullID], ++i);
}
break;
case -removed:
for (w = 0, len4 = newPosts.length; w < len4; w++) {
fullID = newPosts[w];
MarkNewIPs.markOld(g.posts[fullID]);
}
}
} }
MarkNewIPs.ipCount = ipCount; return MarkNewIPs.ipCount = ipCount;
return MarkNewIPs.postIDs = postIDs;
}, },
markNew: function(post, ipCount) { markNew: function(post, ipCount) {
var counter, suffix; var counter, suffix;
@ -12040,7 +11979,7 @@
id: 'updater' id: 'updater'
}); });
$.extend(sc, { $.extend(sc, {
innerHTML: "<span id=\"update-status\"></span><span id=\"update-timer\" title=\"Update now\"></span>" innerHTML: "<span id=\"update-status\" class=\"empty\"></span><span id=\"update-timer\" class=\"empty\" title=\"Update now\"></span>"
}); });
$.ready(function() { $.ready(function() {
return Header.addShortcut(sc); return Header.addShortcut(sc);
@ -12057,7 +11996,6 @@
this.checkPostCount = 0; this.checkPostCount = 0;
this.timer = $('#update-timer', sc); this.timer = $('#update-timer', sc);
this.status = $('#update-status', sc); this.status = $('#update-status', sc);
this.isUpdating = Conf['Auto Update'];
$.on(this.timer, 'click', this.update); $.on(this.timer, 'click', this.update);
$.on(this.status, 'click', this.update); $.on(this.status, 'click', this.update);
updateLink = $.el('span', { updateLink = $.el('span', {
@ -12082,7 +12020,7 @@
$.on(input, 'change', this.cb.scrollBG); $.on(input, 'change', this.cb.scrollBG);
this.cb.scrollBG(); this.cb.scrollBG();
} else if (input.name === 'Auto Update') { } else if (input.name === 'Auto Update') {
$.on(input, 'change', this.cb.autoUpdate); $.on(input, 'change', this.setInterval);
} }
subEntries.push({ subEntries.push({
el: el el: el
@ -12112,17 +12050,21 @@
ThreadUpdater.root = this.OP.nodes.root.parentNode; ThreadUpdater.root = this.OP.nodes.root.parentNode;
ThreadUpdater.lastPost = +this.posts.keys[this.posts.keys.length - 1]; ThreadUpdater.lastPost = +this.posts.keys[this.posts.keys.length - 1];
ThreadUpdater.outdateCount = 0; ThreadUpdater.outdateCount = 0;
ThreadUpdater.postIDs = [];
ThreadUpdater.fileIDs = [];
this.posts.forEach(function(post) {
ThreadUpdater.postIDs.push(post.ID);
if (post.file && !post.file.isDead) {
return ThreadUpdater.fileIDs.push(post.ID);
}
});
ThreadUpdater.cb.interval.call($.el('input', { ThreadUpdater.cb.interval.call($.el('input', {
value: Conf['Interval'] value: Conf['Interval']
})); }));
$.on(window, 'online offline', ThreadUpdater.cb.online); $.on(window, 'online offline', ThreadUpdater.cb.online);
$.on(d, 'QRPostSuccessful', ThreadUpdater.cb.checkpost); $.on(d, 'QRPostSuccessful', ThreadUpdater.cb.checkpost);
$.on(d, 'visibilitychange', ThreadUpdater.cb.visibility); $.on(d, 'visibilitychange', ThreadUpdater.cb.visibility);
if (ThreadUpdater.thread.isArchived) { return ThreadUpdater.setInterval();
return ThreadUpdater.set('status', 'Archived', 'warning');
} else {
return ThreadUpdater.cb.online();
}
}, },
/* /*
@ -12135,32 +12077,24 @@
if (ThreadUpdater.thread.isDead) { if (ThreadUpdater.thread.isDead) {
return; return;
} }
if (ThreadUpdater.online = navigator.onLine) { if (navigator.onLine) {
ThreadUpdater.outdateCount = 0; ThreadUpdater.set('status', '');
ThreadUpdater.setInterval();
return ThreadUpdater.set('status', '', '');
} else { } else {
ThreadUpdater.set('timer', '');
ThreadUpdater.set('status', 'Offline', 'warning'); ThreadUpdater.set('status', 'Offline', 'warning');
return clearTimeout(ThreadUpdater.timeoutID); }
if (Conf['Auto Update'] && !Conf['Ignore Offline Status']) {
ThreadUpdater.outdateCount = 0;
return ThreadUpdater.setInterval();
} }
}, },
checkpost: function(e) { checkpost: function(e) {
if (!ThreadUpdater.checkPostCount) { if (e.detail.threadID !== ThreadUpdater.thread.ID) {
if (e && e.detail.threadID !== ThreadUpdater.thread.ID) { return;
return;
}
ThreadUpdater.seconds = 0;
ThreadUpdater.outdateCount = 0;
ThreadUpdater.set('timer', '...');
} }
if (!(ThreadUpdater.thread.isDead || ThreadUpdater.foundPost || ThreadUpdater.checkPostCount >= 5)) { ThreadUpdater.postID = e.detail.postID;
return setTimeout(ThreadUpdater.update, ++ThreadUpdater.checkPostCount * $.SECOND);
}
ThreadUpdater.setInterval();
ThreadUpdater.checkPostCount = 0; ThreadUpdater.checkPostCount = 0;
delete ThreadUpdater.foundPost; ThreadUpdater.outdateCount = 0;
return delete ThreadUpdater.postID; return ThreadUpdater.setInterval();
}, },
visibility: function() { visibility: function() {
if (d.hidden) { if (d.hidden) {
@ -12178,9 +12112,6 @@
return !d.hidden; return !d.hidden;
}; };
}, },
autoUpdate: function() {
return ThreadUpdater.count(ThreadUpdater.isUpdating = this.checked);
},
interval: function(e) { interval: function(e) {
var val; var val;
val = parseInt(this.value, 10); val = parseInt(this.value, 10);
@ -12197,16 +12128,15 @@
req = ThreadUpdater.req; req = ThreadUpdater.req;
switch (req.status) { switch (req.status) {
case 200: case 200:
ThreadUpdater.parse(req.response.posts); ThreadUpdater.parse(req);
if (ThreadUpdater.thread.isArchived) { if (ThreadUpdater.thread.isArchived) {
ThreadUpdater.set('status', 'Archived', 'warning'); return ThreadUpdater.kill();
ThreadUpdater.kill();
} else { } else {
ThreadUpdater.setInterval(); return ThreadUpdater.setInterval();
} }
break; break;
case 404: case 404:
$.ajax("//a.4cdn.org/" + ThreadUpdater.thread.board + "/catalog.json", { return $.ajax("//a.4cdn.org/" + ThreadUpdater.thread.board + "/catalog.json", {
onloadend: function() { onloadend: function() {
var confirmed, k, len1, len2, page, q, ref, ref1, thread; var confirmed, k, len1, len2, page, q, ref, ref1, thread;
if (this.status === 200) { if (this.status === 200) {
@ -12227,51 +12157,70 @@
confirmed = false; confirmed = false;
} }
if (confirmed) { if (confirmed) {
ThreadUpdater.set('status', '404', 'warning');
return ThreadUpdater.kill(); return ThreadUpdater.kill();
} else { } else {
return ThreadUpdater.error(req); return ThreadUpdater.error(req);
} }
} }
}); });
break;
default: default:
ThreadUpdater.error(req); return ThreadUpdater.error(req);
}
if (ThreadUpdater.postID) {
return ThreadUpdater.cb.checkpost();
} }
} }
}, },
kill: function() { kill: function() {
ThreadUpdater.set('timer', '');
clearTimeout(ThreadUpdater.timeoutID);
ThreadUpdater.thread.kill(); ThreadUpdater.thread.kill();
ThreadUpdater.setInterval();
return $.event('ThreadUpdate', { return $.event('ThreadUpdate', {
404: true, 404: true,
threadID: ThreadUpdater.thread.fullID threadID: ThreadUpdater.thread.fullID
}); });
}, },
error: function(req) { error: function(req) {
var klass, ref, text; if (req.status === 304) {
ThreadUpdater.set('status', '');
}
ThreadUpdater.setInterval(); ThreadUpdater.setInterval();
ref = req.status === 304 ? ['', ''] : [req.statusText + " (" + req.status + ")", 'warning'], text = ref[0], klass = ref[1]; if (!req.status) {
return ThreadUpdater.set('status', text, klass); return ThreadUpdater.set('status', 'Connection Failed', 'warning');
} else if (req.status !== 304) {
return ThreadUpdater.set('status', req.statusText + " (" + req.status + ")", 'warning');
}
}, },
setInterval: function() { setInterval: function() {
var cur, i, j, limit; var cur, interval, j, limit;
i = ThreadUpdater.interval + 1; clearTimeout(ThreadUpdater.timeoutID);
if (Conf['Optional Increase']) { if (ThreadUpdater.thread.isDead) {
cur = ThreadUpdater.outdateCount || 1; ThreadUpdater.set('status', (ThreadUpdater.thread.isArchived ? 'Archived' : '404'), 'warning');
limit = d.hidden ? 7 : 10; ThreadUpdater.set('timer', '');
j = cur <= limit ? cur : limit; return;
cur = (Math.floor(i * 0.1) || 1) * j * j;
ThreadUpdater.seconds = cur > i ? cur <= 300 ? cur : 300 : i;
} else {
ThreadUpdater.seconds = i;
} }
ThreadUpdater.set('timer', ThreadUpdater.seconds); if (ThreadUpdater.postID && ThreadUpdater.checkPostCount < 5) {
return ThreadUpdater.count(true); ThreadUpdater.set('timer', '...', 'loading');
ThreadUpdater.timeoutID = setTimeout(ThreadUpdater.update, ++ThreadUpdater.checkPostCount * $.SECOND);
return;
}
if (!Conf['Auto Update']) {
ThreadUpdater.set('timer', 'Update');
return;
}
if (!navigator.onLine) {
ThreadUpdater.set('status', 'Offline', 'warning');
if (!Conf['Ignore Offline Status']) {
ThreadUpdater.set('timer', '');
return;
}
}
interval = ThreadUpdater.interval;
if (Conf['Optional Increase']) {
limit = d.hidden ? 7 : 10;
j = Math.min(ThreadUpdater.outdateCount, limit);
cur = (Math.floor(interval * 0.1) || 1) * j * j;
ThreadUpdater.seconds = $.minmax(cur, interval, 300);
} else {
ThreadUpdater.seconds = interval;
}
return ThreadUpdater.timeout();
}, },
intervalShortcut: function() { intervalShortcut: function() {
var settings; var settings;
@ -12287,40 +12236,22 @@
} else { } else {
el.textContent = text; el.textContent = text;
} }
if (klass !== void 0) { return el.className = klass != null ? klass : (text === '' ? 'empty' : '');
return el.className = klass;
}
},
count: function(start) {
clearTimeout(ThreadUpdater.timeoutID);
if (start && ThreadUpdater.isUpdating && navigator.onLine) {
return ThreadUpdater.timeout();
}
}, },
timeout: function() { timeout: function() {
var n; if (ThreadUpdater.seconds) {
ThreadUpdater.timeoutID = setTimeout(ThreadUpdater.timeout, 1000); ThreadUpdater.set('timer', ThreadUpdater.seconds);
if (!(n = --ThreadUpdater.seconds)) { ThreadUpdater.timeoutID = setTimeout(ThreadUpdater.timeout, 1000);
} else {
ThreadUpdater.outdateCount++; ThreadUpdater.outdateCount++;
return ThreadUpdater.update(); ThreadUpdater.update();
} else if (n <= -60) {
ThreadUpdater.set('status', 'Retrying', '');
return ThreadUpdater.update();
} else if (n > 0) {
return ThreadUpdater.set('timer', n);
} }
return ThreadUpdater.seconds--;
}, },
update: function() { update: function() {
var ref; var ref;
if (!navigator.onLine) { clearTimeout(ThreadUpdater.timeoutID);
return; ThreadUpdater.set('timer', '...', 'loading');
}
ThreadUpdater.count();
if (Conf['Auto Update']) {
ThreadUpdater.set('timer', '...');
} else {
ThreadUpdater.set('timer', 'Update');
}
if ((ref = ThreadUpdater.req) != null) { if ((ref = ThreadUpdater.req) != null) {
ref.abort(); ref.abort();
} }
@ -12343,17 +12274,25 @@
change = type === 'Sticky' ? status ? 'now a sticky' : 'not a sticky anymore' : status ? 'now closed' : 'not closed anymore'; change = type === 'Sticky' ? status ? 'now a sticky' : 'not a sticky anymore' : status ? 'now closed' : 'not closed anymore';
return new Notice('info', "The thread is " + change + ".", 30); return new Notice('info', "The thread is " + change + ".", 30);
}, },
parse: function(postObjects) { parse: function(req) {
var OP, count, files, index, ipCountEl, k, len1, len2, node, num, post, postObject, posts, q, root, scroll; var ID, OP, board, count, deletedFiles, deletedPosts, files, firstPost, index, ipCountEl, k, lastModified, len1, len2, len3, len4, node, num, post, postObject, postObjects, posts, q, ref, ref1, ref2, scroll, thread, u, w;
lastModified = new Date(req.getResponseHeader('Last-Modified'));
if (ThreadUpdater.lastModified && lastModified < ThreadUpdater.lastModified) {
return;
}
ThreadUpdater.lastModified = lastModified;
postObjects = req.response.posts;
OP = postObjects[0]; OP = postObjects[0];
Build.spoilerRange[ThreadUpdater.thread.board] = OP.custom_spoiler; thread = ThreadUpdater.thread;
ThreadUpdater.thread.setStatus('Archived', !!+OP.archived); board = thread.board;
Build.spoilerRange[board] = OP.custom_spoiler;
thread.setStatus('Archived', !!+OP.archived);
ThreadUpdater.updateThreadStatus('Sticky', !!OP.sticky); ThreadUpdater.updateThreadStatus('Sticky', !!OP.sticky);
ThreadUpdater.updateThreadStatus('Closed', !!OP.closed); ThreadUpdater.updateThreadStatus('Closed', !!OP.closed);
ThreadUpdater.thread.postLimit = !!OP.bumplimit; thread.postLimit = !!OP.bumplimit;
ThreadUpdater.thread.fileLimit = !!OP.imagelimit; thread.fileLimit = !!OP.imagelimit;
if (OP.unique_ips != null) { if (OP.unique_ips != null) {
ThreadUpdater.thread.ipCount = OP.unique_ips; thread.ipCount = OP.unique_ips;
} }
posts = []; posts = [];
index = []; index = [];
@ -12370,27 +12309,36 @@
continue; continue;
} }
count++; count++;
node = Build.postFromObject(postObject, ThreadUpdater.thread.board.ID); node = Build.postFromObject(postObject, board.ID);
posts.push(new Post(node, ThreadUpdater.thread, ThreadUpdater.thread.board)); posts.push(new Post(node, thread, board));
if (ThreadUpdater.postID === num) {
delete ThreadUpdater.postID;
}
} }
ThreadUpdater.thread.posts.forEach(function(post) { deletedPosts = [];
var ID; ref = ThreadUpdater.postIDs;
ID = +post.ID; for (q = 0, len2 = ref.length; q < len2; q++) {
if (!(post.info.date > Date.now() - 60 * $.SECOND)) { ID = ref[q];
if (indexOf.call(index, ID) < 0) { if (!(indexOf.call(index, ID) < 0)) {
post.kill(); continue;
} else if (post.isDead) {
post.resurrect();
} else if (post.file && !(post.file.isDead || indexOf.call(files, ID) >= 0)) {
post.kill(true);
}
} }
if (ThreadUpdater.postID && ThreadUpdater.postID === ID) { thread.posts[ID].kill();
return ThreadUpdater.foundPost = true; deletedPosts.push(board + "." + ID);
}
ThreadUpdater.postIDs = index;
deletedFiles = [];
ref1 = ThreadUpdater.fileIDs;
for (u = 0, len3 = ref1.length; u < len3; u++) {
ID = ref1[u];
if (!(!(indexOf.call(files, ID) >= 0 || (ref2 = board + "." + ID, indexOf.call(deletedPosts, ref2) >= 0)))) {
continue;
} }
}); thread.posts[ID].kill(true);
deletedFiles.push(board + "." + ID);
}
ThreadUpdater.fileIDs = files;
if (!count) { if (!count) {
ThreadUpdater.set('status', '', ''); ThreadUpdater.set('status', '');
} else { } else {
ThreadUpdater.set('status', "+" + count, 'new'); ThreadUpdater.set('status', "+" + count, 'new');
ThreadUpdater.outdateCount = 0; ThreadUpdater.outdateCount = 0;
@ -12405,10 +12353,11 @@
ThreadUpdater.lastPost = posts[count - 1].ID; ThreadUpdater.lastPost = posts[count - 1].ID;
Main.callbackNodes(Post, posts); Main.callbackNodes(Post, posts);
scroll = Conf['Auto Scroll'] && ThreadUpdater.scrollBG() && ThreadUpdater.root.getBoundingClientRect().bottom - doc.clientHeight < 25; scroll = Conf['Auto Scroll'] && ThreadUpdater.scrollBG() && ThreadUpdater.root.getBoundingClientRect().bottom - doc.clientHeight < 25;
for (q = 0, len2 = posts.length; q < len2; q++) { firstPost = null;
post = posts[q]; for (w = 0, len4 = posts.length; w < len4; w++) {
root = post.nodes.root; post = posts[w];
if (!QuoteThreading.insert(post)) { if (!QuoteThreading.insert(post)) {
firstPost || (firstPost = post.nodes.root);
$.add(ThreadUpdater.root, post.nodes.root); $.add(ThreadUpdater.root, post.nodes.root);
} }
} }
@ -12417,8 +12366,8 @@
if (Conf['Bottom Scroll']) { if (Conf['Bottom Scroll']) {
window.scrollTo(0, d.body.clientHeight); window.scrollTo(0, d.body.clientHeight);
} else { } else {
if (root) { if (firstPost) {
Header.scrollTo(root); Header.scrollTo(firstPost);
} }
} }
} }
@ -12428,21 +12377,22 @@
ipCountEl.previousSibling.textContent = ipCountEl.previousSibling.textContent.replace(/\b(?:is|are)\b/, OP.unique_ips === 1 ? 'is' : 'are'); ipCountEl.previousSibling.textContent = ipCountEl.previousSibling.textContent.replace(/\b(?:is|are)\b/, OP.unique_ips === 1 ? 'is' : 'are');
ipCountEl.nextSibling.textContent = ipCountEl.nextSibling.textContent.replace(/\bposters?\b/, OP.unique_ips === 1 ? 'poster' : 'posters'); ipCountEl.nextSibling.textContent = ipCountEl.nextSibling.textContent.replace(/\bposters?\b/, OP.unique_ips === 1 ? 'poster' : 'posters');
} }
ThreadUpdater.postIDs = index;
return $.event('ThreadUpdate', { return $.event('ThreadUpdate', {
404: false, 404: false,
threadID: ThreadUpdater.thread.fullID, threadID: thread.fullID,
newPosts: (function() { newPosts: (function() {
var len3, results, u; var len5, results, y;
results = []; results = [];
for (u = 0, len3 = posts.length; u < len3; u++) { for (y = 0, len5 = posts.length; y < len5; y++) {
post = posts[u]; post = posts[y];
results.push(post.fullID); results.push(post.fullID);
} }
return results; return results;
})(), })(),
deletedPosts: deletedPosts,
deletedFiles: deletedFiles,
postCount: OP.replies + 1, postCount: OP.replies + 1,
fileCount: OP.images + (!!ThreadUpdater.thread.OP.file && !ThreadUpdater.thread.OP.file.isDead), fileCount: OP.images + (!!thread.OP.file && !thread.OP.file.isDead),
ipCount: OP.unique_ips ipCount: OP.unique_ips
}); });
} }
@ -17769,8 +17719,8 @@
".new {\n" + ".new {\n" +
" color: limegreen;\n" + " color: limegreen;\n" +
"}\n" + "}\n" +
"#update-status.new {\n" + "#update-status:not(.empty) + #update-timer:not(.empty):not(.loading) {\n" +
" margin-right: 5px;\n" + " margin-left: 5px;\n" +
"}\n" + "}\n" +
"#update-timer {\n" + "#update-timer {\n" +
" cursor: pointer;\n" + " cursor: pointer;\n" +

Binary file not shown.

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://ccd0.github.io/4chan-x/builds/4chan-X-beta.crx' version='1.10.3.9' /> <updatecheck codebase='https://ccd0.github.io/4chan-x/builds/4chan-X-beta.crx' version='1.10.4.0' />
</app> </app>
</gupdate> </gupdate>

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://ccd0.github.io/4chan-x/builds/4chan-X.crx' version='1.10.3.9' /> <updatecheck codebase='https://ccd0.github.io/4chan-x/builds/4chan-X.crx' version='1.10.4.0' />
</app> </app>
</gupdate> </gupdate>

View File

@ -3,8 +3,8 @@
"description": "Cross-browser userscript for maximum lurking on 4chan.", "description": "Cross-browser userscript for maximum lurking on 4chan.",
"meta": { "meta": {
"name": "4chan X", "name": "4chan X",
"version": "1.10.3.9", "version": "1.10.4.0",
"date": "2015-03-07T13:50:13.050Z", "date": "2015-03-09T09:49:25.081Z",
"repo": "https://github.com/ccd0/4chan-x/", "repo": "https://github.com/ccd0/4chan-x/",
"page": "https://github.com/ccd0/4chan-x", "page": "https://github.com/ccd0/4chan-x",
"downloads": "https://ccd0.github.io/4chan-x/builds/", "downloads": "https://ccd0.github.io/4chan-x/builds/",