diff --git a/CHANGELOG.md b/CHANGELOG.md
index a4e2e694a..33389a3f7 100755
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -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).
+### 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.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")]
diff --git a/builds/4chan-X-beta.crx b/builds/4chan-X-beta.crx
index 551fcb83d..d93532610 100644
Binary files a/builds/4chan-X-beta.crx and b/builds/4chan-X-beta.crx differ
diff --git a/builds/4chan-X-beta.meta.js b/builds/4chan-X-beta.meta.js
index 766f41645..7bd8490fb 100644
--- a/builds/4chan-X-beta.meta.js
+++ b/builds/4chan-X-beta.meta.js
@@ -1,6 +1,6 @@
// ==UserScript==
// @name 4chan X beta
-// @version 1.10.3.9
+// @version 1.10.4.0
// @minGMVer 1.14
// @minFFVer 26
// @namespace 4chan-X
diff --git a/builds/4chan-X-beta.user.js b/builds/4chan-X-beta.user.js
index 9dca03ef8..455d020af 100644
--- a/builds/4chan-X-beta.user.js
+++ b/builds/4chan-X-beta.user.js
@@ -1,7 +1,7 @@
// Generated by CoffeeScript
// ==UserScript==
// @name 4chan X beta
-// @version 1.10.3.9
+// @version 1.10.4.0
// @minGMVer 1.14
// @minFFVer 26
// @namespace 4chan-X
@@ -377,6 +377,7 @@
'Bottom Scroll': [false, 'Always scroll to the bottom, not the first new post. Useful for event threads.'],
'Scroll BG': [false, 'Auto-scroll background tabs.'],
'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.']
},
'Interval': 30
@@ -394,7 +395,7 @@
doc = d.documentElement;
g = {
- VERSION: '1.10.3.9',
+ VERSION: '1.10.4.0',
NAMESPACE: '4chan X.',
NAME: '4chan X',
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() {
this.kill();
g.posts.rm(this.fullID);
@@ -3565,9 +3537,6 @@
},
update: function(state) {
var now, ref, ref1;
- if (!navigator.onLine) {
- return;
- }
delete Index.pageNum;
if ((ref = Index.req) != null) {
ref.abort();
@@ -7591,7 +7560,6 @@
postID: postID,
val: true
});
- ThreadUpdater.postID = postID;
$.event('QRPostSuccessful', {
boardID: g.BOARD.ID,
threadID: threadID,
@@ -11808,59 +11776,30 @@
});
},
node: function() {
- var x;
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);
},
onUpdate: function(e) {
- var added, fullID, i, ipCount, k, len1, len2, len3, len4, newPosts, obj, postIDs, q, ref, ref1, removed, u, w, x;
- ref = e.detail, ipCount = ref.ipCount, newPosts = ref.newPosts;
- postIDs = ThreadUpdater.postIDs;
+ var deletedPosts, fullID, i, ipCount, k, len1, len2, newPosts, q, ref;
+ ref = e.detail, ipCount = ref.ipCount, newPosts = ref.newPosts, deletedPosts = ref.deletedPosts;
if (ipCount == null) {
return;
}
- if (newPosts.length) {
- obj = {};
- ref1 = MarkNewIPs.postIDs;
- for (k = 0, len1 = ref1.length; k < len1; k++) {
- x = ref1[k];
- obj[x] = true;
- }
- added = 0;
- for (q = 0, len2 = postIDs.length; q < len2; q++) {
- x = postIDs[q];
- if (!(x in obj)) {
- added++;
+ switch (ipCount - MarkNewIPs.ipCount) {
+ case newPosts.length:
+ i = MarkNewIPs.ipCount;
+ for (k = 0, len1 = newPosts.length; k < len1; k++) {
+ fullID = newPosts[k];
+ MarkNewIPs.markNew(g.posts[fullID], ++i);
+ }
+ break;
+ case -deletedPosts.length:
+ for (q = 0, len2 = newPosts.length; q < len2; q++) {
+ fullID = newPosts[q];
+ 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.postIDs = postIDs;
+ return MarkNewIPs.ipCount = ipCount;
},
markNew: function(post, ipCount) {
var counter, suffix;
@@ -12040,7 +11979,7 @@
id: 'updater'
});
$.extend(sc, {
- innerHTML: ""
+ innerHTML: ""
});
$.ready(function() {
return Header.addShortcut(sc);
@@ -12057,7 +11996,6 @@
this.checkPostCount = 0;
this.timer = $('#update-timer', sc);
this.status = $('#update-status', sc);
- this.isUpdating = Conf['Auto Update'];
$.on(this.timer, 'click', this.update);
$.on(this.status, 'click', this.update);
updateLink = $.el('span', {
@@ -12082,7 +12020,7 @@
$.on(input, 'change', this.cb.scrollBG);
this.cb.scrollBG();
} else if (input.name === 'Auto Update') {
- $.on(input, 'change', this.cb.autoUpdate);
+ $.on(input, 'change', this.setInterval);
}
subEntries.push({
el: el
@@ -12112,17 +12050,21 @@
ThreadUpdater.root = this.OP.nodes.root.parentNode;
ThreadUpdater.lastPost = +this.posts.keys[this.posts.keys.length - 1];
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', {
value: Conf['Interval']
}));
$.on(window, 'online offline', ThreadUpdater.cb.online);
$.on(d, 'QRPostSuccessful', ThreadUpdater.cb.checkpost);
$.on(d, 'visibilitychange', ThreadUpdater.cb.visibility);
- if (ThreadUpdater.thread.isArchived) {
- return ThreadUpdater.set('status', 'Archived', 'warning');
- } else {
- return ThreadUpdater.cb.online();
- }
+ return ThreadUpdater.setInterval();
},
/*
@@ -12135,32 +12077,24 @@
if (ThreadUpdater.thread.isDead) {
return;
}
- if (ThreadUpdater.online = navigator.onLine) {
- ThreadUpdater.outdateCount = 0;
- ThreadUpdater.setInterval();
- return ThreadUpdater.set('status', '', '');
+ if (navigator.onLine) {
+ ThreadUpdater.set('status', '');
} else {
- ThreadUpdater.set('timer', '');
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) {
- if (!ThreadUpdater.checkPostCount) {
- if (e && e.detail.threadID !== ThreadUpdater.thread.ID) {
- return;
- }
- ThreadUpdater.seconds = 0;
- ThreadUpdater.outdateCount = 0;
- ThreadUpdater.set('timer', '...');
+ if (e.detail.threadID !== ThreadUpdater.thread.ID) {
+ return;
}
- if (!(ThreadUpdater.thread.isDead || ThreadUpdater.foundPost || ThreadUpdater.checkPostCount >= 5)) {
- return setTimeout(ThreadUpdater.update, ++ThreadUpdater.checkPostCount * $.SECOND);
- }
- ThreadUpdater.setInterval();
+ ThreadUpdater.postID = e.detail.postID;
ThreadUpdater.checkPostCount = 0;
- delete ThreadUpdater.foundPost;
- return delete ThreadUpdater.postID;
+ ThreadUpdater.outdateCount = 0;
+ return ThreadUpdater.setInterval();
},
visibility: function() {
if (d.hidden) {
@@ -12178,9 +12112,6 @@
return !d.hidden;
};
},
- autoUpdate: function() {
- return ThreadUpdater.count(ThreadUpdater.isUpdating = this.checked);
- },
interval: function(e) {
var val;
val = parseInt(this.value, 10);
@@ -12197,16 +12128,15 @@
req = ThreadUpdater.req;
switch (req.status) {
case 200:
- ThreadUpdater.parse(req.response.posts);
+ ThreadUpdater.parse(req);
if (ThreadUpdater.thread.isArchived) {
- ThreadUpdater.set('status', 'Archived', 'warning');
- ThreadUpdater.kill();
+ return ThreadUpdater.kill();
} else {
- ThreadUpdater.setInterval();
+ return ThreadUpdater.setInterval();
}
break;
case 404:
- $.ajax("//a.4cdn.org/" + ThreadUpdater.thread.board + "/catalog.json", {
+ return $.ajax("//a.4cdn.org/" + ThreadUpdater.thread.board + "/catalog.json", {
onloadend: function() {
var confirmed, k, len1, len2, page, q, ref, ref1, thread;
if (this.status === 200) {
@@ -12227,51 +12157,70 @@
confirmed = false;
}
if (confirmed) {
- ThreadUpdater.set('status', '404', 'warning');
return ThreadUpdater.kill();
} else {
return ThreadUpdater.error(req);
}
}
});
- break;
default:
- ThreadUpdater.error(req);
- }
- if (ThreadUpdater.postID) {
- return ThreadUpdater.cb.checkpost();
+ return ThreadUpdater.error(req);
}
}
},
kill: function() {
- ThreadUpdater.set('timer', '');
- clearTimeout(ThreadUpdater.timeoutID);
ThreadUpdater.thread.kill();
+ ThreadUpdater.setInterval();
return $.event('ThreadUpdate', {
404: true,
threadID: ThreadUpdater.thread.fullID
});
},
error: function(req) {
- var klass, ref, text;
+ if (req.status === 304) {
+ ThreadUpdater.set('status', '');
+ }
ThreadUpdater.setInterval();
- ref = req.status === 304 ? ['', ''] : [req.statusText + " (" + req.status + ")", 'warning'], text = ref[0], klass = ref[1];
- return ThreadUpdater.set('status', text, klass);
+ if (!req.status) {
+ return ThreadUpdater.set('status', 'Connection Failed', 'warning');
+ } else if (req.status !== 304) {
+ return ThreadUpdater.set('status', req.statusText + " (" + req.status + ")", 'warning');
+ }
},
setInterval: function() {
- var cur, i, j, limit;
- i = ThreadUpdater.interval + 1;
- if (Conf['Optional Increase']) {
- cur = ThreadUpdater.outdateCount || 1;
- limit = d.hidden ? 7 : 10;
- j = cur <= limit ? cur : limit;
- cur = (Math.floor(i * 0.1) || 1) * j * j;
- ThreadUpdater.seconds = cur > i ? cur <= 300 ? cur : 300 : i;
- } else {
- ThreadUpdater.seconds = i;
+ var cur, interval, j, limit;
+ clearTimeout(ThreadUpdater.timeoutID);
+ if (ThreadUpdater.thread.isDead) {
+ ThreadUpdater.set('status', (ThreadUpdater.thread.isArchived ? 'Archived' : '404'), 'warning');
+ ThreadUpdater.set('timer', '');
+ return;
}
- ThreadUpdater.set('timer', ThreadUpdater.seconds);
- return ThreadUpdater.count(true);
+ if (ThreadUpdater.postID && ThreadUpdater.checkPostCount < 5) {
+ 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() {
var settings;
@@ -12287,40 +12236,22 @@
} else {
el.textContent = text;
}
- if (klass !== void 0) {
- return el.className = klass;
- }
- },
- count: function(start) {
- clearTimeout(ThreadUpdater.timeoutID);
- if (start && ThreadUpdater.isUpdating && navigator.onLine) {
- return ThreadUpdater.timeout();
- }
+ return el.className = klass != null ? klass : (text === '' ? 'empty' : '');
},
timeout: function() {
- var n;
- ThreadUpdater.timeoutID = setTimeout(ThreadUpdater.timeout, 1000);
- if (!(n = --ThreadUpdater.seconds)) {
+ if (ThreadUpdater.seconds) {
+ ThreadUpdater.set('timer', ThreadUpdater.seconds);
+ ThreadUpdater.timeoutID = setTimeout(ThreadUpdater.timeout, 1000);
+ } else {
ThreadUpdater.outdateCount++;
- return ThreadUpdater.update();
- } else if (n <= -60) {
- ThreadUpdater.set('status', 'Retrying', '');
- return ThreadUpdater.update();
- } else if (n > 0) {
- return ThreadUpdater.set('timer', n);
+ ThreadUpdater.update();
}
+ return ThreadUpdater.seconds--;
},
update: function() {
var ref;
- if (!navigator.onLine) {
- return;
- }
- ThreadUpdater.count();
- if (Conf['Auto Update']) {
- ThreadUpdater.set('timer', '...');
- } else {
- ThreadUpdater.set('timer', 'Update');
- }
+ clearTimeout(ThreadUpdater.timeoutID);
+ ThreadUpdater.set('timer', '...', 'loading');
if ((ref = ThreadUpdater.req) != null) {
ref.abort();
}
@@ -12343,17 +12274,25 @@
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);
},
- parse: function(postObjects) {
- var OP, count, files, index, ipCountEl, k, len1, len2, node, num, post, postObject, posts, q, root, scroll;
+ parse: function(req) {
+ 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];
- Build.spoilerRange[ThreadUpdater.thread.board] = OP.custom_spoiler;
- ThreadUpdater.thread.setStatus('Archived', !!+OP.archived);
+ thread = ThreadUpdater.thread;
+ board = thread.board;
+ Build.spoilerRange[board] = OP.custom_spoiler;
+ thread.setStatus('Archived', !!+OP.archived);
ThreadUpdater.updateThreadStatus('Sticky', !!OP.sticky);
ThreadUpdater.updateThreadStatus('Closed', !!OP.closed);
- ThreadUpdater.thread.postLimit = !!OP.bumplimit;
- ThreadUpdater.thread.fileLimit = !!OP.imagelimit;
+ thread.postLimit = !!OP.bumplimit;
+ thread.fileLimit = !!OP.imagelimit;
if (OP.unique_ips != null) {
- ThreadUpdater.thread.ipCount = OP.unique_ips;
+ thread.ipCount = OP.unique_ips;
}
posts = [];
index = [];
@@ -12370,27 +12309,36 @@
continue;
}
count++;
- node = Build.postFromObject(postObject, ThreadUpdater.thread.board.ID);
- posts.push(new Post(node, ThreadUpdater.thread, ThreadUpdater.thread.board));
+ node = Build.postFromObject(postObject, board.ID);
+ posts.push(new Post(node, thread, board));
+ if (ThreadUpdater.postID === num) {
+ delete ThreadUpdater.postID;
+ }
}
- ThreadUpdater.thread.posts.forEach(function(post) {
- var ID;
- ID = +post.ID;
- if (!(post.info.date > Date.now() - 60 * $.SECOND)) {
- if (indexOf.call(index, ID) < 0) {
- post.kill();
- } else if (post.isDead) {
- post.resurrect();
- } else if (post.file && !(post.file.isDead || indexOf.call(files, ID) >= 0)) {
- post.kill(true);
- }
+ deletedPosts = [];
+ ref = ThreadUpdater.postIDs;
+ for (q = 0, len2 = ref.length; q < len2; q++) {
+ ID = ref[q];
+ if (!(indexOf.call(index, ID) < 0)) {
+ continue;
}
- if (ThreadUpdater.postID && ThreadUpdater.postID === ID) {
- return ThreadUpdater.foundPost = true;
+ thread.posts[ID].kill();
+ 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) {
- ThreadUpdater.set('status', '', '');
+ ThreadUpdater.set('status', '');
} else {
ThreadUpdater.set('status', "+" + count, 'new');
ThreadUpdater.outdateCount = 0;
@@ -12405,10 +12353,11 @@
ThreadUpdater.lastPost = posts[count - 1].ID;
Main.callbackNodes(Post, posts);
scroll = Conf['Auto Scroll'] && ThreadUpdater.scrollBG() && ThreadUpdater.root.getBoundingClientRect().bottom - doc.clientHeight < 25;
- for (q = 0, len2 = posts.length; q < len2; q++) {
- post = posts[q];
- root = post.nodes.root;
+ firstPost = null;
+ for (w = 0, len4 = posts.length; w < len4; w++) {
+ post = posts[w];
if (!QuoteThreading.insert(post)) {
+ firstPost || (firstPost = post.nodes.root);
$.add(ThreadUpdater.root, post.nodes.root);
}
}
@@ -12417,8 +12366,8 @@
if (Conf['Bottom Scroll']) {
window.scrollTo(0, d.body.clientHeight);
} else {
- if (root) {
- Header.scrollTo(root);
+ if (firstPost) {
+ 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.nextSibling.textContent = ipCountEl.nextSibling.textContent.replace(/\bposters?\b/, OP.unique_ips === 1 ? 'poster' : 'posters');
}
- ThreadUpdater.postIDs = index;
return $.event('ThreadUpdate', {
404: false,
- threadID: ThreadUpdater.thread.fullID,
+ threadID: thread.fullID,
newPosts: (function() {
- var len3, results, u;
+ var len5, results, y;
results = [];
- for (u = 0, len3 = posts.length; u < len3; u++) {
- post = posts[u];
+ for (y = 0, len5 = posts.length; y < len5; y++) {
+ post = posts[y];
results.push(post.fullID);
}
return results;
})(),
+ deletedPosts: deletedPosts,
+ deletedFiles: deletedFiles,
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
});
}
@@ -17769,8 +17719,8 @@
".new {\n" +
" color: limegreen;\n" +
"}\n" +
-"#update-status.new {\n" +
-" margin-right: 5px;\n" +
+"#update-status:not(.empty) + #update-timer:not(.empty):not(.loading) {\n" +
+" margin-left: 5px;\n" +
"}\n" +
"#update-timer {\n" +
" cursor: pointer;\n" +
diff --git a/builds/4chan-X-noupdate.crx b/builds/4chan-X-noupdate.crx
index 4797a3ea9..4a6e753d3 100644
Binary files a/builds/4chan-X-noupdate.crx and b/builds/4chan-X-noupdate.crx differ
diff --git a/builds/4chan-X-noupdate.user.js b/builds/4chan-X-noupdate.user.js
index 52a8ce252..fc82496ac 100644
--- a/builds/4chan-X-noupdate.user.js
+++ b/builds/4chan-X-noupdate.user.js
@@ -1,7 +1,7 @@
// Generated by CoffeeScript
// ==UserScript==
// @name 4chan X
-// @version 1.10.3.9
+// @version 1.10.4.0
// @minGMVer 1.14
// @minFFVer 26
// @namespace 4chan-X
@@ -376,6 +376,7 @@
'Bottom Scroll': [false, 'Always scroll to the bottom, not the first new post. Useful for event threads.'],
'Scroll BG': [false, 'Auto-scroll background tabs.'],
'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.']
},
'Interval': 30
@@ -393,7 +394,7 @@
doc = d.documentElement;
g = {
- VERSION: '1.10.3.9',
+ VERSION: '1.10.4.0',
NAMESPACE: '4chan X.',
NAME: '4chan X',
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() {
this.kill();
g.posts.rm(this.fullID);
@@ -3564,9 +3536,6 @@
},
update: function(state) {
var now, ref, ref1;
- if (!navigator.onLine) {
- return;
- }
delete Index.pageNum;
if ((ref = Index.req) != null) {
ref.abort();
@@ -7590,7 +7559,6 @@
postID: postID,
val: true
});
- ThreadUpdater.postID = postID;
$.event('QRPostSuccessful', {
boardID: g.BOARD.ID,
threadID: threadID,
@@ -11807,59 +11775,30 @@
});
},
node: function() {
- var x;
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);
},
onUpdate: function(e) {
- var added, fullID, i, ipCount, k, len1, len2, len3, len4, newPosts, obj, postIDs, q, ref, ref1, removed, u, w, x;
- ref = e.detail, ipCount = ref.ipCount, newPosts = ref.newPosts;
- postIDs = ThreadUpdater.postIDs;
+ var deletedPosts, fullID, i, ipCount, k, len1, len2, newPosts, q, ref;
+ ref = e.detail, ipCount = ref.ipCount, newPosts = ref.newPosts, deletedPosts = ref.deletedPosts;
if (ipCount == null) {
return;
}
- if (newPosts.length) {
- obj = {};
- ref1 = MarkNewIPs.postIDs;
- for (k = 0, len1 = ref1.length; k < len1; k++) {
- x = ref1[k];
- obj[x] = true;
- }
- added = 0;
- for (q = 0, len2 = postIDs.length; q < len2; q++) {
- x = postIDs[q];
- if (!(x in obj)) {
- added++;
+ switch (ipCount - MarkNewIPs.ipCount) {
+ case newPosts.length:
+ i = MarkNewIPs.ipCount;
+ for (k = 0, len1 = newPosts.length; k < len1; k++) {
+ fullID = newPosts[k];
+ MarkNewIPs.markNew(g.posts[fullID], ++i);
+ }
+ break;
+ case -deletedPosts.length:
+ for (q = 0, len2 = newPosts.length; q < len2; q++) {
+ fullID = newPosts[q];
+ 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.postIDs = postIDs;
+ return MarkNewIPs.ipCount = ipCount;
},
markNew: function(post, ipCount) {
var counter, suffix;
@@ -12039,7 +11978,7 @@
id: 'updater'
});
$.extend(sc, {
- innerHTML: ""
+ innerHTML: ""
});
$.ready(function() {
return Header.addShortcut(sc);
@@ -12056,7 +11995,6 @@
this.checkPostCount = 0;
this.timer = $('#update-timer', sc);
this.status = $('#update-status', sc);
- this.isUpdating = Conf['Auto Update'];
$.on(this.timer, 'click', this.update);
$.on(this.status, 'click', this.update);
updateLink = $.el('span', {
@@ -12081,7 +12019,7 @@
$.on(input, 'change', this.cb.scrollBG);
this.cb.scrollBG();
} else if (input.name === 'Auto Update') {
- $.on(input, 'change', this.cb.autoUpdate);
+ $.on(input, 'change', this.setInterval);
}
subEntries.push({
el: el
@@ -12111,17 +12049,21 @@
ThreadUpdater.root = this.OP.nodes.root.parentNode;
ThreadUpdater.lastPost = +this.posts.keys[this.posts.keys.length - 1];
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', {
value: Conf['Interval']
}));
$.on(window, 'online offline', ThreadUpdater.cb.online);
$.on(d, 'QRPostSuccessful', ThreadUpdater.cb.checkpost);
$.on(d, 'visibilitychange', ThreadUpdater.cb.visibility);
- if (ThreadUpdater.thread.isArchived) {
- return ThreadUpdater.set('status', 'Archived', 'warning');
- } else {
- return ThreadUpdater.cb.online();
- }
+ return ThreadUpdater.setInterval();
},
/*
@@ -12134,32 +12076,24 @@
if (ThreadUpdater.thread.isDead) {
return;
}
- if (ThreadUpdater.online = navigator.onLine) {
- ThreadUpdater.outdateCount = 0;
- ThreadUpdater.setInterval();
- return ThreadUpdater.set('status', '', '');
+ if (navigator.onLine) {
+ ThreadUpdater.set('status', '');
} else {
- ThreadUpdater.set('timer', '');
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) {
- if (!ThreadUpdater.checkPostCount) {
- if (e && e.detail.threadID !== ThreadUpdater.thread.ID) {
- return;
- }
- ThreadUpdater.seconds = 0;
- ThreadUpdater.outdateCount = 0;
- ThreadUpdater.set('timer', '...');
+ if (e.detail.threadID !== ThreadUpdater.thread.ID) {
+ return;
}
- if (!(ThreadUpdater.thread.isDead || ThreadUpdater.foundPost || ThreadUpdater.checkPostCount >= 5)) {
- return setTimeout(ThreadUpdater.update, ++ThreadUpdater.checkPostCount * $.SECOND);
- }
- ThreadUpdater.setInterval();
+ ThreadUpdater.postID = e.detail.postID;
ThreadUpdater.checkPostCount = 0;
- delete ThreadUpdater.foundPost;
- return delete ThreadUpdater.postID;
+ ThreadUpdater.outdateCount = 0;
+ return ThreadUpdater.setInterval();
},
visibility: function() {
if (d.hidden) {
@@ -12177,9 +12111,6 @@
return !d.hidden;
};
},
- autoUpdate: function() {
- return ThreadUpdater.count(ThreadUpdater.isUpdating = this.checked);
- },
interval: function(e) {
var val;
val = parseInt(this.value, 10);
@@ -12196,16 +12127,15 @@
req = ThreadUpdater.req;
switch (req.status) {
case 200:
- ThreadUpdater.parse(req.response.posts);
+ ThreadUpdater.parse(req);
if (ThreadUpdater.thread.isArchived) {
- ThreadUpdater.set('status', 'Archived', 'warning');
- ThreadUpdater.kill();
+ return ThreadUpdater.kill();
} else {
- ThreadUpdater.setInterval();
+ return ThreadUpdater.setInterval();
}
break;
case 404:
- $.ajax("//a.4cdn.org/" + ThreadUpdater.thread.board + "/catalog.json", {
+ return $.ajax("//a.4cdn.org/" + ThreadUpdater.thread.board + "/catalog.json", {
onloadend: function() {
var confirmed, k, len1, len2, page, q, ref, ref1, thread;
if (this.status === 200) {
@@ -12226,51 +12156,70 @@
confirmed = false;
}
if (confirmed) {
- ThreadUpdater.set('status', '404', 'warning');
return ThreadUpdater.kill();
} else {
return ThreadUpdater.error(req);
}
}
});
- break;
default:
- ThreadUpdater.error(req);
- }
- if (ThreadUpdater.postID) {
- return ThreadUpdater.cb.checkpost();
+ return ThreadUpdater.error(req);
}
}
},
kill: function() {
- ThreadUpdater.set('timer', '');
- clearTimeout(ThreadUpdater.timeoutID);
ThreadUpdater.thread.kill();
+ ThreadUpdater.setInterval();
return $.event('ThreadUpdate', {
404: true,
threadID: ThreadUpdater.thread.fullID
});
},
error: function(req) {
- var klass, ref, text;
+ if (req.status === 304) {
+ ThreadUpdater.set('status', '');
+ }
ThreadUpdater.setInterval();
- ref = req.status === 304 ? ['', ''] : [req.statusText + " (" + req.status + ")", 'warning'], text = ref[0], klass = ref[1];
- return ThreadUpdater.set('status', text, klass);
+ if (!req.status) {
+ return ThreadUpdater.set('status', 'Connection Failed', 'warning');
+ } else if (req.status !== 304) {
+ return ThreadUpdater.set('status', req.statusText + " (" + req.status + ")", 'warning');
+ }
},
setInterval: function() {
- var cur, i, j, limit;
- i = ThreadUpdater.interval + 1;
- if (Conf['Optional Increase']) {
- cur = ThreadUpdater.outdateCount || 1;
- limit = d.hidden ? 7 : 10;
- j = cur <= limit ? cur : limit;
- cur = (Math.floor(i * 0.1) || 1) * j * j;
- ThreadUpdater.seconds = cur > i ? cur <= 300 ? cur : 300 : i;
- } else {
- ThreadUpdater.seconds = i;
+ var cur, interval, j, limit;
+ clearTimeout(ThreadUpdater.timeoutID);
+ if (ThreadUpdater.thread.isDead) {
+ ThreadUpdater.set('status', (ThreadUpdater.thread.isArchived ? 'Archived' : '404'), 'warning');
+ ThreadUpdater.set('timer', '');
+ return;
}
- ThreadUpdater.set('timer', ThreadUpdater.seconds);
- return ThreadUpdater.count(true);
+ if (ThreadUpdater.postID && ThreadUpdater.checkPostCount < 5) {
+ 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() {
var settings;
@@ -12286,40 +12235,22 @@
} else {
el.textContent = text;
}
- if (klass !== void 0) {
- return el.className = klass;
- }
- },
- count: function(start) {
- clearTimeout(ThreadUpdater.timeoutID);
- if (start && ThreadUpdater.isUpdating && navigator.onLine) {
- return ThreadUpdater.timeout();
- }
+ return el.className = klass != null ? klass : (text === '' ? 'empty' : '');
},
timeout: function() {
- var n;
- ThreadUpdater.timeoutID = setTimeout(ThreadUpdater.timeout, 1000);
- if (!(n = --ThreadUpdater.seconds)) {
+ if (ThreadUpdater.seconds) {
+ ThreadUpdater.set('timer', ThreadUpdater.seconds);
+ ThreadUpdater.timeoutID = setTimeout(ThreadUpdater.timeout, 1000);
+ } else {
ThreadUpdater.outdateCount++;
- return ThreadUpdater.update();
- } else if (n <= -60) {
- ThreadUpdater.set('status', 'Retrying', '');
- return ThreadUpdater.update();
- } else if (n > 0) {
- return ThreadUpdater.set('timer', n);
+ ThreadUpdater.update();
}
+ return ThreadUpdater.seconds--;
},
update: function() {
var ref;
- if (!navigator.onLine) {
- return;
- }
- ThreadUpdater.count();
- if (Conf['Auto Update']) {
- ThreadUpdater.set('timer', '...');
- } else {
- ThreadUpdater.set('timer', 'Update');
- }
+ clearTimeout(ThreadUpdater.timeoutID);
+ ThreadUpdater.set('timer', '...', 'loading');
if ((ref = ThreadUpdater.req) != null) {
ref.abort();
}
@@ -12342,17 +12273,25 @@
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);
},
- parse: function(postObjects) {
- var OP, count, files, index, ipCountEl, k, len1, len2, node, num, post, postObject, posts, q, root, scroll;
+ parse: function(req) {
+ 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];
- Build.spoilerRange[ThreadUpdater.thread.board] = OP.custom_spoiler;
- ThreadUpdater.thread.setStatus('Archived', !!+OP.archived);
+ thread = ThreadUpdater.thread;
+ board = thread.board;
+ Build.spoilerRange[board] = OP.custom_spoiler;
+ thread.setStatus('Archived', !!+OP.archived);
ThreadUpdater.updateThreadStatus('Sticky', !!OP.sticky);
ThreadUpdater.updateThreadStatus('Closed', !!OP.closed);
- ThreadUpdater.thread.postLimit = !!OP.bumplimit;
- ThreadUpdater.thread.fileLimit = !!OP.imagelimit;
+ thread.postLimit = !!OP.bumplimit;
+ thread.fileLimit = !!OP.imagelimit;
if (OP.unique_ips != null) {
- ThreadUpdater.thread.ipCount = OP.unique_ips;
+ thread.ipCount = OP.unique_ips;
}
posts = [];
index = [];
@@ -12369,27 +12308,36 @@
continue;
}
count++;
- node = Build.postFromObject(postObject, ThreadUpdater.thread.board.ID);
- posts.push(new Post(node, ThreadUpdater.thread, ThreadUpdater.thread.board));
+ node = Build.postFromObject(postObject, board.ID);
+ posts.push(new Post(node, thread, board));
+ if (ThreadUpdater.postID === num) {
+ delete ThreadUpdater.postID;
+ }
}
- ThreadUpdater.thread.posts.forEach(function(post) {
- var ID;
- ID = +post.ID;
- if (!(post.info.date > Date.now() - 60 * $.SECOND)) {
- if (indexOf.call(index, ID) < 0) {
- post.kill();
- } else if (post.isDead) {
- post.resurrect();
- } else if (post.file && !(post.file.isDead || indexOf.call(files, ID) >= 0)) {
- post.kill(true);
- }
+ deletedPosts = [];
+ ref = ThreadUpdater.postIDs;
+ for (q = 0, len2 = ref.length; q < len2; q++) {
+ ID = ref[q];
+ if (!(indexOf.call(index, ID) < 0)) {
+ continue;
}
- if (ThreadUpdater.postID && ThreadUpdater.postID === ID) {
- return ThreadUpdater.foundPost = true;
+ thread.posts[ID].kill();
+ 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) {
- ThreadUpdater.set('status', '', '');
+ ThreadUpdater.set('status', '');
} else {
ThreadUpdater.set('status', "+" + count, 'new');
ThreadUpdater.outdateCount = 0;
@@ -12404,10 +12352,11 @@
ThreadUpdater.lastPost = posts[count - 1].ID;
Main.callbackNodes(Post, posts);
scroll = Conf['Auto Scroll'] && ThreadUpdater.scrollBG() && ThreadUpdater.root.getBoundingClientRect().bottom - doc.clientHeight < 25;
- for (q = 0, len2 = posts.length; q < len2; q++) {
- post = posts[q];
- root = post.nodes.root;
+ firstPost = null;
+ for (w = 0, len4 = posts.length; w < len4; w++) {
+ post = posts[w];
if (!QuoteThreading.insert(post)) {
+ firstPost || (firstPost = post.nodes.root);
$.add(ThreadUpdater.root, post.nodes.root);
}
}
@@ -12416,8 +12365,8 @@
if (Conf['Bottom Scroll']) {
window.scrollTo(0, d.body.clientHeight);
} else {
- if (root) {
- Header.scrollTo(root);
+ if (firstPost) {
+ 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.nextSibling.textContent = ipCountEl.nextSibling.textContent.replace(/\bposters?\b/, OP.unique_ips === 1 ? 'poster' : 'posters');
}
- ThreadUpdater.postIDs = index;
return $.event('ThreadUpdate', {
404: false,
- threadID: ThreadUpdater.thread.fullID,
+ threadID: thread.fullID,
newPosts: (function() {
- var len3, results, u;
+ var len5, results, y;
results = [];
- for (u = 0, len3 = posts.length; u < len3; u++) {
- post = posts[u];
+ for (y = 0, len5 = posts.length; y < len5; y++) {
+ post = posts[y];
results.push(post.fullID);
}
return results;
})(),
+ deletedPosts: deletedPosts,
+ deletedFiles: deletedFiles,
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
});
}
@@ -17768,8 +17718,8 @@
".new {\n" +
" color: limegreen;\n" +
"}\n" +
-"#update-status.new {\n" +
-" margin-right: 5px;\n" +
+"#update-status:not(.empty) + #update-timer:not(.empty):not(.loading) {\n" +
+" margin-left: 5px;\n" +
"}\n" +
"#update-timer {\n" +
" cursor: pointer;\n" +
diff --git a/builds/4chan-X.crx b/builds/4chan-X.crx
index 79c8da059..2e1581dce 100644
Binary files a/builds/4chan-X.crx and b/builds/4chan-X.crx differ
diff --git a/builds/4chan-X.meta.js b/builds/4chan-X.meta.js
index 326a1c557..e7427a244 100644
--- a/builds/4chan-X.meta.js
+++ b/builds/4chan-X.meta.js
@@ -1,6 +1,6 @@
// ==UserScript==
// @name 4chan X
-// @version 1.10.3.9
+// @version 1.10.4.0
// @minGMVer 1.14
// @minFFVer 26
// @namespace 4chan-X
diff --git a/builds/4chan-X.user.js b/builds/4chan-X.user.js
index 0fb85b7ff..e9f836a8d 100644
--- a/builds/4chan-X.user.js
+++ b/builds/4chan-X.user.js
@@ -1,7 +1,7 @@
// Generated by CoffeeScript
// ==UserScript==
// @name 4chan X
-// @version 1.10.3.9
+// @version 1.10.4.0
// @minGMVer 1.14
// @minFFVer 26
// @namespace 4chan-X
@@ -377,6 +377,7 @@
'Bottom Scroll': [false, 'Always scroll to the bottom, not the first new post. Useful for event threads.'],
'Scroll BG': [false, 'Auto-scroll background tabs.'],
'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.']
},
'Interval': 30
@@ -394,7 +395,7 @@
doc = d.documentElement;
g = {
- VERSION: '1.10.3.9',
+ VERSION: '1.10.4.0',
NAMESPACE: '4chan X.',
NAME: '4chan X',
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() {
this.kill();
g.posts.rm(this.fullID);
@@ -3565,9 +3537,6 @@
},
update: function(state) {
var now, ref, ref1;
- if (!navigator.onLine) {
- return;
- }
delete Index.pageNum;
if ((ref = Index.req) != null) {
ref.abort();
@@ -7591,7 +7560,6 @@
postID: postID,
val: true
});
- ThreadUpdater.postID = postID;
$.event('QRPostSuccessful', {
boardID: g.BOARD.ID,
threadID: threadID,
@@ -11808,59 +11776,30 @@
});
},
node: function() {
- var x;
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);
},
onUpdate: function(e) {
- var added, fullID, i, ipCount, k, len1, len2, len3, len4, newPosts, obj, postIDs, q, ref, ref1, removed, u, w, x;
- ref = e.detail, ipCount = ref.ipCount, newPosts = ref.newPosts;
- postIDs = ThreadUpdater.postIDs;
+ var deletedPosts, fullID, i, ipCount, k, len1, len2, newPosts, q, ref;
+ ref = e.detail, ipCount = ref.ipCount, newPosts = ref.newPosts, deletedPosts = ref.deletedPosts;
if (ipCount == null) {
return;
}
- if (newPosts.length) {
- obj = {};
- ref1 = MarkNewIPs.postIDs;
- for (k = 0, len1 = ref1.length; k < len1; k++) {
- x = ref1[k];
- obj[x] = true;
- }
- added = 0;
- for (q = 0, len2 = postIDs.length; q < len2; q++) {
- x = postIDs[q];
- if (!(x in obj)) {
- added++;
+ switch (ipCount - MarkNewIPs.ipCount) {
+ case newPosts.length:
+ i = MarkNewIPs.ipCount;
+ for (k = 0, len1 = newPosts.length; k < len1; k++) {
+ fullID = newPosts[k];
+ MarkNewIPs.markNew(g.posts[fullID], ++i);
+ }
+ break;
+ case -deletedPosts.length:
+ for (q = 0, len2 = newPosts.length; q < len2; q++) {
+ fullID = newPosts[q];
+ 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.postIDs = postIDs;
+ return MarkNewIPs.ipCount = ipCount;
},
markNew: function(post, ipCount) {
var counter, suffix;
@@ -12040,7 +11979,7 @@
id: 'updater'
});
$.extend(sc, {
- innerHTML: ""
+ innerHTML: ""
});
$.ready(function() {
return Header.addShortcut(sc);
@@ -12057,7 +11996,6 @@
this.checkPostCount = 0;
this.timer = $('#update-timer', sc);
this.status = $('#update-status', sc);
- this.isUpdating = Conf['Auto Update'];
$.on(this.timer, 'click', this.update);
$.on(this.status, 'click', this.update);
updateLink = $.el('span', {
@@ -12082,7 +12020,7 @@
$.on(input, 'change', this.cb.scrollBG);
this.cb.scrollBG();
} else if (input.name === 'Auto Update') {
- $.on(input, 'change', this.cb.autoUpdate);
+ $.on(input, 'change', this.setInterval);
}
subEntries.push({
el: el
@@ -12112,17 +12050,21 @@
ThreadUpdater.root = this.OP.nodes.root.parentNode;
ThreadUpdater.lastPost = +this.posts.keys[this.posts.keys.length - 1];
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', {
value: Conf['Interval']
}));
$.on(window, 'online offline', ThreadUpdater.cb.online);
$.on(d, 'QRPostSuccessful', ThreadUpdater.cb.checkpost);
$.on(d, 'visibilitychange', ThreadUpdater.cb.visibility);
- if (ThreadUpdater.thread.isArchived) {
- return ThreadUpdater.set('status', 'Archived', 'warning');
- } else {
- return ThreadUpdater.cb.online();
- }
+ return ThreadUpdater.setInterval();
},
/*
@@ -12135,32 +12077,24 @@
if (ThreadUpdater.thread.isDead) {
return;
}
- if (ThreadUpdater.online = navigator.onLine) {
- ThreadUpdater.outdateCount = 0;
- ThreadUpdater.setInterval();
- return ThreadUpdater.set('status', '', '');
+ if (navigator.onLine) {
+ ThreadUpdater.set('status', '');
} else {
- ThreadUpdater.set('timer', '');
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) {
- if (!ThreadUpdater.checkPostCount) {
- if (e && e.detail.threadID !== ThreadUpdater.thread.ID) {
- return;
- }
- ThreadUpdater.seconds = 0;
- ThreadUpdater.outdateCount = 0;
- ThreadUpdater.set('timer', '...');
+ if (e.detail.threadID !== ThreadUpdater.thread.ID) {
+ return;
}
- if (!(ThreadUpdater.thread.isDead || ThreadUpdater.foundPost || ThreadUpdater.checkPostCount >= 5)) {
- return setTimeout(ThreadUpdater.update, ++ThreadUpdater.checkPostCount * $.SECOND);
- }
- ThreadUpdater.setInterval();
+ ThreadUpdater.postID = e.detail.postID;
ThreadUpdater.checkPostCount = 0;
- delete ThreadUpdater.foundPost;
- return delete ThreadUpdater.postID;
+ ThreadUpdater.outdateCount = 0;
+ return ThreadUpdater.setInterval();
},
visibility: function() {
if (d.hidden) {
@@ -12178,9 +12112,6 @@
return !d.hidden;
};
},
- autoUpdate: function() {
- return ThreadUpdater.count(ThreadUpdater.isUpdating = this.checked);
- },
interval: function(e) {
var val;
val = parseInt(this.value, 10);
@@ -12197,16 +12128,15 @@
req = ThreadUpdater.req;
switch (req.status) {
case 200:
- ThreadUpdater.parse(req.response.posts);
+ ThreadUpdater.parse(req);
if (ThreadUpdater.thread.isArchived) {
- ThreadUpdater.set('status', 'Archived', 'warning');
- ThreadUpdater.kill();
+ return ThreadUpdater.kill();
} else {
- ThreadUpdater.setInterval();
+ return ThreadUpdater.setInterval();
}
break;
case 404:
- $.ajax("//a.4cdn.org/" + ThreadUpdater.thread.board + "/catalog.json", {
+ return $.ajax("//a.4cdn.org/" + ThreadUpdater.thread.board + "/catalog.json", {
onloadend: function() {
var confirmed, k, len1, len2, page, q, ref, ref1, thread;
if (this.status === 200) {
@@ -12227,51 +12157,70 @@
confirmed = false;
}
if (confirmed) {
- ThreadUpdater.set('status', '404', 'warning');
return ThreadUpdater.kill();
} else {
return ThreadUpdater.error(req);
}
}
});
- break;
default:
- ThreadUpdater.error(req);
- }
- if (ThreadUpdater.postID) {
- return ThreadUpdater.cb.checkpost();
+ return ThreadUpdater.error(req);
}
}
},
kill: function() {
- ThreadUpdater.set('timer', '');
- clearTimeout(ThreadUpdater.timeoutID);
ThreadUpdater.thread.kill();
+ ThreadUpdater.setInterval();
return $.event('ThreadUpdate', {
404: true,
threadID: ThreadUpdater.thread.fullID
});
},
error: function(req) {
- var klass, ref, text;
+ if (req.status === 304) {
+ ThreadUpdater.set('status', '');
+ }
ThreadUpdater.setInterval();
- ref = req.status === 304 ? ['', ''] : [req.statusText + " (" + req.status + ")", 'warning'], text = ref[0], klass = ref[1];
- return ThreadUpdater.set('status', text, klass);
+ if (!req.status) {
+ return ThreadUpdater.set('status', 'Connection Failed', 'warning');
+ } else if (req.status !== 304) {
+ return ThreadUpdater.set('status', req.statusText + " (" + req.status + ")", 'warning');
+ }
},
setInterval: function() {
- var cur, i, j, limit;
- i = ThreadUpdater.interval + 1;
- if (Conf['Optional Increase']) {
- cur = ThreadUpdater.outdateCount || 1;
- limit = d.hidden ? 7 : 10;
- j = cur <= limit ? cur : limit;
- cur = (Math.floor(i * 0.1) || 1) * j * j;
- ThreadUpdater.seconds = cur > i ? cur <= 300 ? cur : 300 : i;
- } else {
- ThreadUpdater.seconds = i;
+ var cur, interval, j, limit;
+ clearTimeout(ThreadUpdater.timeoutID);
+ if (ThreadUpdater.thread.isDead) {
+ ThreadUpdater.set('status', (ThreadUpdater.thread.isArchived ? 'Archived' : '404'), 'warning');
+ ThreadUpdater.set('timer', '');
+ return;
}
- ThreadUpdater.set('timer', ThreadUpdater.seconds);
- return ThreadUpdater.count(true);
+ if (ThreadUpdater.postID && ThreadUpdater.checkPostCount < 5) {
+ 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() {
var settings;
@@ -12287,40 +12236,22 @@
} else {
el.textContent = text;
}
- if (klass !== void 0) {
- return el.className = klass;
- }
- },
- count: function(start) {
- clearTimeout(ThreadUpdater.timeoutID);
- if (start && ThreadUpdater.isUpdating && navigator.onLine) {
- return ThreadUpdater.timeout();
- }
+ return el.className = klass != null ? klass : (text === '' ? 'empty' : '');
},
timeout: function() {
- var n;
- ThreadUpdater.timeoutID = setTimeout(ThreadUpdater.timeout, 1000);
- if (!(n = --ThreadUpdater.seconds)) {
+ if (ThreadUpdater.seconds) {
+ ThreadUpdater.set('timer', ThreadUpdater.seconds);
+ ThreadUpdater.timeoutID = setTimeout(ThreadUpdater.timeout, 1000);
+ } else {
ThreadUpdater.outdateCount++;
- return ThreadUpdater.update();
- } else if (n <= -60) {
- ThreadUpdater.set('status', 'Retrying', '');
- return ThreadUpdater.update();
- } else if (n > 0) {
- return ThreadUpdater.set('timer', n);
+ ThreadUpdater.update();
}
+ return ThreadUpdater.seconds--;
},
update: function() {
var ref;
- if (!navigator.onLine) {
- return;
- }
- ThreadUpdater.count();
- if (Conf['Auto Update']) {
- ThreadUpdater.set('timer', '...');
- } else {
- ThreadUpdater.set('timer', 'Update');
- }
+ clearTimeout(ThreadUpdater.timeoutID);
+ ThreadUpdater.set('timer', '...', 'loading');
if ((ref = ThreadUpdater.req) != null) {
ref.abort();
}
@@ -12343,17 +12274,25 @@
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);
},
- parse: function(postObjects) {
- var OP, count, files, index, ipCountEl, k, len1, len2, node, num, post, postObject, posts, q, root, scroll;
+ parse: function(req) {
+ 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];
- Build.spoilerRange[ThreadUpdater.thread.board] = OP.custom_spoiler;
- ThreadUpdater.thread.setStatus('Archived', !!+OP.archived);
+ thread = ThreadUpdater.thread;
+ board = thread.board;
+ Build.spoilerRange[board] = OP.custom_spoiler;
+ thread.setStatus('Archived', !!+OP.archived);
ThreadUpdater.updateThreadStatus('Sticky', !!OP.sticky);
ThreadUpdater.updateThreadStatus('Closed', !!OP.closed);
- ThreadUpdater.thread.postLimit = !!OP.bumplimit;
- ThreadUpdater.thread.fileLimit = !!OP.imagelimit;
+ thread.postLimit = !!OP.bumplimit;
+ thread.fileLimit = !!OP.imagelimit;
if (OP.unique_ips != null) {
- ThreadUpdater.thread.ipCount = OP.unique_ips;
+ thread.ipCount = OP.unique_ips;
}
posts = [];
index = [];
@@ -12370,27 +12309,36 @@
continue;
}
count++;
- node = Build.postFromObject(postObject, ThreadUpdater.thread.board.ID);
- posts.push(new Post(node, ThreadUpdater.thread, ThreadUpdater.thread.board));
+ node = Build.postFromObject(postObject, board.ID);
+ posts.push(new Post(node, thread, board));
+ if (ThreadUpdater.postID === num) {
+ delete ThreadUpdater.postID;
+ }
}
- ThreadUpdater.thread.posts.forEach(function(post) {
- var ID;
- ID = +post.ID;
- if (!(post.info.date > Date.now() - 60 * $.SECOND)) {
- if (indexOf.call(index, ID) < 0) {
- post.kill();
- } else if (post.isDead) {
- post.resurrect();
- } else if (post.file && !(post.file.isDead || indexOf.call(files, ID) >= 0)) {
- post.kill(true);
- }
+ deletedPosts = [];
+ ref = ThreadUpdater.postIDs;
+ for (q = 0, len2 = ref.length; q < len2; q++) {
+ ID = ref[q];
+ if (!(indexOf.call(index, ID) < 0)) {
+ continue;
}
- if (ThreadUpdater.postID && ThreadUpdater.postID === ID) {
- return ThreadUpdater.foundPost = true;
+ thread.posts[ID].kill();
+ 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) {
- ThreadUpdater.set('status', '', '');
+ ThreadUpdater.set('status', '');
} else {
ThreadUpdater.set('status', "+" + count, 'new');
ThreadUpdater.outdateCount = 0;
@@ -12405,10 +12353,11 @@
ThreadUpdater.lastPost = posts[count - 1].ID;
Main.callbackNodes(Post, posts);
scroll = Conf['Auto Scroll'] && ThreadUpdater.scrollBG() && ThreadUpdater.root.getBoundingClientRect().bottom - doc.clientHeight < 25;
- for (q = 0, len2 = posts.length; q < len2; q++) {
- post = posts[q];
- root = post.nodes.root;
+ firstPost = null;
+ for (w = 0, len4 = posts.length; w < len4; w++) {
+ post = posts[w];
if (!QuoteThreading.insert(post)) {
+ firstPost || (firstPost = post.nodes.root);
$.add(ThreadUpdater.root, post.nodes.root);
}
}
@@ -12417,8 +12366,8 @@
if (Conf['Bottom Scroll']) {
window.scrollTo(0, d.body.clientHeight);
} else {
- if (root) {
- Header.scrollTo(root);
+ if (firstPost) {
+ 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.nextSibling.textContent = ipCountEl.nextSibling.textContent.replace(/\bposters?\b/, OP.unique_ips === 1 ? 'poster' : 'posters');
}
- ThreadUpdater.postIDs = index;
return $.event('ThreadUpdate', {
404: false,
- threadID: ThreadUpdater.thread.fullID,
+ threadID: thread.fullID,
newPosts: (function() {
- var len3, results, u;
+ var len5, results, y;
results = [];
- for (u = 0, len3 = posts.length; u < len3; u++) {
- post = posts[u];
+ for (y = 0, len5 = posts.length; y < len5; y++) {
+ post = posts[y];
results.push(post.fullID);
}
return results;
})(),
+ deletedPosts: deletedPosts,
+ deletedFiles: deletedFiles,
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
});
}
@@ -17769,8 +17719,8 @@
".new {\n" +
" color: limegreen;\n" +
"}\n" +
-"#update-status.new {\n" +
-" margin-right: 5px;\n" +
+"#update-status:not(.empty) + #update-timer:not(.empty):not(.loading) {\n" +
+" margin-left: 5px;\n" +
"}\n" +
"#update-timer {\n" +
" cursor: pointer;\n" +
diff --git a/builds/4chan-X.zip b/builds/4chan-X.zip
index 99c40ba01..98ffffebc 100644
Binary files a/builds/4chan-X.zip and b/builds/4chan-X.zip differ
diff --git a/builds/updates-beta.xml b/builds/updates-beta.xml
index 9e7515816..cc1174608 100644
--- a/builds/updates-beta.xml
+++ b/builds/updates-beta.xml
@@ -1,7 +1,7 @@
-
+
diff --git a/builds/updates.xml b/builds/updates.xml
index 9259d08c3..5bdec4652 100644
--- a/builds/updates.xml
+++ b/builds/updates.xml
@@ -1,7 +1,7 @@
-
+
diff --git a/package.json b/package.json
index 8420b9f22..05d96096f 100755
--- a/package.json
+++ b/package.json
@@ -3,8 +3,8 @@
"description": "Cross-browser userscript for maximum lurking on 4chan.",
"meta": {
"name": "4chan X",
- "version": "1.10.3.9",
- "date": "2015-03-07T13:50:13.050Z",
+ "version": "1.10.4.0",
+ "date": "2015-03-09T09:49:25.081Z",
"repo": "https://github.com/ccd0/4chan-x/",
"page": "https://github.com/ccd0/4chan-x",
"downloads": "https://ccd0.github.io/4chan-x/builds/",