Release 4chan X v1.9.6.0.
This commit is contained in:
parent
fb30a59fe7
commit
0ffddd8a79
10
CHANGELOG.md
10
CHANGELOG.md
@ -2,6 +2,16 @@ The attributions below are for work that has been incorporated into the script a
|
||||
|
||||
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.9.6.x -->
|
||||
### v1.9.6.0
|
||||
*2014-10-05* - [[Firefox](https://raw.githubusercontent.com/ccd0/4chan-x/1.9.6.0/builds/4chan-X-noupdate.user.js "Firefox version")] [[Chromium](https://raw.githubusercontent.com/ccd0/4chan-x/1.9.6.0/builds/4chan-X-noupdate.crx "Chromium version")]
|
||||
|
||||
**ccd0**
|
||||
- Update cooldown timers to include 4chan's new 5-minute global thread cooldown.
|
||||
- Fix various cooldown bugs.
|
||||
- Improve error messages for invalid filter entries.
|
||||
- Fix bug causing hidden threads list to be reverted to a prior state due to syncing with native catalog.
|
||||
|
||||
<!-- v1.9.5.x -->
|
||||
### v1.9.5.3
|
||||
*2014-10-03* - [[Firefox](https://raw.githubusercontent.com/ccd0/4chan-x/1.9.5.3/builds/4chan-X-noupdate.user.js "Firefox version")] [[Chromium](https://raw.githubusercontent.com/ccd0/4chan-x/1.9.5.3/builds/4chan-X-noupdate.crx "Chromium version")]
|
||||
|
||||
2
LICENSE
2
LICENSE
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* 4chan X - Version 1.9.5.3
|
||||
* 4chan X - Version 1.9.6.0
|
||||
*
|
||||
* Licensed under the MIT license.
|
||||
* https://github.com/ccd0/4chan-x/blob/master/LICENSE
|
||||
|
||||
Binary file not shown.
@ -1,6 +1,6 @@
|
||||
// ==UserScript==
|
||||
// @name 4chan X beta
|
||||
// @version 1.9.5.3
|
||||
// @version 1.9.6.0
|
||||
// @minGMVer 1.14
|
||||
// @minFFVer 26
|
||||
// @namespace 4chan-X
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// Generated by CoffeeScript
|
||||
// ==UserScript==
|
||||
// @name 4chan X beta
|
||||
// @version 1.9.5.3
|
||||
// @version 1.9.6.0
|
||||
// @minGMVer 1.14
|
||||
// @minFFVer 26
|
||||
// @namespace 4chan-X
|
||||
@ -24,7 +24,7 @@
|
||||
// ==/UserScript==
|
||||
|
||||
/*
|
||||
* 4chan X - Version 1.9.5.3
|
||||
* 4chan X - Version 1.9.6.0
|
||||
*
|
||||
* Licensed under the MIT license.
|
||||
* https://github.com/ccd0/4chan-x/blob/master/LICENSE
|
||||
@ -380,7 +380,7 @@
|
||||
doc = d.documentElement;
|
||||
|
||||
g = {
|
||||
VERSION: '1.9.5.3',
|
||||
VERSION: '1.9.6.0',
|
||||
NAMESPACE: '4chan X.',
|
||||
NAME: '4chan X',
|
||||
FAQ: 'https://github.com/ccd0/4chan-x/wiki/Frequently-Asked-Questions',
|
||||
@ -797,8 +797,13 @@
|
||||
var cb, key, newValue;
|
||||
key = _arg.key, newValue = _arg.newValue;
|
||||
if (cb = $.syncing[key]) {
|
||||
oldValue[key] = newValue;
|
||||
return cb(JSON.parse(newValue), key);
|
||||
if (newValue != null) {
|
||||
oldValue[key] = newValue;
|
||||
return cb(JSON.parse(newValue), key);
|
||||
} else {
|
||||
delete oldValue[key];
|
||||
return cb(void 0, key);
|
||||
}
|
||||
}
|
||||
};
|
||||
$.on(window, 'storage', onChange);
|
||||
@ -4659,7 +4664,7 @@
|
||||
Filter = {
|
||||
filters: {},
|
||||
init: function() {
|
||||
var boards, err, filter, hl, key, op, regexp, stub, top, _i, _len, _ref, _ref1, _ref2, _ref3, _ref4, _ref5;
|
||||
var boards, err, filter, hl, key, line, op, regexp, stub, top, _i, _len, _ref, _ref1, _ref2, _ref3, _ref4, _ref5;
|
||||
if (g.VIEW === 'catalog' || !Conf['Filter']) {
|
||||
return;
|
||||
}
|
||||
@ -4670,14 +4675,14 @@
|
||||
this.filters[key] = [];
|
||||
_ref = Conf[key].split('\n');
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
filter = _ref[_i];
|
||||
if (filter[0] === '#') {
|
||||
line = _ref[_i];
|
||||
if (line[0] === '#') {
|
||||
continue;
|
||||
}
|
||||
if (!(regexp = filter.match(/\/(.+)\/(\w*)/))) {
|
||||
if (!(regexp = line.match(/\/(.+)\/(\w*)/))) {
|
||||
continue;
|
||||
}
|
||||
filter = filter.replace(regexp[0], '');
|
||||
filter = line.replace(regexp[0], '');
|
||||
boards = ((_ref1 = filter.match(/boards:([^;]+)/)) != null ? _ref1[1].toLowerCase() : void 0) || 'global';
|
||||
if (boards !== 'global' && (_ref2 = g.BOARD.ID, __indexOf.call(boards.split(','), _ref2) < 0)) {
|
||||
continue;
|
||||
@ -4689,7 +4694,7 @@
|
||||
regexp = RegExp(regexp[1], regexp[2]);
|
||||
} catch (_error) {
|
||||
err = _error;
|
||||
new Notice('warning', err.message, 60);
|
||||
new Notice('warning', [$.tn("Invalid " + key + " filter:"), $.el('br'), $.tn(line), $.el('br'), $.tn(err.message)], 60);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -5288,16 +5293,64 @@
|
||||
|
||||
ThreadHiding = {
|
||||
init: function() {
|
||||
if (g.VIEW !== 'index' || !Conf['Thread Hiding Buttons'] && !Conf['Thread Hiding Link'] && !Conf['JSON Navigation']) {
|
||||
if (g.VIEW === 'thread' || !Conf['Thread Hiding Buttons'] && !Conf['Thread Hiding Link'] && !Conf['JSON Navigation']) {
|
||||
return;
|
||||
}
|
||||
this.db = new DataBoard('hiddenThreads');
|
||||
this.syncCatalog();
|
||||
if (g.VIEW === 'catalog') {
|
||||
return this.catalogWatch();
|
||||
}
|
||||
this.catalogSet(g.BOARD);
|
||||
return Thread.callbacks.push({
|
||||
name: 'Thread Hiding',
|
||||
cb: this.node
|
||||
});
|
||||
},
|
||||
catalogSet: function(board) {
|
||||
var hiddenThreads, threadID;
|
||||
hiddenThreads = ThreadHiding.db.get({
|
||||
boardID: board.ID,
|
||||
defaultValue: {}
|
||||
});
|
||||
for (threadID in hiddenThreads) {
|
||||
hiddenThreads[threadID] = true;
|
||||
}
|
||||
return localStorage.setItem("4chan-hide-t-" + board, JSON.stringify(hiddenThreads));
|
||||
},
|
||||
catalogWatch: function() {
|
||||
this.hiddenThreads = JSON.parse(localStorage.getItem("4chan-hide-t-" + g.BOARD)) || {};
|
||||
return $.ready(function() {
|
||||
return new MutationObserver(ThreadHiding.catalogSave).observe($.id('threads'), {
|
||||
attributes: true,
|
||||
subtree: true,
|
||||
attributeFilter: ['style']
|
||||
});
|
||||
});
|
||||
},
|
||||
catalogSave: function() {
|
||||
var hiddenThreads2, threadID;
|
||||
hiddenThreads2 = JSON.parse(localStorage.getItem("4chan-hide-t-" + g.BOARD)) || {};
|
||||
for (threadID in hiddenThreads2) {
|
||||
if (!(threadID in ThreadHiding.hiddenThreads)) {
|
||||
ThreadHiding.db.set({
|
||||
boardID: g.BOARD.ID,
|
||||
threadID: threadID,
|
||||
val: {
|
||||
makeStub: Conf['Stubs']
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
for (threadID in ThreadHiding.hiddenThreads) {
|
||||
if (!(threadID in hiddenThreads2)) {
|
||||
ThreadHiding.db["delete"]({
|
||||
boardID: g.BOARD.ID,
|
||||
threadID: threadID
|
||||
});
|
||||
}
|
||||
}
|
||||
return ThreadHiding.hiddenThreads = hiddenThreads2;
|
||||
},
|
||||
node: function() {
|
||||
var data;
|
||||
if (data = ThreadHiding.db.get({
|
||||
@ -5321,56 +5374,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
syncCatalog: function() {
|
||||
var hiddenThreads, hiddenThreadsOnCatalog, threadID;
|
||||
hiddenThreads = ThreadHiding.db.get({
|
||||
boardID: g.BOARD.ID,
|
||||
defaultValue: {}
|
||||
});
|
||||
hiddenThreadsOnCatalog = JSON.parse(localStorage.getItem("4chan-hide-t-" + g.BOARD)) || {};
|
||||
for (threadID in hiddenThreadsOnCatalog) {
|
||||
if (!(threadID in hiddenThreads)) {
|
||||
hiddenThreads[threadID] = {};
|
||||
}
|
||||
}
|
||||
for (threadID in hiddenThreads) {
|
||||
if (!(threadID in hiddenThreadsOnCatalog)) {
|
||||
delete hiddenThreads[threadID];
|
||||
}
|
||||
}
|
||||
if ((ThreadHiding.db.data.lastChecked || 0) > Date.now() - $.MINUTE) {
|
||||
ThreadHiding.cleanCatalog(hiddenThreadsOnCatalog);
|
||||
}
|
||||
return ThreadHiding.db.set({
|
||||
boardID: g.BOARD.ID,
|
||||
val: hiddenThreads
|
||||
});
|
||||
},
|
||||
cleanCatalog: function(hiddenThreadsOnCatalog) {
|
||||
return $.cache("//a.4cdn.org/" + g.BOARD + "/threads.json", function() {
|
||||
var page, thread, threads, _i, _j, _len, _len1, _ref, _ref1;
|
||||
if (this.status !== 200) {
|
||||
return;
|
||||
}
|
||||
threads = {};
|
||||
_ref = this.response;
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
page = _ref[_i];
|
||||
_ref1 = page.threads;
|
||||
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
||||
thread = _ref1[_j];
|
||||
if (thread.no in hiddenThreadsOnCatalog) {
|
||||
threads[thread.no] = hiddenThreadsOnCatalog[thread.no];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Object.keys(threads).length) {
|
||||
return localStorage.setItem("4chan-hide-t-" + g.BOARD, JSON.stringify(threads));
|
||||
} else {
|
||||
return localStorage.removeItem("4chan-hide-t-" + g.BOARD);
|
||||
}
|
||||
});
|
||||
},
|
||||
menu: {
|
||||
init: function() {
|
||||
var apply, div, hideStubLink, makeStub;
|
||||
@ -5501,8 +5504,6 @@
|
||||
return $.prepend(root, thread.stub);
|
||||
},
|
||||
saveHiddenState: function(thread, makeStub) {
|
||||
var hiddenThreadsOnCatalog;
|
||||
hiddenThreadsOnCatalog = JSON.parse(localStorage.getItem("4chan-hide-t-" + g.BOARD)) || {};
|
||||
if (thread.isHidden) {
|
||||
ThreadHiding.db.set({
|
||||
boardID: thread.board.ID,
|
||||
@ -5511,15 +5512,13 @@
|
||||
makeStub: makeStub
|
||||
}
|
||||
});
|
||||
hiddenThreadsOnCatalog[thread] = true;
|
||||
} else {
|
||||
ThreadHiding.db["delete"]({
|
||||
boardID: thread.board.ID,
|
||||
threadID: thread.ID
|
||||
});
|
||||
delete hiddenThreadsOnCatalog[thread];
|
||||
}
|
||||
return localStorage.setItem("4chan-hide-t-" + g.BOARD, JSON.stringify(hiddenThreadsOnCatalog));
|
||||
return ThreadHiding.catalogSet(thread.board);
|
||||
},
|
||||
toggle: function(thread) {
|
||||
if (!(thread instanceof Thread)) {
|
||||
@ -7145,14 +7144,10 @@
|
||||
err = 'This CAPTCHA is no longer valid because it has expired.';
|
||||
}
|
||||
QR.cooldown.auto = QR.captcha.isEnabled ? !!QR.captcha.captchas.length : err === 'Connection error with sys.4chan.org.' ? true : false;
|
||||
QR.cooldown.set({
|
||||
delay: 2
|
||||
});
|
||||
} else if (err.textContent && (m = err.textContent.match(/wait\s+(\d+)\s+second/i))) {
|
||||
QR.cooldown.addDelay(post, 2);
|
||||
} else if (err.textContent && (m = err.textContent.match(/wait\s+(\d+)\s+second/i)) && !/duplicate/i.test(err.textContent)) {
|
||||
QR.cooldown.auto = QR.captcha.isEnabled ? !!QR.captcha.captchas.length : true;
|
||||
QR.cooldown.set({
|
||||
delay: m[1]
|
||||
});
|
||||
QR.cooldown.addDelay(post, +m[1]);
|
||||
} else {
|
||||
QR.cooldown.auto = false;
|
||||
}
|
||||
@ -7213,12 +7208,7 @@
|
||||
}
|
||||
post.rm();
|
||||
}
|
||||
QR.cooldown.set({
|
||||
req: req,
|
||||
post: post,
|
||||
isReply: isReply,
|
||||
threadID: threadID
|
||||
});
|
||||
QR.cooldown.add(req.uploadEndTime, threadID, postID);
|
||||
URL = threadID === postID ? "" + window.location.origin + "/" + g.BOARD + "/thread/" + threadID : g.VIEW === 'index' && !QR.cooldown.auto && Conf['Open Post in New Tab'] ? "" + window.location.origin + "/" + g.BOARD + "/thread/" + threadID + "#p" + postID : void 0;
|
||||
if (URL) {
|
||||
if (Conf['Open Post in New Tab']) {
|
||||
@ -7455,119 +7445,184 @@
|
||||
};
|
||||
|
||||
QR.cooldown = {
|
||||
seconds: 0,
|
||||
init: function() {
|
||||
var key, setTimers, type;
|
||||
var delay, items, key, keys, scope, setTimers, type, _ref, _results;
|
||||
if (!Conf['Cooldown']) {
|
||||
return;
|
||||
}
|
||||
setTimers = (function(_this) {
|
||||
return function(e) {
|
||||
return QR.cooldown.types = e.detail;
|
||||
return QR.cooldown.delays = e.detail;
|
||||
};
|
||||
})(this);
|
||||
$.on(window, 'cooldown:timers', setTimers);
|
||||
$.globalEval('window.dispatchEvent(new CustomEvent("cooldown:timers", {detail: cooldowns}))');
|
||||
$.off(window, 'cooldown:timers', setTimers);
|
||||
for (type in QR.cooldown.types) {
|
||||
QR.cooldown.types[type] = +QR.cooldown.types[type];
|
||||
QR.cooldown.maxDelay = 0;
|
||||
_ref = QR.cooldown.delays;
|
||||
for (type in _ref) {
|
||||
delay = _ref[type];
|
||||
if (type !== 'thread') {
|
||||
QR.cooldown.maxDelay = Math.max(QR.cooldown.maxDelay, delay);
|
||||
}
|
||||
}
|
||||
key = "cooldown." + g.BOARD;
|
||||
$.get(key, {}, function(item) {
|
||||
QR.cooldown.cooldowns = item[key];
|
||||
QR.cooldown.delays['thread_global'] = 300;
|
||||
keys = QR.cooldown.keys = {
|
||||
local: "cooldown." + g.BOARD,
|
||||
global: 'cooldown.global'
|
||||
};
|
||||
items = {};
|
||||
for (scope in keys) {
|
||||
key = keys[scope];
|
||||
items[key] = {};
|
||||
}
|
||||
$.get(items, function(items) {
|
||||
for (scope in keys) {
|
||||
key = keys[scope];
|
||||
QR.cooldown[scope] = items[key];
|
||||
}
|
||||
return QR.cooldown.start();
|
||||
});
|
||||
return $.sync(key, QR.cooldown.sync);
|
||||
_results = [];
|
||||
for (scope in keys) {
|
||||
key = keys[scope];
|
||||
_results.push($.sync(key, QR.cooldown.sync(scope)));
|
||||
}
|
||||
return _results;
|
||||
},
|
||||
start: function() {
|
||||
if (QR.cooldown.isCounting || !Object.keys(QR.cooldown.cooldowns).length) {
|
||||
if (QR.cooldown.isCounting || Object.keys(QR.cooldown.local).length + Object.keys(QR.cooldown.global).length === 0) {
|
||||
return;
|
||||
}
|
||||
QR.cooldown.isCounting = true;
|
||||
return QR.cooldown.count();
|
||||
},
|
||||
sync: function(cooldowns) {
|
||||
var id;
|
||||
for (id in cooldowns) {
|
||||
QR.cooldown.cooldowns[id] = cooldowns[id];
|
||||
}
|
||||
return QR.cooldown.start();
|
||||
sync: function(scope) {
|
||||
return function(cooldowns) {
|
||||
QR.cooldown[scope] = cooldowns || {};
|
||||
return QR.cooldown.start();
|
||||
};
|
||||
},
|
||||
set: function(data) {
|
||||
var cooldown, delay, isReply, post, req, start, threadID;
|
||||
add: function(start, threadID, postID) {
|
||||
var boardID;
|
||||
if (!Conf['Cooldown']) {
|
||||
return;
|
||||
}
|
||||
req = data.req, post = data.post, isReply = data.isReply, threadID = data.threadID, delay = data.delay;
|
||||
start = req ? req.uploadEndTime : Date.now();
|
||||
if (delay) {
|
||||
cooldown = {
|
||||
delay: delay
|
||||
};
|
||||
} else {
|
||||
cooldown = {
|
||||
isReply: isReply,
|
||||
threadID: threadID
|
||||
};
|
||||
boardID = g.BOARD.ID;
|
||||
QR.cooldown.set('local', start, {
|
||||
threadID: threadID,
|
||||
postID: postID
|
||||
});
|
||||
if (threadID === postID) {
|
||||
QR.cooldown.set('global', start, {
|
||||
boardID: boardID,
|
||||
threadID: threadID,
|
||||
postID: postID
|
||||
});
|
||||
}
|
||||
QR.cooldown.cooldowns[start] = cooldown;
|
||||
$.set("cooldown." + g.BOARD, QR.cooldown.cooldowns);
|
||||
return QR.cooldown.start();
|
||||
},
|
||||
unset: function(id) {
|
||||
delete QR.cooldown.cooldowns[id];
|
||||
if (Object.keys(QR.cooldown.cooldowns).length) {
|
||||
return $.set("cooldown." + g.BOARD, QR.cooldown.cooldowns);
|
||||
addDelay: function(post, delay) {
|
||||
var cooldown;
|
||||
if (!Conf['Cooldown']) {
|
||||
return;
|
||||
}
|
||||
cooldown = QR.cooldown.categorize(post);
|
||||
cooldown.delay = delay;
|
||||
QR.cooldown.set('local', Date.now(), cooldown);
|
||||
return QR.cooldown.start();
|
||||
},
|
||||
"delete": function(post) {
|
||||
var cooldown, id, _ref;
|
||||
if (!(Conf['Cooldown'] && g.BOARD.ID === post.board.ID)) {
|
||||
return;
|
||||
}
|
||||
$.forceSync(QR.cooldown.keys.local);
|
||||
_ref = QR.cooldown.local;
|
||||
for (id in _ref) {
|
||||
cooldown = _ref[id];
|
||||
if ((cooldown.delay == null) && cooldown.threadID === post.thread.ID && cooldown.postID === post.ID) {
|
||||
delete QR.cooldown.local[id];
|
||||
}
|
||||
}
|
||||
return QR.cooldown.save('local');
|
||||
},
|
||||
categorize: function(post) {
|
||||
if (post.thread === 'new') {
|
||||
return {
|
||||
type: 'thread'
|
||||
};
|
||||
} else {
|
||||
return $["delete"]("cooldown." + g.BOARD);
|
||||
return {
|
||||
type: !!post.file ? 'image' : 'reply',
|
||||
threadID: +post.thread
|
||||
};
|
||||
}
|
||||
},
|
||||
set: function(scope, id, value) {
|
||||
$.forceSync(QR.cooldown.keys[scope]);
|
||||
QR.cooldown[scope][id] = value;
|
||||
return $.set(QR.cooldown.keys[scope], QR.cooldown[scope]);
|
||||
},
|
||||
save: function(scope) {
|
||||
if (Object.keys(QR.cooldown[scope]).length) {
|
||||
return $.set(QR.cooldown.keys[scope], QR.cooldown[scope]);
|
||||
} else {
|
||||
return $["delete"](QR.cooldown.keys[scope]);
|
||||
}
|
||||
},
|
||||
count: function() {
|
||||
var cooldown, cooldowns, elapsed, hasFile, isReply, maxTimer, now, post, seconds, start, type, types, update, _ref;
|
||||
if (!Object.keys(QR.cooldown.cooldowns).length) {
|
||||
$["delete"]("cooldown." + g.BOARD);
|
||||
delete QR.cooldown.isCounting;
|
||||
delete QR.cooldown.seconds;
|
||||
QR.status();
|
||||
return;
|
||||
}
|
||||
clearTimeout(QR.cooldown.timeout);
|
||||
QR.cooldown.timeout = setTimeout(QR.cooldown.count, $.SECOND);
|
||||
var cooldown, elapsed, key, maxDelay, now, save, scope, seconds, start, suffix, threadID, type, update, _ref, _ref1, _ref2;
|
||||
now = Date.now();
|
||||
post = QR.posts[0];
|
||||
isReply = post.thread !== 'new';
|
||||
hasFile = !!post.file;
|
||||
seconds = null;
|
||||
_ref = QR.cooldown, types = _ref.types, cooldowns = _ref.cooldowns;
|
||||
for (start in cooldowns) {
|
||||
cooldown = cooldowns[start];
|
||||
start = +start;
|
||||
if ('delay' in cooldown) {
|
||||
if (cooldown.delay) {
|
||||
seconds = Math.max(seconds, cooldown.delay--);
|
||||
} else {
|
||||
seconds = Math.max(seconds, 0);
|
||||
QR.cooldown.unset(start);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (isReply === cooldown.isReply) {
|
||||
_ref = QR.cooldown.categorize(QR.posts[0]), type = _ref.type, threadID = _ref.threadID;
|
||||
seconds = 0;
|
||||
_ref1 = QR.cooldown.keys;
|
||||
for (scope in _ref1) {
|
||||
key = _ref1[scope];
|
||||
$.forceSync(key);
|
||||
save = false;
|
||||
_ref2 = QR.cooldown[scope];
|
||||
for (start in _ref2) {
|
||||
cooldown = _ref2[start];
|
||||
start = +start;
|
||||
elapsed = Math.floor((now - start) / $.SECOND);
|
||||
if (elapsed < 0) {
|
||||
QR.cooldown.unset(start);
|
||||
delete QR.cooldown[scope][start];
|
||||
save = true;
|
||||
continue;
|
||||
}
|
||||
type = !isReply ? 'thread' : hasFile ? 'image' : 'reply';
|
||||
maxTimer = Math.max(types[type] || 0, types[type + '_intra'] || 0);
|
||||
if (!((start <= now && now <= start + maxTimer * $.SECOND))) {
|
||||
QR.cooldown.unset(start);
|
||||
if (cooldown.delay != null) {
|
||||
if (cooldown.delay <= elapsed) {
|
||||
delete QR.cooldown[scope][start];
|
||||
save = true;
|
||||
} else if (cooldown.type === type && cooldown.threadID === threadID) {
|
||||
seconds = Math.max(seconds, cooldown.delay - elapsed);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (isReply && +post.thread === cooldown.threadID) {
|
||||
type += '_intra';
|
||||
maxDelay = cooldown.threadID !== cooldown.postID ? QR.cooldown.maxDelay : QR.cooldown.delays[scope === 'global' ? 'thread_global' : 'thread'];
|
||||
if (maxDelay <= elapsed) {
|
||||
delete QR.cooldown[scope][start];
|
||||
save = true;
|
||||
continue;
|
||||
}
|
||||
seconds = Math.max(seconds, types[type] - elapsed);
|
||||
if ((type === 'thread') === (cooldown.threadID === cooldown.postID)) {
|
||||
suffix = scope === 'global' ? '_global' : type !== 'thread' && threadID === cooldown.threadID ? '_intra' : '';
|
||||
seconds = Math.max(seconds, QR.cooldown.delays[type + suffix] - elapsed);
|
||||
}
|
||||
}
|
||||
if (save) {
|
||||
QR.cooldown.save(scope);
|
||||
}
|
||||
}
|
||||
update = seconds !== null || !!QR.cooldown.seconds;
|
||||
if (Object.keys(QR.cooldown.local).length + Object.keys(QR.cooldown.global).length) {
|
||||
clearTimeout(QR.cooldown.timeout);
|
||||
QR.cooldown.timeout = setTimeout(QR.cooldown.count, $.SECOND);
|
||||
} else {
|
||||
delete QR.cooldown.isCounting;
|
||||
}
|
||||
update = seconds !== QR.cooldown.seconds;
|
||||
QR.cooldown.seconds = seconds;
|
||||
if (update) {
|
||||
QR.status();
|
||||
@ -10188,6 +10243,7 @@
|
||||
$.on(link, 'click', DeleteLink["delete"]);
|
||||
} else {
|
||||
if (resDoc.title === 'Updating index...') {
|
||||
QR.cooldown["delete"](post);
|
||||
(post.origin || post).kill(fileOnly);
|
||||
}
|
||||
s = 'Deleted';
|
||||
@ -13406,7 +13462,7 @@
|
||||
className: 'dialog'
|
||||
});
|
||||
$.extend(dialog, {
|
||||
innerHTML: "<nav><div class=sections-list></div><p class='imp-exp-result warning'></p><div class=credits><a class=export>Export</a> | <a class=import>Import</a> | <a class=reset>Reset Settings</a> | <input type=file hidden><a href='https://github.com/ccd0/4chan-x' target=_blank>4chan X</a> | <a href='https://github.com/ccd0/4chan-x/blob/master/CHANGELOG.md' target=_blank>1.9.5.3</a> | <a href='https://github.com/ccd0/4chan-x/issues' target=_blank>Issues</a> | <a href=javascript:; class='close fa fa-times' title=Close></a></div></nav><div class=section-container><section></section></div>"
|
||||
innerHTML: "<nav><div class=sections-list></div><p class='imp-exp-result warning'></p><div class=credits><a class=export>Export</a> | <a class=import>Import</a> | <a class=reset>Reset Settings</a> | <input type=file hidden><a href='https://github.com/ccd0/4chan-x' target=_blank>4chan X</a> | <a href='https://github.com/ccd0/4chan-x/blob/master/CHANGELOG.md' target=_blank>1.9.6.0</a> | <a href='https://github.com/ccd0/4chan-x/issues' target=_blank>Issues</a> | <a href=javascript:; class='close fa fa-times' title=Close></a></div></nav><div class=section-container><section></section></div>"
|
||||
});
|
||||
$.on($('.export', Settings.dialog), 'click', Settings["export"]);
|
||||
$.on($('.import', Settings.dialog), 'click', Settings["import"]);
|
||||
|
||||
Binary file not shown.
@ -1,7 +1,7 @@
|
||||
// Generated by CoffeeScript
|
||||
// ==UserScript==
|
||||
// @name 4chan X
|
||||
// @version 1.9.5.3
|
||||
// @version 1.9.6.0
|
||||
// @minGMVer 1.14
|
||||
// @minFFVer 26
|
||||
// @namespace 4chan-X
|
||||
@ -23,7 +23,7 @@
|
||||
// ==/UserScript==
|
||||
|
||||
/*
|
||||
* 4chan X - Version 1.9.5.3
|
||||
* 4chan X - Version 1.9.6.0
|
||||
*
|
||||
* Licensed under the MIT license.
|
||||
* https://github.com/ccd0/4chan-x/blob/master/LICENSE
|
||||
@ -379,7 +379,7 @@
|
||||
doc = d.documentElement;
|
||||
|
||||
g = {
|
||||
VERSION: '1.9.5.3',
|
||||
VERSION: '1.9.6.0',
|
||||
NAMESPACE: '4chan X.',
|
||||
NAME: '4chan X',
|
||||
FAQ: 'https://github.com/ccd0/4chan-x/wiki/Frequently-Asked-Questions',
|
||||
@ -796,8 +796,13 @@
|
||||
var cb, key, newValue;
|
||||
key = _arg.key, newValue = _arg.newValue;
|
||||
if (cb = $.syncing[key]) {
|
||||
oldValue[key] = newValue;
|
||||
return cb(JSON.parse(newValue), key);
|
||||
if (newValue != null) {
|
||||
oldValue[key] = newValue;
|
||||
return cb(JSON.parse(newValue), key);
|
||||
} else {
|
||||
delete oldValue[key];
|
||||
return cb(void 0, key);
|
||||
}
|
||||
}
|
||||
};
|
||||
$.on(window, 'storage', onChange);
|
||||
@ -4658,7 +4663,7 @@
|
||||
Filter = {
|
||||
filters: {},
|
||||
init: function() {
|
||||
var boards, err, filter, hl, key, op, regexp, stub, top, _i, _len, _ref, _ref1, _ref2, _ref3, _ref4, _ref5;
|
||||
var boards, err, filter, hl, key, line, op, regexp, stub, top, _i, _len, _ref, _ref1, _ref2, _ref3, _ref4, _ref5;
|
||||
if (g.VIEW === 'catalog' || !Conf['Filter']) {
|
||||
return;
|
||||
}
|
||||
@ -4669,14 +4674,14 @@
|
||||
this.filters[key] = [];
|
||||
_ref = Conf[key].split('\n');
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
filter = _ref[_i];
|
||||
if (filter[0] === '#') {
|
||||
line = _ref[_i];
|
||||
if (line[0] === '#') {
|
||||
continue;
|
||||
}
|
||||
if (!(regexp = filter.match(/\/(.+)\/(\w*)/))) {
|
||||
if (!(regexp = line.match(/\/(.+)\/(\w*)/))) {
|
||||
continue;
|
||||
}
|
||||
filter = filter.replace(regexp[0], '');
|
||||
filter = line.replace(regexp[0], '');
|
||||
boards = ((_ref1 = filter.match(/boards:([^;]+)/)) != null ? _ref1[1].toLowerCase() : void 0) || 'global';
|
||||
if (boards !== 'global' && (_ref2 = g.BOARD.ID, __indexOf.call(boards.split(','), _ref2) < 0)) {
|
||||
continue;
|
||||
@ -4688,7 +4693,7 @@
|
||||
regexp = RegExp(regexp[1], regexp[2]);
|
||||
} catch (_error) {
|
||||
err = _error;
|
||||
new Notice('warning', err.message, 60);
|
||||
new Notice('warning', [$.tn("Invalid " + key + " filter:"), $.el('br'), $.tn(line), $.el('br'), $.tn(err.message)], 60);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -5287,16 +5292,64 @@
|
||||
|
||||
ThreadHiding = {
|
||||
init: function() {
|
||||
if (g.VIEW !== 'index' || !Conf['Thread Hiding Buttons'] && !Conf['Thread Hiding Link'] && !Conf['JSON Navigation']) {
|
||||
if (g.VIEW === 'thread' || !Conf['Thread Hiding Buttons'] && !Conf['Thread Hiding Link'] && !Conf['JSON Navigation']) {
|
||||
return;
|
||||
}
|
||||
this.db = new DataBoard('hiddenThreads');
|
||||
this.syncCatalog();
|
||||
if (g.VIEW === 'catalog') {
|
||||
return this.catalogWatch();
|
||||
}
|
||||
this.catalogSet(g.BOARD);
|
||||
return Thread.callbacks.push({
|
||||
name: 'Thread Hiding',
|
||||
cb: this.node
|
||||
});
|
||||
},
|
||||
catalogSet: function(board) {
|
||||
var hiddenThreads, threadID;
|
||||
hiddenThreads = ThreadHiding.db.get({
|
||||
boardID: board.ID,
|
||||
defaultValue: {}
|
||||
});
|
||||
for (threadID in hiddenThreads) {
|
||||
hiddenThreads[threadID] = true;
|
||||
}
|
||||
return localStorage.setItem("4chan-hide-t-" + board, JSON.stringify(hiddenThreads));
|
||||
},
|
||||
catalogWatch: function() {
|
||||
this.hiddenThreads = JSON.parse(localStorage.getItem("4chan-hide-t-" + g.BOARD)) || {};
|
||||
return $.ready(function() {
|
||||
return new MutationObserver(ThreadHiding.catalogSave).observe($.id('threads'), {
|
||||
attributes: true,
|
||||
subtree: true,
|
||||
attributeFilter: ['style']
|
||||
});
|
||||
});
|
||||
},
|
||||
catalogSave: function() {
|
||||
var hiddenThreads2, threadID;
|
||||
hiddenThreads2 = JSON.parse(localStorage.getItem("4chan-hide-t-" + g.BOARD)) || {};
|
||||
for (threadID in hiddenThreads2) {
|
||||
if (!(threadID in ThreadHiding.hiddenThreads)) {
|
||||
ThreadHiding.db.set({
|
||||
boardID: g.BOARD.ID,
|
||||
threadID: threadID,
|
||||
val: {
|
||||
makeStub: Conf['Stubs']
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
for (threadID in ThreadHiding.hiddenThreads) {
|
||||
if (!(threadID in hiddenThreads2)) {
|
||||
ThreadHiding.db["delete"]({
|
||||
boardID: g.BOARD.ID,
|
||||
threadID: threadID
|
||||
});
|
||||
}
|
||||
}
|
||||
return ThreadHiding.hiddenThreads = hiddenThreads2;
|
||||
},
|
||||
node: function() {
|
||||
var data;
|
||||
if (data = ThreadHiding.db.get({
|
||||
@ -5320,56 +5373,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
syncCatalog: function() {
|
||||
var hiddenThreads, hiddenThreadsOnCatalog, threadID;
|
||||
hiddenThreads = ThreadHiding.db.get({
|
||||
boardID: g.BOARD.ID,
|
||||
defaultValue: {}
|
||||
});
|
||||
hiddenThreadsOnCatalog = JSON.parse(localStorage.getItem("4chan-hide-t-" + g.BOARD)) || {};
|
||||
for (threadID in hiddenThreadsOnCatalog) {
|
||||
if (!(threadID in hiddenThreads)) {
|
||||
hiddenThreads[threadID] = {};
|
||||
}
|
||||
}
|
||||
for (threadID in hiddenThreads) {
|
||||
if (!(threadID in hiddenThreadsOnCatalog)) {
|
||||
delete hiddenThreads[threadID];
|
||||
}
|
||||
}
|
||||
if ((ThreadHiding.db.data.lastChecked || 0) > Date.now() - $.MINUTE) {
|
||||
ThreadHiding.cleanCatalog(hiddenThreadsOnCatalog);
|
||||
}
|
||||
return ThreadHiding.db.set({
|
||||
boardID: g.BOARD.ID,
|
||||
val: hiddenThreads
|
||||
});
|
||||
},
|
||||
cleanCatalog: function(hiddenThreadsOnCatalog) {
|
||||
return $.cache("//a.4cdn.org/" + g.BOARD + "/threads.json", function() {
|
||||
var page, thread, threads, _i, _j, _len, _len1, _ref, _ref1;
|
||||
if (this.status !== 200) {
|
||||
return;
|
||||
}
|
||||
threads = {};
|
||||
_ref = this.response;
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
page = _ref[_i];
|
||||
_ref1 = page.threads;
|
||||
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
||||
thread = _ref1[_j];
|
||||
if (thread.no in hiddenThreadsOnCatalog) {
|
||||
threads[thread.no] = hiddenThreadsOnCatalog[thread.no];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Object.keys(threads).length) {
|
||||
return localStorage.setItem("4chan-hide-t-" + g.BOARD, JSON.stringify(threads));
|
||||
} else {
|
||||
return localStorage.removeItem("4chan-hide-t-" + g.BOARD);
|
||||
}
|
||||
});
|
||||
},
|
||||
menu: {
|
||||
init: function() {
|
||||
var apply, div, hideStubLink, makeStub;
|
||||
@ -5500,8 +5503,6 @@
|
||||
return $.prepend(root, thread.stub);
|
||||
},
|
||||
saveHiddenState: function(thread, makeStub) {
|
||||
var hiddenThreadsOnCatalog;
|
||||
hiddenThreadsOnCatalog = JSON.parse(localStorage.getItem("4chan-hide-t-" + g.BOARD)) || {};
|
||||
if (thread.isHidden) {
|
||||
ThreadHiding.db.set({
|
||||
boardID: thread.board.ID,
|
||||
@ -5510,15 +5511,13 @@
|
||||
makeStub: makeStub
|
||||
}
|
||||
});
|
||||
hiddenThreadsOnCatalog[thread] = true;
|
||||
} else {
|
||||
ThreadHiding.db["delete"]({
|
||||
boardID: thread.board.ID,
|
||||
threadID: thread.ID
|
||||
});
|
||||
delete hiddenThreadsOnCatalog[thread];
|
||||
}
|
||||
return localStorage.setItem("4chan-hide-t-" + g.BOARD, JSON.stringify(hiddenThreadsOnCatalog));
|
||||
return ThreadHiding.catalogSet(thread.board);
|
||||
},
|
||||
toggle: function(thread) {
|
||||
if (!(thread instanceof Thread)) {
|
||||
@ -7144,14 +7143,10 @@
|
||||
err = 'This CAPTCHA is no longer valid because it has expired.';
|
||||
}
|
||||
QR.cooldown.auto = QR.captcha.isEnabled ? !!QR.captcha.captchas.length : err === 'Connection error with sys.4chan.org.' ? true : false;
|
||||
QR.cooldown.set({
|
||||
delay: 2
|
||||
});
|
||||
} else if (err.textContent && (m = err.textContent.match(/wait\s+(\d+)\s+second/i))) {
|
||||
QR.cooldown.addDelay(post, 2);
|
||||
} else if (err.textContent && (m = err.textContent.match(/wait\s+(\d+)\s+second/i)) && !/duplicate/i.test(err.textContent)) {
|
||||
QR.cooldown.auto = QR.captcha.isEnabled ? !!QR.captcha.captchas.length : true;
|
||||
QR.cooldown.set({
|
||||
delay: m[1]
|
||||
});
|
||||
QR.cooldown.addDelay(post, +m[1]);
|
||||
} else {
|
||||
QR.cooldown.auto = false;
|
||||
}
|
||||
@ -7212,12 +7207,7 @@
|
||||
}
|
||||
post.rm();
|
||||
}
|
||||
QR.cooldown.set({
|
||||
req: req,
|
||||
post: post,
|
||||
isReply: isReply,
|
||||
threadID: threadID
|
||||
});
|
||||
QR.cooldown.add(req.uploadEndTime, threadID, postID);
|
||||
URL = threadID === postID ? "" + window.location.origin + "/" + g.BOARD + "/thread/" + threadID : g.VIEW === 'index' && !QR.cooldown.auto && Conf['Open Post in New Tab'] ? "" + window.location.origin + "/" + g.BOARD + "/thread/" + threadID + "#p" + postID : void 0;
|
||||
if (URL) {
|
||||
if (Conf['Open Post in New Tab']) {
|
||||
@ -7454,119 +7444,184 @@
|
||||
};
|
||||
|
||||
QR.cooldown = {
|
||||
seconds: 0,
|
||||
init: function() {
|
||||
var key, setTimers, type;
|
||||
var delay, items, key, keys, scope, setTimers, type, _ref, _results;
|
||||
if (!Conf['Cooldown']) {
|
||||
return;
|
||||
}
|
||||
setTimers = (function(_this) {
|
||||
return function(e) {
|
||||
return QR.cooldown.types = e.detail;
|
||||
return QR.cooldown.delays = e.detail;
|
||||
};
|
||||
})(this);
|
||||
$.on(window, 'cooldown:timers', setTimers);
|
||||
$.globalEval('window.dispatchEvent(new CustomEvent("cooldown:timers", {detail: cooldowns}))');
|
||||
$.off(window, 'cooldown:timers', setTimers);
|
||||
for (type in QR.cooldown.types) {
|
||||
QR.cooldown.types[type] = +QR.cooldown.types[type];
|
||||
QR.cooldown.maxDelay = 0;
|
||||
_ref = QR.cooldown.delays;
|
||||
for (type in _ref) {
|
||||
delay = _ref[type];
|
||||
if (type !== 'thread') {
|
||||
QR.cooldown.maxDelay = Math.max(QR.cooldown.maxDelay, delay);
|
||||
}
|
||||
}
|
||||
key = "cooldown." + g.BOARD;
|
||||
$.get(key, {}, function(item) {
|
||||
QR.cooldown.cooldowns = item[key];
|
||||
QR.cooldown.delays['thread_global'] = 300;
|
||||
keys = QR.cooldown.keys = {
|
||||
local: "cooldown." + g.BOARD,
|
||||
global: 'cooldown.global'
|
||||
};
|
||||
items = {};
|
||||
for (scope in keys) {
|
||||
key = keys[scope];
|
||||
items[key] = {};
|
||||
}
|
||||
$.get(items, function(items) {
|
||||
for (scope in keys) {
|
||||
key = keys[scope];
|
||||
QR.cooldown[scope] = items[key];
|
||||
}
|
||||
return QR.cooldown.start();
|
||||
});
|
||||
return $.sync(key, QR.cooldown.sync);
|
||||
_results = [];
|
||||
for (scope in keys) {
|
||||
key = keys[scope];
|
||||
_results.push($.sync(key, QR.cooldown.sync(scope)));
|
||||
}
|
||||
return _results;
|
||||
},
|
||||
start: function() {
|
||||
if (QR.cooldown.isCounting || !Object.keys(QR.cooldown.cooldowns).length) {
|
||||
if (QR.cooldown.isCounting || Object.keys(QR.cooldown.local).length + Object.keys(QR.cooldown.global).length === 0) {
|
||||
return;
|
||||
}
|
||||
QR.cooldown.isCounting = true;
|
||||
return QR.cooldown.count();
|
||||
},
|
||||
sync: function(cooldowns) {
|
||||
var id;
|
||||
for (id in cooldowns) {
|
||||
QR.cooldown.cooldowns[id] = cooldowns[id];
|
||||
}
|
||||
return QR.cooldown.start();
|
||||
sync: function(scope) {
|
||||
return function(cooldowns) {
|
||||
QR.cooldown[scope] = cooldowns || {};
|
||||
return QR.cooldown.start();
|
||||
};
|
||||
},
|
||||
set: function(data) {
|
||||
var cooldown, delay, isReply, post, req, start, threadID;
|
||||
add: function(start, threadID, postID) {
|
||||
var boardID;
|
||||
if (!Conf['Cooldown']) {
|
||||
return;
|
||||
}
|
||||
req = data.req, post = data.post, isReply = data.isReply, threadID = data.threadID, delay = data.delay;
|
||||
start = req ? req.uploadEndTime : Date.now();
|
||||
if (delay) {
|
||||
cooldown = {
|
||||
delay: delay
|
||||
};
|
||||
} else {
|
||||
cooldown = {
|
||||
isReply: isReply,
|
||||
threadID: threadID
|
||||
};
|
||||
boardID = g.BOARD.ID;
|
||||
QR.cooldown.set('local', start, {
|
||||
threadID: threadID,
|
||||
postID: postID
|
||||
});
|
||||
if (threadID === postID) {
|
||||
QR.cooldown.set('global', start, {
|
||||
boardID: boardID,
|
||||
threadID: threadID,
|
||||
postID: postID
|
||||
});
|
||||
}
|
||||
QR.cooldown.cooldowns[start] = cooldown;
|
||||
$.set("cooldown." + g.BOARD, QR.cooldown.cooldowns);
|
||||
return QR.cooldown.start();
|
||||
},
|
||||
unset: function(id) {
|
||||
delete QR.cooldown.cooldowns[id];
|
||||
if (Object.keys(QR.cooldown.cooldowns).length) {
|
||||
return $.set("cooldown." + g.BOARD, QR.cooldown.cooldowns);
|
||||
addDelay: function(post, delay) {
|
||||
var cooldown;
|
||||
if (!Conf['Cooldown']) {
|
||||
return;
|
||||
}
|
||||
cooldown = QR.cooldown.categorize(post);
|
||||
cooldown.delay = delay;
|
||||
QR.cooldown.set('local', Date.now(), cooldown);
|
||||
return QR.cooldown.start();
|
||||
},
|
||||
"delete": function(post) {
|
||||
var cooldown, id, _ref;
|
||||
if (!(Conf['Cooldown'] && g.BOARD.ID === post.board.ID)) {
|
||||
return;
|
||||
}
|
||||
$.forceSync(QR.cooldown.keys.local);
|
||||
_ref = QR.cooldown.local;
|
||||
for (id in _ref) {
|
||||
cooldown = _ref[id];
|
||||
if ((cooldown.delay == null) && cooldown.threadID === post.thread.ID && cooldown.postID === post.ID) {
|
||||
delete QR.cooldown.local[id];
|
||||
}
|
||||
}
|
||||
return QR.cooldown.save('local');
|
||||
},
|
||||
categorize: function(post) {
|
||||
if (post.thread === 'new') {
|
||||
return {
|
||||
type: 'thread'
|
||||
};
|
||||
} else {
|
||||
return $["delete"]("cooldown." + g.BOARD);
|
||||
return {
|
||||
type: !!post.file ? 'image' : 'reply',
|
||||
threadID: +post.thread
|
||||
};
|
||||
}
|
||||
},
|
||||
set: function(scope, id, value) {
|
||||
$.forceSync(QR.cooldown.keys[scope]);
|
||||
QR.cooldown[scope][id] = value;
|
||||
return $.set(QR.cooldown.keys[scope], QR.cooldown[scope]);
|
||||
},
|
||||
save: function(scope) {
|
||||
if (Object.keys(QR.cooldown[scope]).length) {
|
||||
return $.set(QR.cooldown.keys[scope], QR.cooldown[scope]);
|
||||
} else {
|
||||
return $["delete"](QR.cooldown.keys[scope]);
|
||||
}
|
||||
},
|
||||
count: function() {
|
||||
var cooldown, cooldowns, elapsed, hasFile, isReply, maxTimer, now, post, seconds, start, type, types, update, _ref;
|
||||
if (!Object.keys(QR.cooldown.cooldowns).length) {
|
||||
$["delete"]("cooldown." + g.BOARD);
|
||||
delete QR.cooldown.isCounting;
|
||||
delete QR.cooldown.seconds;
|
||||
QR.status();
|
||||
return;
|
||||
}
|
||||
clearTimeout(QR.cooldown.timeout);
|
||||
QR.cooldown.timeout = setTimeout(QR.cooldown.count, $.SECOND);
|
||||
var cooldown, elapsed, key, maxDelay, now, save, scope, seconds, start, suffix, threadID, type, update, _ref, _ref1, _ref2;
|
||||
now = Date.now();
|
||||
post = QR.posts[0];
|
||||
isReply = post.thread !== 'new';
|
||||
hasFile = !!post.file;
|
||||
seconds = null;
|
||||
_ref = QR.cooldown, types = _ref.types, cooldowns = _ref.cooldowns;
|
||||
for (start in cooldowns) {
|
||||
cooldown = cooldowns[start];
|
||||
start = +start;
|
||||
if ('delay' in cooldown) {
|
||||
if (cooldown.delay) {
|
||||
seconds = Math.max(seconds, cooldown.delay--);
|
||||
} else {
|
||||
seconds = Math.max(seconds, 0);
|
||||
QR.cooldown.unset(start);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (isReply === cooldown.isReply) {
|
||||
_ref = QR.cooldown.categorize(QR.posts[0]), type = _ref.type, threadID = _ref.threadID;
|
||||
seconds = 0;
|
||||
_ref1 = QR.cooldown.keys;
|
||||
for (scope in _ref1) {
|
||||
key = _ref1[scope];
|
||||
$.forceSync(key);
|
||||
save = false;
|
||||
_ref2 = QR.cooldown[scope];
|
||||
for (start in _ref2) {
|
||||
cooldown = _ref2[start];
|
||||
start = +start;
|
||||
elapsed = Math.floor((now - start) / $.SECOND);
|
||||
if (elapsed < 0) {
|
||||
QR.cooldown.unset(start);
|
||||
delete QR.cooldown[scope][start];
|
||||
save = true;
|
||||
continue;
|
||||
}
|
||||
type = !isReply ? 'thread' : hasFile ? 'image' : 'reply';
|
||||
maxTimer = Math.max(types[type] || 0, types[type + '_intra'] || 0);
|
||||
if (!((start <= now && now <= start + maxTimer * $.SECOND))) {
|
||||
QR.cooldown.unset(start);
|
||||
if (cooldown.delay != null) {
|
||||
if (cooldown.delay <= elapsed) {
|
||||
delete QR.cooldown[scope][start];
|
||||
save = true;
|
||||
} else if (cooldown.type === type && cooldown.threadID === threadID) {
|
||||
seconds = Math.max(seconds, cooldown.delay - elapsed);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (isReply && +post.thread === cooldown.threadID) {
|
||||
type += '_intra';
|
||||
maxDelay = cooldown.threadID !== cooldown.postID ? QR.cooldown.maxDelay : QR.cooldown.delays[scope === 'global' ? 'thread_global' : 'thread'];
|
||||
if (maxDelay <= elapsed) {
|
||||
delete QR.cooldown[scope][start];
|
||||
save = true;
|
||||
continue;
|
||||
}
|
||||
seconds = Math.max(seconds, types[type] - elapsed);
|
||||
if ((type === 'thread') === (cooldown.threadID === cooldown.postID)) {
|
||||
suffix = scope === 'global' ? '_global' : type !== 'thread' && threadID === cooldown.threadID ? '_intra' : '';
|
||||
seconds = Math.max(seconds, QR.cooldown.delays[type + suffix] - elapsed);
|
||||
}
|
||||
}
|
||||
if (save) {
|
||||
QR.cooldown.save(scope);
|
||||
}
|
||||
}
|
||||
update = seconds !== null || !!QR.cooldown.seconds;
|
||||
if (Object.keys(QR.cooldown.local).length + Object.keys(QR.cooldown.global).length) {
|
||||
clearTimeout(QR.cooldown.timeout);
|
||||
QR.cooldown.timeout = setTimeout(QR.cooldown.count, $.SECOND);
|
||||
} else {
|
||||
delete QR.cooldown.isCounting;
|
||||
}
|
||||
update = seconds !== QR.cooldown.seconds;
|
||||
QR.cooldown.seconds = seconds;
|
||||
if (update) {
|
||||
QR.status();
|
||||
@ -10187,6 +10242,7 @@
|
||||
$.on(link, 'click', DeleteLink["delete"]);
|
||||
} else {
|
||||
if (resDoc.title === 'Updating index...') {
|
||||
QR.cooldown["delete"](post);
|
||||
(post.origin || post).kill(fileOnly);
|
||||
}
|
||||
s = 'Deleted';
|
||||
@ -13405,7 +13461,7 @@
|
||||
className: 'dialog'
|
||||
});
|
||||
$.extend(dialog, {
|
||||
innerHTML: "<nav><div class=sections-list></div><p class='imp-exp-result warning'></p><div class=credits><a class=export>Export</a> | <a class=import>Import</a> | <a class=reset>Reset Settings</a> | <input type=file hidden><a href='https://github.com/ccd0/4chan-x' target=_blank>4chan X</a> | <a href='https://github.com/ccd0/4chan-x/blob/master/CHANGELOG.md' target=_blank>1.9.5.3</a> | <a href='https://github.com/ccd0/4chan-x/issues' target=_blank>Issues</a> | <a href=javascript:; class='close fa fa-times' title=Close></a></div></nav><div class=section-container><section></section></div>"
|
||||
innerHTML: "<nav><div class=sections-list></div><p class='imp-exp-result warning'></p><div class=credits><a class=export>Export</a> | <a class=import>Import</a> | <a class=reset>Reset Settings</a> | <input type=file hidden><a href='https://github.com/ccd0/4chan-x' target=_blank>4chan X</a> | <a href='https://github.com/ccd0/4chan-x/blob/master/CHANGELOG.md' target=_blank>1.9.6.0</a> | <a href='https://github.com/ccd0/4chan-x/issues' target=_blank>Issues</a> | <a href=javascript:; class='close fa fa-times' title=Close></a></div></nav><div class=section-container><section></section></div>"
|
||||
});
|
||||
$.on($('.export', Settings.dialog), 'click', Settings["export"]);
|
||||
$.on($('.import', Settings.dialog), 'click', Settings["import"]);
|
||||
|
||||
Binary file not shown.
@ -1,6 +1,6 @@
|
||||
// ==UserScript==
|
||||
// @name 4chan X
|
||||
// @version 1.9.5.3
|
||||
// @version 1.9.6.0
|
||||
// @minGMVer 1.14
|
||||
// @minFFVer 26
|
||||
// @namespace 4chan-X
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
// Generated by CoffeeScript
|
||||
// ==UserScript==
|
||||
// @name 4chan X
|
||||
// @version 1.9.5.3
|
||||
// @version 1.9.6.0
|
||||
// @minGMVer 1.14
|
||||
// @minFFVer 26
|
||||
// @namespace 4chan-X
|
||||
@ -24,7 +24,7 @@
|
||||
// ==/UserScript==
|
||||
|
||||
/*
|
||||
* 4chan X - Version 1.9.5.3
|
||||
* 4chan X - Version 1.9.6.0
|
||||
*
|
||||
* Licensed under the MIT license.
|
||||
* https://github.com/ccd0/4chan-x/blob/master/LICENSE
|
||||
@ -380,7 +380,7 @@
|
||||
doc = d.documentElement;
|
||||
|
||||
g = {
|
||||
VERSION: '1.9.5.3',
|
||||
VERSION: '1.9.6.0',
|
||||
NAMESPACE: '4chan X.',
|
||||
NAME: '4chan X',
|
||||
FAQ: 'https://github.com/ccd0/4chan-x/wiki/Frequently-Asked-Questions',
|
||||
@ -797,8 +797,13 @@
|
||||
var cb, key, newValue;
|
||||
key = _arg.key, newValue = _arg.newValue;
|
||||
if (cb = $.syncing[key]) {
|
||||
oldValue[key] = newValue;
|
||||
return cb(JSON.parse(newValue), key);
|
||||
if (newValue != null) {
|
||||
oldValue[key] = newValue;
|
||||
return cb(JSON.parse(newValue), key);
|
||||
} else {
|
||||
delete oldValue[key];
|
||||
return cb(void 0, key);
|
||||
}
|
||||
}
|
||||
};
|
||||
$.on(window, 'storage', onChange);
|
||||
@ -4659,7 +4664,7 @@
|
||||
Filter = {
|
||||
filters: {},
|
||||
init: function() {
|
||||
var boards, err, filter, hl, key, op, regexp, stub, top, _i, _len, _ref, _ref1, _ref2, _ref3, _ref4, _ref5;
|
||||
var boards, err, filter, hl, key, line, op, regexp, stub, top, _i, _len, _ref, _ref1, _ref2, _ref3, _ref4, _ref5;
|
||||
if (g.VIEW === 'catalog' || !Conf['Filter']) {
|
||||
return;
|
||||
}
|
||||
@ -4670,14 +4675,14 @@
|
||||
this.filters[key] = [];
|
||||
_ref = Conf[key].split('\n');
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
filter = _ref[_i];
|
||||
if (filter[0] === '#') {
|
||||
line = _ref[_i];
|
||||
if (line[0] === '#') {
|
||||
continue;
|
||||
}
|
||||
if (!(regexp = filter.match(/\/(.+)\/(\w*)/))) {
|
||||
if (!(regexp = line.match(/\/(.+)\/(\w*)/))) {
|
||||
continue;
|
||||
}
|
||||
filter = filter.replace(regexp[0], '');
|
||||
filter = line.replace(regexp[0], '');
|
||||
boards = ((_ref1 = filter.match(/boards:([^;]+)/)) != null ? _ref1[1].toLowerCase() : void 0) || 'global';
|
||||
if (boards !== 'global' && (_ref2 = g.BOARD.ID, __indexOf.call(boards.split(','), _ref2) < 0)) {
|
||||
continue;
|
||||
@ -4689,7 +4694,7 @@
|
||||
regexp = RegExp(regexp[1], regexp[2]);
|
||||
} catch (_error) {
|
||||
err = _error;
|
||||
new Notice('warning', err.message, 60);
|
||||
new Notice('warning', [$.tn("Invalid " + key + " filter:"), $.el('br'), $.tn(line), $.el('br'), $.tn(err.message)], 60);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -5288,16 +5293,64 @@
|
||||
|
||||
ThreadHiding = {
|
||||
init: function() {
|
||||
if (g.VIEW !== 'index' || !Conf['Thread Hiding Buttons'] && !Conf['Thread Hiding Link'] && !Conf['JSON Navigation']) {
|
||||
if (g.VIEW === 'thread' || !Conf['Thread Hiding Buttons'] && !Conf['Thread Hiding Link'] && !Conf['JSON Navigation']) {
|
||||
return;
|
||||
}
|
||||
this.db = new DataBoard('hiddenThreads');
|
||||
this.syncCatalog();
|
||||
if (g.VIEW === 'catalog') {
|
||||
return this.catalogWatch();
|
||||
}
|
||||
this.catalogSet(g.BOARD);
|
||||
return Thread.callbacks.push({
|
||||
name: 'Thread Hiding',
|
||||
cb: this.node
|
||||
});
|
||||
},
|
||||
catalogSet: function(board) {
|
||||
var hiddenThreads, threadID;
|
||||
hiddenThreads = ThreadHiding.db.get({
|
||||
boardID: board.ID,
|
||||
defaultValue: {}
|
||||
});
|
||||
for (threadID in hiddenThreads) {
|
||||
hiddenThreads[threadID] = true;
|
||||
}
|
||||
return localStorage.setItem("4chan-hide-t-" + board, JSON.stringify(hiddenThreads));
|
||||
},
|
||||
catalogWatch: function() {
|
||||
this.hiddenThreads = JSON.parse(localStorage.getItem("4chan-hide-t-" + g.BOARD)) || {};
|
||||
return $.ready(function() {
|
||||
return new MutationObserver(ThreadHiding.catalogSave).observe($.id('threads'), {
|
||||
attributes: true,
|
||||
subtree: true,
|
||||
attributeFilter: ['style']
|
||||
});
|
||||
});
|
||||
},
|
||||
catalogSave: function() {
|
||||
var hiddenThreads2, threadID;
|
||||
hiddenThreads2 = JSON.parse(localStorage.getItem("4chan-hide-t-" + g.BOARD)) || {};
|
||||
for (threadID in hiddenThreads2) {
|
||||
if (!(threadID in ThreadHiding.hiddenThreads)) {
|
||||
ThreadHiding.db.set({
|
||||
boardID: g.BOARD.ID,
|
||||
threadID: threadID,
|
||||
val: {
|
||||
makeStub: Conf['Stubs']
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
for (threadID in ThreadHiding.hiddenThreads) {
|
||||
if (!(threadID in hiddenThreads2)) {
|
||||
ThreadHiding.db["delete"]({
|
||||
boardID: g.BOARD.ID,
|
||||
threadID: threadID
|
||||
});
|
||||
}
|
||||
}
|
||||
return ThreadHiding.hiddenThreads = hiddenThreads2;
|
||||
},
|
||||
node: function() {
|
||||
var data;
|
||||
if (data = ThreadHiding.db.get({
|
||||
@ -5321,56 +5374,6 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
syncCatalog: function() {
|
||||
var hiddenThreads, hiddenThreadsOnCatalog, threadID;
|
||||
hiddenThreads = ThreadHiding.db.get({
|
||||
boardID: g.BOARD.ID,
|
||||
defaultValue: {}
|
||||
});
|
||||
hiddenThreadsOnCatalog = JSON.parse(localStorage.getItem("4chan-hide-t-" + g.BOARD)) || {};
|
||||
for (threadID in hiddenThreadsOnCatalog) {
|
||||
if (!(threadID in hiddenThreads)) {
|
||||
hiddenThreads[threadID] = {};
|
||||
}
|
||||
}
|
||||
for (threadID in hiddenThreads) {
|
||||
if (!(threadID in hiddenThreadsOnCatalog)) {
|
||||
delete hiddenThreads[threadID];
|
||||
}
|
||||
}
|
||||
if ((ThreadHiding.db.data.lastChecked || 0) > Date.now() - $.MINUTE) {
|
||||
ThreadHiding.cleanCatalog(hiddenThreadsOnCatalog);
|
||||
}
|
||||
return ThreadHiding.db.set({
|
||||
boardID: g.BOARD.ID,
|
||||
val: hiddenThreads
|
||||
});
|
||||
},
|
||||
cleanCatalog: function(hiddenThreadsOnCatalog) {
|
||||
return $.cache("//a.4cdn.org/" + g.BOARD + "/threads.json", function() {
|
||||
var page, thread, threads, _i, _j, _len, _len1, _ref, _ref1;
|
||||
if (this.status !== 200) {
|
||||
return;
|
||||
}
|
||||
threads = {};
|
||||
_ref = this.response;
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
page = _ref[_i];
|
||||
_ref1 = page.threads;
|
||||
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
||||
thread = _ref1[_j];
|
||||
if (thread.no in hiddenThreadsOnCatalog) {
|
||||
threads[thread.no] = hiddenThreadsOnCatalog[thread.no];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (Object.keys(threads).length) {
|
||||
return localStorage.setItem("4chan-hide-t-" + g.BOARD, JSON.stringify(threads));
|
||||
} else {
|
||||
return localStorage.removeItem("4chan-hide-t-" + g.BOARD);
|
||||
}
|
||||
});
|
||||
},
|
||||
menu: {
|
||||
init: function() {
|
||||
var apply, div, hideStubLink, makeStub;
|
||||
@ -5501,8 +5504,6 @@
|
||||
return $.prepend(root, thread.stub);
|
||||
},
|
||||
saveHiddenState: function(thread, makeStub) {
|
||||
var hiddenThreadsOnCatalog;
|
||||
hiddenThreadsOnCatalog = JSON.parse(localStorage.getItem("4chan-hide-t-" + g.BOARD)) || {};
|
||||
if (thread.isHidden) {
|
||||
ThreadHiding.db.set({
|
||||
boardID: thread.board.ID,
|
||||
@ -5511,15 +5512,13 @@
|
||||
makeStub: makeStub
|
||||
}
|
||||
});
|
||||
hiddenThreadsOnCatalog[thread] = true;
|
||||
} else {
|
||||
ThreadHiding.db["delete"]({
|
||||
boardID: thread.board.ID,
|
||||
threadID: thread.ID
|
||||
});
|
||||
delete hiddenThreadsOnCatalog[thread];
|
||||
}
|
||||
return localStorage.setItem("4chan-hide-t-" + g.BOARD, JSON.stringify(hiddenThreadsOnCatalog));
|
||||
return ThreadHiding.catalogSet(thread.board);
|
||||
},
|
||||
toggle: function(thread) {
|
||||
if (!(thread instanceof Thread)) {
|
||||
@ -7145,14 +7144,10 @@
|
||||
err = 'This CAPTCHA is no longer valid because it has expired.';
|
||||
}
|
||||
QR.cooldown.auto = QR.captcha.isEnabled ? !!QR.captcha.captchas.length : err === 'Connection error with sys.4chan.org.' ? true : false;
|
||||
QR.cooldown.set({
|
||||
delay: 2
|
||||
});
|
||||
} else if (err.textContent && (m = err.textContent.match(/wait\s+(\d+)\s+second/i))) {
|
||||
QR.cooldown.addDelay(post, 2);
|
||||
} else if (err.textContent && (m = err.textContent.match(/wait\s+(\d+)\s+second/i)) && !/duplicate/i.test(err.textContent)) {
|
||||
QR.cooldown.auto = QR.captcha.isEnabled ? !!QR.captcha.captchas.length : true;
|
||||
QR.cooldown.set({
|
||||
delay: m[1]
|
||||
});
|
||||
QR.cooldown.addDelay(post, +m[1]);
|
||||
} else {
|
||||
QR.cooldown.auto = false;
|
||||
}
|
||||
@ -7213,12 +7208,7 @@
|
||||
}
|
||||
post.rm();
|
||||
}
|
||||
QR.cooldown.set({
|
||||
req: req,
|
||||
post: post,
|
||||
isReply: isReply,
|
||||
threadID: threadID
|
||||
});
|
||||
QR.cooldown.add(req.uploadEndTime, threadID, postID);
|
||||
URL = threadID === postID ? "" + window.location.origin + "/" + g.BOARD + "/thread/" + threadID : g.VIEW === 'index' && !QR.cooldown.auto && Conf['Open Post in New Tab'] ? "" + window.location.origin + "/" + g.BOARD + "/thread/" + threadID + "#p" + postID : void 0;
|
||||
if (URL) {
|
||||
if (Conf['Open Post in New Tab']) {
|
||||
@ -7455,119 +7445,184 @@
|
||||
};
|
||||
|
||||
QR.cooldown = {
|
||||
seconds: 0,
|
||||
init: function() {
|
||||
var key, setTimers, type;
|
||||
var delay, items, key, keys, scope, setTimers, type, _ref, _results;
|
||||
if (!Conf['Cooldown']) {
|
||||
return;
|
||||
}
|
||||
setTimers = (function(_this) {
|
||||
return function(e) {
|
||||
return QR.cooldown.types = e.detail;
|
||||
return QR.cooldown.delays = e.detail;
|
||||
};
|
||||
})(this);
|
||||
$.on(window, 'cooldown:timers', setTimers);
|
||||
$.globalEval('window.dispatchEvent(new CustomEvent("cooldown:timers", {detail: cooldowns}))');
|
||||
$.off(window, 'cooldown:timers', setTimers);
|
||||
for (type in QR.cooldown.types) {
|
||||
QR.cooldown.types[type] = +QR.cooldown.types[type];
|
||||
QR.cooldown.maxDelay = 0;
|
||||
_ref = QR.cooldown.delays;
|
||||
for (type in _ref) {
|
||||
delay = _ref[type];
|
||||
if (type !== 'thread') {
|
||||
QR.cooldown.maxDelay = Math.max(QR.cooldown.maxDelay, delay);
|
||||
}
|
||||
}
|
||||
key = "cooldown." + g.BOARD;
|
||||
$.get(key, {}, function(item) {
|
||||
QR.cooldown.cooldowns = item[key];
|
||||
QR.cooldown.delays['thread_global'] = 300;
|
||||
keys = QR.cooldown.keys = {
|
||||
local: "cooldown." + g.BOARD,
|
||||
global: 'cooldown.global'
|
||||
};
|
||||
items = {};
|
||||
for (scope in keys) {
|
||||
key = keys[scope];
|
||||
items[key] = {};
|
||||
}
|
||||
$.get(items, function(items) {
|
||||
for (scope in keys) {
|
||||
key = keys[scope];
|
||||
QR.cooldown[scope] = items[key];
|
||||
}
|
||||
return QR.cooldown.start();
|
||||
});
|
||||
return $.sync(key, QR.cooldown.sync);
|
||||
_results = [];
|
||||
for (scope in keys) {
|
||||
key = keys[scope];
|
||||
_results.push($.sync(key, QR.cooldown.sync(scope)));
|
||||
}
|
||||
return _results;
|
||||
},
|
||||
start: function() {
|
||||
if (QR.cooldown.isCounting || !Object.keys(QR.cooldown.cooldowns).length) {
|
||||
if (QR.cooldown.isCounting || Object.keys(QR.cooldown.local).length + Object.keys(QR.cooldown.global).length === 0) {
|
||||
return;
|
||||
}
|
||||
QR.cooldown.isCounting = true;
|
||||
return QR.cooldown.count();
|
||||
},
|
||||
sync: function(cooldowns) {
|
||||
var id;
|
||||
for (id in cooldowns) {
|
||||
QR.cooldown.cooldowns[id] = cooldowns[id];
|
||||
}
|
||||
return QR.cooldown.start();
|
||||
sync: function(scope) {
|
||||
return function(cooldowns) {
|
||||
QR.cooldown[scope] = cooldowns || {};
|
||||
return QR.cooldown.start();
|
||||
};
|
||||
},
|
||||
set: function(data) {
|
||||
var cooldown, delay, isReply, post, req, start, threadID;
|
||||
add: function(start, threadID, postID) {
|
||||
var boardID;
|
||||
if (!Conf['Cooldown']) {
|
||||
return;
|
||||
}
|
||||
req = data.req, post = data.post, isReply = data.isReply, threadID = data.threadID, delay = data.delay;
|
||||
start = req ? req.uploadEndTime : Date.now();
|
||||
if (delay) {
|
||||
cooldown = {
|
||||
delay: delay
|
||||
};
|
||||
} else {
|
||||
cooldown = {
|
||||
isReply: isReply,
|
||||
threadID: threadID
|
||||
};
|
||||
boardID = g.BOARD.ID;
|
||||
QR.cooldown.set('local', start, {
|
||||
threadID: threadID,
|
||||
postID: postID
|
||||
});
|
||||
if (threadID === postID) {
|
||||
QR.cooldown.set('global', start, {
|
||||
boardID: boardID,
|
||||
threadID: threadID,
|
||||
postID: postID
|
||||
});
|
||||
}
|
||||
QR.cooldown.cooldowns[start] = cooldown;
|
||||
$.set("cooldown." + g.BOARD, QR.cooldown.cooldowns);
|
||||
return QR.cooldown.start();
|
||||
},
|
||||
unset: function(id) {
|
||||
delete QR.cooldown.cooldowns[id];
|
||||
if (Object.keys(QR.cooldown.cooldowns).length) {
|
||||
return $.set("cooldown." + g.BOARD, QR.cooldown.cooldowns);
|
||||
addDelay: function(post, delay) {
|
||||
var cooldown;
|
||||
if (!Conf['Cooldown']) {
|
||||
return;
|
||||
}
|
||||
cooldown = QR.cooldown.categorize(post);
|
||||
cooldown.delay = delay;
|
||||
QR.cooldown.set('local', Date.now(), cooldown);
|
||||
return QR.cooldown.start();
|
||||
},
|
||||
"delete": function(post) {
|
||||
var cooldown, id, _ref;
|
||||
if (!(Conf['Cooldown'] && g.BOARD.ID === post.board.ID)) {
|
||||
return;
|
||||
}
|
||||
$.forceSync(QR.cooldown.keys.local);
|
||||
_ref = QR.cooldown.local;
|
||||
for (id in _ref) {
|
||||
cooldown = _ref[id];
|
||||
if ((cooldown.delay == null) && cooldown.threadID === post.thread.ID && cooldown.postID === post.ID) {
|
||||
delete QR.cooldown.local[id];
|
||||
}
|
||||
}
|
||||
return QR.cooldown.save('local');
|
||||
},
|
||||
categorize: function(post) {
|
||||
if (post.thread === 'new') {
|
||||
return {
|
||||
type: 'thread'
|
||||
};
|
||||
} else {
|
||||
return $["delete"]("cooldown." + g.BOARD);
|
||||
return {
|
||||
type: !!post.file ? 'image' : 'reply',
|
||||
threadID: +post.thread
|
||||
};
|
||||
}
|
||||
},
|
||||
set: function(scope, id, value) {
|
||||
$.forceSync(QR.cooldown.keys[scope]);
|
||||
QR.cooldown[scope][id] = value;
|
||||
return $.set(QR.cooldown.keys[scope], QR.cooldown[scope]);
|
||||
},
|
||||
save: function(scope) {
|
||||
if (Object.keys(QR.cooldown[scope]).length) {
|
||||
return $.set(QR.cooldown.keys[scope], QR.cooldown[scope]);
|
||||
} else {
|
||||
return $["delete"](QR.cooldown.keys[scope]);
|
||||
}
|
||||
},
|
||||
count: function() {
|
||||
var cooldown, cooldowns, elapsed, hasFile, isReply, maxTimer, now, post, seconds, start, type, types, update, _ref;
|
||||
if (!Object.keys(QR.cooldown.cooldowns).length) {
|
||||
$["delete"]("cooldown." + g.BOARD);
|
||||
delete QR.cooldown.isCounting;
|
||||
delete QR.cooldown.seconds;
|
||||
QR.status();
|
||||
return;
|
||||
}
|
||||
clearTimeout(QR.cooldown.timeout);
|
||||
QR.cooldown.timeout = setTimeout(QR.cooldown.count, $.SECOND);
|
||||
var cooldown, elapsed, key, maxDelay, now, save, scope, seconds, start, suffix, threadID, type, update, _ref, _ref1, _ref2;
|
||||
now = Date.now();
|
||||
post = QR.posts[0];
|
||||
isReply = post.thread !== 'new';
|
||||
hasFile = !!post.file;
|
||||
seconds = null;
|
||||
_ref = QR.cooldown, types = _ref.types, cooldowns = _ref.cooldowns;
|
||||
for (start in cooldowns) {
|
||||
cooldown = cooldowns[start];
|
||||
start = +start;
|
||||
if ('delay' in cooldown) {
|
||||
if (cooldown.delay) {
|
||||
seconds = Math.max(seconds, cooldown.delay--);
|
||||
} else {
|
||||
seconds = Math.max(seconds, 0);
|
||||
QR.cooldown.unset(start);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (isReply === cooldown.isReply) {
|
||||
_ref = QR.cooldown.categorize(QR.posts[0]), type = _ref.type, threadID = _ref.threadID;
|
||||
seconds = 0;
|
||||
_ref1 = QR.cooldown.keys;
|
||||
for (scope in _ref1) {
|
||||
key = _ref1[scope];
|
||||
$.forceSync(key);
|
||||
save = false;
|
||||
_ref2 = QR.cooldown[scope];
|
||||
for (start in _ref2) {
|
||||
cooldown = _ref2[start];
|
||||
start = +start;
|
||||
elapsed = Math.floor((now - start) / $.SECOND);
|
||||
if (elapsed < 0) {
|
||||
QR.cooldown.unset(start);
|
||||
delete QR.cooldown[scope][start];
|
||||
save = true;
|
||||
continue;
|
||||
}
|
||||
type = !isReply ? 'thread' : hasFile ? 'image' : 'reply';
|
||||
maxTimer = Math.max(types[type] || 0, types[type + '_intra'] || 0);
|
||||
if (!((start <= now && now <= start + maxTimer * $.SECOND))) {
|
||||
QR.cooldown.unset(start);
|
||||
if (cooldown.delay != null) {
|
||||
if (cooldown.delay <= elapsed) {
|
||||
delete QR.cooldown[scope][start];
|
||||
save = true;
|
||||
} else if (cooldown.type === type && cooldown.threadID === threadID) {
|
||||
seconds = Math.max(seconds, cooldown.delay - elapsed);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (isReply && +post.thread === cooldown.threadID) {
|
||||
type += '_intra';
|
||||
maxDelay = cooldown.threadID !== cooldown.postID ? QR.cooldown.maxDelay : QR.cooldown.delays[scope === 'global' ? 'thread_global' : 'thread'];
|
||||
if (maxDelay <= elapsed) {
|
||||
delete QR.cooldown[scope][start];
|
||||
save = true;
|
||||
continue;
|
||||
}
|
||||
seconds = Math.max(seconds, types[type] - elapsed);
|
||||
if ((type === 'thread') === (cooldown.threadID === cooldown.postID)) {
|
||||
suffix = scope === 'global' ? '_global' : type !== 'thread' && threadID === cooldown.threadID ? '_intra' : '';
|
||||
seconds = Math.max(seconds, QR.cooldown.delays[type + suffix] - elapsed);
|
||||
}
|
||||
}
|
||||
if (save) {
|
||||
QR.cooldown.save(scope);
|
||||
}
|
||||
}
|
||||
update = seconds !== null || !!QR.cooldown.seconds;
|
||||
if (Object.keys(QR.cooldown.local).length + Object.keys(QR.cooldown.global).length) {
|
||||
clearTimeout(QR.cooldown.timeout);
|
||||
QR.cooldown.timeout = setTimeout(QR.cooldown.count, $.SECOND);
|
||||
} else {
|
||||
delete QR.cooldown.isCounting;
|
||||
}
|
||||
update = seconds !== QR.cooldown.seconds;
|
||||
QR.cooldown.seconds = seconds;
|
||||
if (update) {
|
||||
QR.status();
|
||||
@ -10188,6 +10243,7 @@
|
||||
$.on(link, 'click', DeleteLink["delete"]);
|
||||
} else {
|
||||
if (resDoc.title === 'Updating index...') {
|
||||
QR.cooldown["delete"](post);
|
||||
(post.origin || post).kill(fileOnly);
|
||||
}
|
||||
s = 'Deleted';
|
||||
@ -13406,7 +13462,7 @@
|
||||
className: 'dialog'
|
||||
});
|
||||
$.extend(dialog, {
|
||||
innerHTML: "<nav><div class=sections-list></div><p class='imp-exp-result warning'></p><div class=credits><a class=export>Export</a> | <a class=import>Import</a> | <a class=reset>Reset Settings</a> | <input type=file hidden><a href='https://github.com/ccd0/4chan-x' target=_blank>4chan X</a> | <a href='https://github.com/ccd0/4chan-x/blob/master/CHANGELOG.md' target=_blank>1.9.5.3</a> | <a href='https://github.com/ccd0/4chan-x/issues' target=_blank>Issues</a> | <a href=javascript:; class='close fa fa-times' title=Close></a></div></nav><div class=section-container><section></section></div>"
|
||||
innerHTML: "<nav><div class=sections-list></div><p class='imp-exp-result warning'></p><div class=credits><a class=export>Export</a> | <a class=import>Import</a> | <a class=reset>Reset Settings</a> | <input type=file hidden><a href='https://github.com/ccd0/4chan-x' target=_blank>4chan X</a> | <a href='https://github.com/ccd0/4chan-x/blob/master/CHANGELOG.md' target=_blank>1.9.6.0</a> | <a href='https://github.com/ccd0/4chan-x/issues' target=_blank>Issues</a> | <a href=javascript:; class='close fa fa-times' title=Close></a></div></nav><div class=section-container><section></section></div>"
|
||||
});
|
||||
$.on($('.export', Settings.dialog), 'click', Settings["export"]);
|
||||
$.on($('.import', Settings.dialog), 'click', Settings["import"]);
|
||||
|
||||
Binary file not shown.
@ -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.9.5.3' />
|
||||
<updatecheck codebase='https://ccd0.github.io/4chan-x/builds/4chan-X-beta.crx' version='1.9.6.0' />
|
||||
</app>
|
||||
</gupdate>
|
||||
|
||||
|
||||
@ -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.9.5.3' />
|
||||
<updatecheck codebase='https://ccd0.github.io/4chan-x/builds/4chan-X.crx' version='1.9.6.0' />
|
||||
</app>
|
||||
</gupdate>
|
||||
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
"description": "Cross-browser userscript for maximum lurking on 4chan.",
|
||||
"meta": {
|
||||
"name": "4chan X",
|
||||
"version": "1.9.5.3",
|
||||
"version": "1.9.6.0",
|
||||
"repo": "https://github.com/ccd0/4chan-x/",
|
||||
"page": "https://github.com/ccd0/4chan-x",
|
||||
"downloads": "https://ccd0.github.io/4chan-x/builds/",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user