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).
### 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")]

Binary file not shown.

View File

@ -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

View File

@ -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: "<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() {
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" +

Binary file not shown.

View File

@ -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: "<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() {
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" +

Binary file not shown.

View File

@ -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

View File

@ -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: "<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() {
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" +

Binary file not shown.

View File

@ -1,7 +1,7 @@
<?xml version='1.0' encoding='UTF-8'?>
<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>
<app appid='lacclbnghgdicfifcamcmcnilckjamag'>
<updatecheck codebase='https://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>
</gupdate>

View File

@ -1,7 +1,7 @@
<?xml version='1.0' encoding='UTF-8'?>
<gupdate xmlns='http://www.google.com/update2/response' protocol='2.0'>
<app appid='lacclbnghgdicfifcamcmcnilckjamag'>
<updatecheck codebase='https://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>
</gupdate>

View File

@ -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/",