The rest of the QR
This commit is contained in:
parent
13563ffcda
commit
e4dde07c11
@ -10053,119 +10053,183 @@
|
||||
};
|
||||
|
||||
QR.cooldown = {
|
||||
seconds: 0,
|
||||
init: function() {
|
||||
var key, setTimers, type;
|
||||
var delay, items, key, keys, m, scope, type, _ref, _results;
|
||||
if (!Conf['Cooldown']) {
|
||||
return;
|
||||
}
|
||||
setTimers = (function(_this) {
|
||||
return function(e) {
|
||||
return QR.cooldown.types = 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.delays = (m = Get.scriptData().match(/\bcooldowns *= *({[^}]+})/)) ? JSON.parse(m[1]) : {
|
||||
thread: 0,
|
||||
reply: 0,
|
||||
image: 0,
|
||||
reply_intra: 0,
|
||||
image_intra: 0
|
||||
};
|
||||
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();
|
||||
@ -10244,9 +10308,9 @@
|
||||
}
|
||||
},
|
||||
getPassword: function() {
|
||||
var input, m;
|
||||
var input, m, _ref;
|
||||
if (!QR.persona.pwd) {
|
||||
QR.persona.pwd = (m = d.cookie.match(/4chan_pass=([^;]+)/)) ? decodeURIComponent(m[1]) : (input = $.id('postPassword')) ? input.value : $.id('delPassword').value;
|
||||
QR.persona.pwd = (m = d.cookie.match(/4chan_pass=([^;]+)/)) ? decodeURIComponent(m[1]) : (input = $.id('postPassword')) ? input.value : ((_ref = $.id('delPassword')) != null ? _ref.value : void 0) || '';
|
||||
}
|
||||
return QR.persona.pwd;
|
||||
},
|
||||
@ -10264,7 +10328,6 @@
|
||||
persona = {
|
||||
name: post.name,
|
||||
email: /^sage$/.test(post.email) ? persona.email : post.email,
|
||||
sub: Conf['Remember Subject'] ? post.sub : void 0,
|
||||
flag: post.flag
|
||||
};
|
||||
return $.set('QR.persona', persona);
|
||||
@ -10275,12 +10338,14 @@
|
||||
QR.post = (function() {
|
||||
function _Class(select) {
|
||||
this.select = __bind(this.select, this);
|
||||
var el, elm, event, prev, _i, _j, _len, _len1, _ref, _ref1;
|
||||
var el, event, prev, _i, _len, _ref;
|
||||
el = $.el('a', {
|
||||
className: 'qr-preview',
|
||||
draggable: true,
|
||||
href: 'javascript:;',
|
||||
innerHTML: '<a class="remove fa" title=Remove>\uf057</a><label hidden><input type=checkbox> Spoiler</label><span></span>'
|
||||
href: 'javascript:;'
|
||||
});
|
||||
$.extend(el, {
|
||||
innerHTML: "<a class=\"remove fa\" title=\"Remove\"></a><label hidden><input type=\"checkbox\"> Spoiler</label><span></span>"
|
||||
});
|
||||
this.nodes = {
|
||||
el: el,
|
||||
@ -10289,12 +10354,6 @@
|
||||
spoiler: $('input', el),
|
||||
span: el.lastChild
|
||||
};
|
||||
_ref = $$('*', el);
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
elm = _ref[_i];
|
||||
$.on(elm, 'blur', QR.focusout);
|
||||
$.on(elm, 'focus', QR.focusin);
|
||||
}
|
||||
$.on(el, 'click', this.select);
|
||||
$.on(this.nodes.rm, 'click', (function(_this) {
|
||||
return function(e) {
|
||||
@ -10316,9 +10375,9 @@
|
||||
};
|
||||
})(this));
|
||||
$.add(QR.nodes.dumpList, el);
|
||||
_ref1 = ['dragStart', 'dragEnter', 'dragLeave', 'dragOver', 'dragEnd', 'drop'];
|
||||
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
|
||||
event = _ref1[_j];
|
||||
_ref = ['dragStart', 'dragEnter', 'dragLeave', 'dragOver', 'dragEnd', 'drop'];
|
||||
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
|
||||
event = _ref[_i];
|
||||
$.on(el, event.toLowerCase(), this[event]);
|
||||
}
|
||||
this.thread = g.VIEW === 'thread' ? g.THREADID : 'new';
|
||||
@ -10343,7 +10402,7 @@
|
||||
}
|
||||
this.unlock();
|
||||
$.queueTask(function() {
|
||||
return QR.captcha.setup();
|
||||
return QR.captcha.onNewPost();
|
||||
});
|
||||
}
|
||||
|
||||
@ -10418,6 +10477,7 @@
|
||||
node.value = this[name] || node.dataset["default"] || null;
|
||||
}
|
||||
QR.tripcodeHider.call(QR.nodes['name']);
|
||||
(this.thread !== 'new' ? $.addClass : $.rmClass)(QR.nodes.el, 'reply-to-thread');
|
||||
this.showFileData();
|
||||
return QR.characterCount();
|
||||
};
|
||||
@ -10432,6 +10492,7 @@
|
||||
this[name] = input.value || input.dataset["default"] || null;
|
||||
switch (name) {
|
||||
case 'thread':
|
||||
(this.thread !== 'new' ? $.addClass : $.rmClass)(QR.nodes.el, 'reply-to-thread');
|
||||
return QR.status();
|
||||
case 'com':
|
||||
this.nodes.span.textContent = this.com;
|
||||
@ -10598,13 +10659,13 @@
|
||||
};
|
||||
|
||||
_Class.prototype.updateFilename = function() {
|
||||
var title;
|
||||
title = "" + this.filename + " (" + this.filesize + ")\nCtrl/\u2318+click to edit filename. Shift+click to clear.";
|
||||
this.nodes.el.title = title;
|
||||
var long;
|
||||
long = "" + this.filename + " (" + this.filesize + ")\nCtrl/\u2318+click to edit filename. Shift+click to clear.";
|
||||
this.nodes.el.title = long;
|
||||
if (this !== QR.selected) {
|
||||
return;
|
||||
}
|
||||
return QR.nodes.fileContainer.title = title;
|
||||
return QR.nodes.fileContainer.title = long;
|
||||
};
|
||||
|
||||
_Class.prototype.showFileData = function() {
|
||||
|
||||
@ -10096,119 +10096,183 @@
|
||||
};
|
||||
|
||||
QR.cooldown = {
|
||||
seconds: 0,
|
||||
init: function() {
|
||||
var key, setTimers, type;
|
||||
var delay, items, key, keys, m, scope, type, _ref, _results;
|
||||
if (!Conf['Cooldown']) {
|
||||
return;
|
||||
}
|
||||
setTimers = (function(_this) {
|
||||
return function(e) {
|
||||
return QR.cooldown.types = 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.delays = (m = Get.scriptData().match(/\bcooldowns *= *({[^}]+})/)) ? JSON.parse(m[1]) : {
|
||||
thread: 0,
|
||||
reply: 0,
|
||||
image: 0,
|
||||
reply_intra: 0,
|
||||
image_intra: 0
|
||||
};
|
||||
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();
|
||||
@ -10287,9 +10351,9 @@
|
||||
}
|
||||
},
|
||||
getPassword: function() {
|
||||
var input, m;
|
||||
var input, m, _ref;
|
||||
if (!QR.persona.pwd) {
|
||||
QR.persona.pwd = (m = d.cookie.match(/4chan_pass=([^;]+)/)) ? decodeURIComponent(m[1]) : (input = $.id('postPassword')) ? input.value : $.id('delPassword').value;
|
||||
QR.persona.pwd = (m = d.cookie.match(/4chan_pass=([^;]+)/)) ? decodeURIComponent(m[1]) : (input = $.id('postPassword')) ? input.value : ((_ref = $.id('delPassword')) != null ? _ref.value : void 0) || '';
|
||||
}
|
||||
return QR.persona.pwd;
|
||||
},
|
||||
@ -10307,7 +10371,6 @@
|
||||
persona = {
|
||||
name: post.name,
|
||||
email: /^sage$/.test(post.email) ? persona.email : post.email,
|
||||
sub: Conf['Remember Subject'] ? post.sub : void 0,
|
||||
flag: post.flag
|
||||
};
|
||||
return $.set('QR.persona', persona);
|
||||
@ -10322,8 +10385,10 @@
|
||||
el = $.el('a', {
|
||||
className: 'qr-preview',
|
||||
draggable: true,
|
||||
href: 'javascript:;',
|
||||
innerHTML: '<a class="remove fa" title=Remove>\uf057</a><label hidden><input type=checkbox> Spoiler</label><span></span>'
|
||||
href: 'javascript:;'
|
||||
});
|
||||
$.extend(el, {
|
||||
innerHTML: "<a class=\"remove fa\" title=\"Remove\"></a><label hidden><input type=\"checkbox\"> Spoiler</label><span></span>"
|
||||
});
|
||||
this.nodes = {
|
||||
el: el,
|
||||
@ -10380,7 +10445,7 @@
|
||||
}
|
||||
this.unlock();
|
||||
$.queueTask(function() {
|
||||
return QR.captcha.setup();
|
||||
return QR.captcha.onNewPost();
|
||||
});
|
||||
}
|
||||
|
||||
@ -10455,6 +10520,7 @@
|
||||
node.value = this[name] || node.dataset["default"] || null;
|
||||
}
|
||||
QR.tripcodeHider.call(QR.nodes['name']);
|
||||
(this.thread !== 'new' ? $.addClass : $.rmClass)(QR.nodes.el, 'reply-to-thread');
|
||||
this.showFileData();
|
||||
return QR.characterCount();
|
||||
};
|
||||
@ -10469,6 +10535,7 @@
|
||||
this[name] = input.value || input.dataset["default"] || null;
|
||||
switch (name) {
|
||||
case 'thread':
|
||||
(this.thread !== 'new' ? $.addClass : $.rmClass)(QR.nodes.el, 'reply-to-thread');
|
||||
return QR.status();
|
||||
case 'com':
|
||||
this.nodes.span.textContent = this.com;
|
||||
@ -10632,13 +10699,13 @@
|
||||
};
|
||||
|
||||
_Class.prototype.updateFilename = function() {
|
||||
var title;
|
||||
title = "" + this.filename + " (" + this.filesize + ")\nCtrl/\u2318+click to edit filename. Shift+click to clear.";
|
||||
this.nodes.el.title = title;
|
||||
var long;
|
||||
long = "" + this.filename + " (" + this.filesize + ")\nCtrl/\u2318+click to edit filename. Shift+click to clear.";
|
||||
this.nodes.el.title = long;
|
||||
if (this !== QR.selected) {
|
||||
return;
|
||||
}
|
||||
return QR.nodes.fileContainer.title = title;
|
||||
return QR.nodes.fileContainer.title = long;
|
||||
};
|
||||
|
||||
_Class.prototype.showFileData = function() {
|
||||
|
||||
@ -1,99 +1,143 @@
|
||||
QR.cooldown =
|
||||
seconds: 0
|
||||
|
||||
init: ->
|
||||
return unless Conf['Cooldown']
|
||||
setTimers = (e) => QR.cooldown.types = e.detail
|
||||
$.on window, 'cooldown:timers', setTimers
|
||||
$.globalEval 'window.dispatchEvent(new CustomEvent("cooldown:timers", {detail: cooldowns}))'
|
||||
$.off window, 'cooldown:timers', setTimers
|
||||
for type of QR.cooldown.types
|
||||
QR.cooldown.types[type] = +QR.cooldown.types[type]
|
||||
key = "cooldown.#{g.BOARD}"
|
||||
$.get key, {}, (item) ->
|
||||
QR.cooldown.cooldowns = item[key]
|
||||
|
||||
# Read cooldown times
|
||||
QR.cooldown.delays = if m = Get.scriptData().match /\bcooldowns *= *({[^}]+})/
|
||||
JSON.parse m[1]
|
||||
else
|
||||
{thread: 0, reply: 0, image: 0, reply_intra: 0, image_intra: 0}
|
||||
|
||||
# The longest reply cooldown, for use in pruning old reply data
|
||||
QR.cooldown.maxDelay = 0
|
||||
for type, delay of QR.cooldown.delays when type isnt 'thread'
|
||||
QR.cooldown.maxDelay = Math.max QR.cooldown.maxDelay, delay
|
||||
|
||||
# There is a 300 second global thread cooldown.
|
||||
QR.cooldown.delays['thread_global'] = 300
|
||||
|
||||
# Retrieve recent posts and delays.
|
||||
keys = QR.cooldown.keys =
|
||||
local: "cooldown.#{g.BOARD}"
|
||||
global: 'cooldown.global'
|
||||
items = {}
|
||||
items[key] = {} for scope, key of keys
|
||||
$.get items, (items) ->
|
||||
QR.cooldown[scope] = items[key] for scope, key of keys
|
||||
QR.cooldown.start()
|
||||
$.sync key, QR.cooldown.sync
|
||||
$.sync key, QR.cooldown.sync scope for scope, key of keys
|
||||
|
||||
start: ->
|
||||
return if QR.cooldown.isCounting or !Object.keys(QR.cooldown.cooldowns).length
|
||||
return if QR.cooldown.isCounting or Object.keys(QR.cooldown.local).length + Object.keys(QR.cooldown.global).length is 0
|
||||
QR.cooldown.isCounting = true
|
||||
QR.cooldown.count()
|
||||
|
||||
sync: (cooldowns) ->
|
||||
# Add each cooldowns, don't overwrite everything in case we
|
||||
# still need to prune one in the current tab to auto-post.
|
||||
for id of cooldowns
|
||||
QR.cooldown.cooldowns[id] = cooldowns[id]
|
||||
sync: (scope) -> (cooldowns) ->
|
||||
QR.cooldown[scope] = cooldowns or {}
|
||||
QR.cooldown.start()
|
||||
|
||||
set: (data) ->
|
||||
add: (start, threadID, postID) ->
|
||||
return unless Conf['Cooldown']
|
||||
{req, post, isReply, threadID, delay} = data
|
||||
start = if req then req.uploadEndTime else Date.now()
|
||||
if delay
|
||||
cooldown = {delay}
|
||||
else
|
||||
cooldown = {isReply, threadID}
|
||||
QR.cooldown.cooldowns[start] = cooldown
|
||||
$.set "cooldown.#{g.BOARD}", QR.cooldown.cooldowns
|
||||
boardID = g.BOARD.ID
|
||||
QR.cooldown.set 'local', start, {threadID, postID}
|
||||
QR.cooldown.set 'global', start, {boardID, threadID, postID} if threadID is postID
|
||||
QR.cooldown.start()
|
||||
|
||||
unset: (id) ->
|
||||
delete QR.cooldown.cooldowns[id]
|
||||
if Object.keys(QR.cooldown.cooldowns).length
|
||||
$.set "cooldown.#{g.BOARD}", QR.cooldown.cooldowns
|
||||
addDelay: (post, delay) ->
|
||||
return unless Conf['Cooldown']
|
||||
cooldown = QR.cooldown.categorize post
|
||||
cooldown.delay = delay
|
||||
QR.cooldown.set 'local', Date.now(), cooldown
|
||||
QR.cooldown.start()
|
||||
|
||||
delete: (post) ->
|
||||
return unless Conf['Cooldown'] and g.BOARD.ID is post.board.ID
|
||||
$.forceSync QR.cooldown.keys.local
|
||||
for id, cooldown of QR.cooldown.local
|
||||
if !cooldown.delay? and cooldown.threadID is post.thread.ID and cooldown.postID is post.ID
|
||||
delete QR.cooldown.local[id]
|
||||
QR.cooldown.save 'local'
|
||||
|
||||
categorize: (post) ->
|
||||
if post.thread is 'new'
|
||||
type: 'thread'
|
||||
else
|
||||
$.delete "cooldown.#{g.BOARD}"
|
||||
type: if !!post.file then 'image' else 'reply'
|
||||
threadID: +post.thread
|
||||
|
||||
set: (scope, id, value) ->
|
||||
$.forceSync QR.cooldown.keys[scope]
|
||||
QR.cooldown[scope][id] = value
|
||||
$.set QR.cooldown.keys[scope], QR.cooldown[scope]
|
||||
|
||||
save: (scope) ->
|
||||
if Object.keys(QR.cooldown[scope]).length
|
||||
$.set QR.cooldown.keys[scope], QR.cooldown[scope]
|
||||
else
|
||||
$.delete QR.cooldown.keys[scope]
|
||||
|
||||
count: ->
|
||||
unless Object.keys(QR.cooldown.cooldowns).length
|
||||
$.delete "cooldown.#{g.BOARD}"
|
||||
delete QR.cooldown.isCounting
|
||||
delete QR.cooldown.seconds
|
||||
QR.status()
|
||||
return
|
||||
now = Date.now()
|
||||
{type, threadID} = QR.cooldown.categorize QR.posts[0]
|
||||
seconds = 0
|
||||
|
||||
clearTimeout QR.cooldown.timeout
|
||||
QR.cooldown.timeout = setTimeout QR.cooldown.count, $.SECOND
|
||||
for scope, key of QR.cooldown.keys
|
||||
$.forceSync key
|
||||
save = false
|
||||
|
||||
now = Date.now()
|
||||
post = QR.posts[0]
|
||||
isReply = post.thread isnt 'new'
|
||||
hasFile = !!post.file
|
||||
seconds = null
|
||||
{types, cooldowns} = QR.cooldown
|
||||
|
||||
for start, cooldown of cooldowns
|
||||
start = +start
|
||||
if 'delay' of cooldown
|
||||
if cooldown.delay
|
||||
seconds = Math.max seconds, cooldown.delay--
|
||||
else
|
||||
seconds = Math.max seconds, 0
|
||||
QR.cooldown.unset start
|
||||
continue
|
||||
|
||||
if isReply is cooldown.isReply
|
||||
# Only cooldowns relevant to this post can set the seconds variable:
|
||||
# reply cooldown with a reply, thread cooldown with a thread
|
||||
for start, cooldown of QR.cooldown[scope]
|
||||
start = +start
|
||||
elapsed = (now - start) // $.SECOND
|
||||
if elapsed < 0 # clock changed since then?
|
||||
QR.cooldown.unset start
|
||||
delete QR.cooldown[scope][start]
|
||||
save = true
|
||||
continue
|
||||
type = unless isReply
|
||||
'thread'
|
||||
else if hasFile
|
||||
'image'
|
||||
|
||||
# Explicit delays from error messages
|
||||
if cooldown.delay?
|
||||
if cooldown.delay <= elapsed
|
||||
delete QR.cooldown[scope][start]
|
||||
save = true
|
||||
else if cooldown.type is type and cooldown.threadID is threadID
|
||||
# Delays only apply to the given post type and thread.
|
||||
seconds = Math.max seconds, cooldown.delay - elapsed
|
||||
continue
|
||||
|
||||
# Clean up expired cooldowns
|
||||
maxDelay = if cooldown.threadID isnt cooldown.postID
|
||||
QR.cooldown.maxDelay
|
||||
else
|
||||
'reply'
|
||||
maxTimer = Math.max types[type] or 0, types[type + '_intra'] or 0
|
||||
unless start <= now <= start + maxTimer * $.SECOND
|
||||
QR.cooldown.unset start
|
||||
type += '_intra' if isReply and +post.thread is cooldown.threadID
|
||||
seconds = Math.max seconds, types[type] - elapsed
|
||||
QR.cooldown.delays[if scope is 'global' then 'thread_global' else 'thread']
|
||||
if maxDelay <= elapsed
|
||||
delete QR.cooldown[scope][start]
|
||||
save = true
|
||||
continue
|
||||
|
||||
if (type is 'thread') is (cooldown.threadID is cooldown.postID)
|
||||
# Only cooldowns relevant to this post can set the seconds variable:
|
||||
# reply cooldown with a reply, thread cooldown with a thread
|
||||
suffix = if scope is 'global'
|
||||
'_global'
|
||||
else if type isnt 'thread' and threadID is cooldown.threadID
|
||||
'_intra'
|
||||
else
|
||||
''
|
||||
seconds = Math.max seconds, QR.cooldown.delays[type + suffix] - elapsed
|
||||
|
||||
QR.cooldown.save scope if save
|
||||
|
||||
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 the status when we change posting type.
|
||||
# Don't get stuck at some random number.
|
||||
# Don't interfere with progress status updates.
|
||||
update = seconds isnt null or !!QR.cooldown.seconds
|
||||
update = seconds isnt QR.cooldown.seconds
|
||||
QR.cooldown.seconds = seconds
|
||||
QR.status() if update
|
||||
QR.submit() if seconds is 0 and QR.cooldown.auto and !QR.req
|
||||
|
||||
@ -56,7 +56,7 @@ QR.persona =
|
||||
# If we're in a closed thread, #postPassword isn't available.
|
||||
# And since #delPassword.value is only filled on window.onload
|
||||
# we'd rather use #postPassword when we can.
|
||||
$.id('delPassword').value
|
||||
$.id('delPassword')?.value or ''
|
||||
return QR.persona.pwd
|
||||
|
||||
get: (cb) ->
|
||||
@ -68,6 +68,5 @@ QR.persona =
|
||||
persona =
|
||||
name: post.name
|
||||
email: if /^sage$/.test post.email then persona.email else post.email
|
||||
sub: if Conf['Remember Subject'] then post.sub else undefined
|
||||
flag: post.flag
|
||||
$.set 'QR.persona', persona
|
||||
|
||||
@ -4,7 +4,7 @@ QR.post = class
|
||||
className: 'qr-preview'
|
||||
draggable: true
|
||||
href: 'javascript:;'
|
||||
innerHTML: '<a class="remove fa" title=Remove>\uf057</a><label hidden><input type=checkbox> Spoiler</label><span></span>'
|
||||
$.extend el, <%= html('<a class="remove fa" title="Remove">\uf057</a><label hidden><input type="checkbox"> Spoiler</label><span></span>') %>
|
||||
|
||||
@nodes =
|
||||
el: el
|
||||
@ -13,12 +13,6 @@ QR.post = class
|
||||
spoiler: $ 'input', el
|
||||
span: el.lastChild
|
||||
|
||||
<% if (type === 'userscript') { %>
|
||||
# XXX Firefox lacks focusin/focusout support.
|
||||
for elm in $$ '*', el
|
||||
$.on elm, 'blur', QR.focusout
|
||||
$.on elm, 'focus', QR.focusin
|
||||
<% } %>
|
||||
$.on el, 'click', @select
|
||||
$.on @nodes.rm, 'click', (e) => e.stopPropagation(); @rm()
|
||||
$.on @nodes.label, 'click', (e) => e.stopPropagation()
|
||||
@ -72,7 +66,7 @@ QR.post = class
|
||||
@select() if select
|
||||
@unlock()
|
||||
# Post count temporarily off by 1 when called from QR.post.rm
|
||||
$.queueTask -> QR.captcha.setup()
|
||||
$.queueTask -> QR.captcha.onNewPost()
|
||||
|
||||
rm: ->
|
||||
@delete()
|
||||
@ -123,6 +117,9 @@ QR.post = class
|
||||
node.value = @[name] or node.dataset.default or null
|
||||
|
||||
QR.tripcodeHider.call QR.nodes['name']
|
||||
|
||||
(if @thread isnt 'new' then $.addClass else $.rmClass) QR.nodes.el, 'reply-to-thread'
|
||||
|
||||
@showFileData()
|
||||
QR.characterCount()
|
||||
|
||||
@ -134,6 +131,7 @@ QR.post = class
|
||||
@[name] = input.value or input.dataset.default or null
|
||||
switch name
|
||||
when 'thread'
|
||||
(if @thread isnt 'new' then $.addClass else $.rmClass) QR.nodes.el, 'reply-to-thread'
|
||||
QR.status()
|
||||
when 'com'
|
||||
@nodes.span.textContent = @com
|
||||
@ -271,10 +269,10 @@ QR.post = class
|
||||
URL.revokeObjectURL @URL
|
||||
|
||||
updateFilename: ->
|
||||
title = "#{@filename} (#{@filesize})\nCtrl/\u2318+click to edit filename. Shift+click to clear."
|
||||
@nodes.el.title = title
|
||||
long = "#{@filename} (#{@filesize})\nCtrl/\u2318+click to edit filename. Shift+click to clear."
|
||||
@nodes.el.title = long
|
||||
return unless @ is QR.selected
|
||||
QR.nodes.fileContainer.title = title
|
||||
QR.nodes.fileContainer.title = long
|
||||
|
||||
showFileData: ->
|
||||
if @file
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user