Thread creation cooldown. Fix cooldown between different post-type. Fix /q/ cooldowns?

Ugh. see #774
This commit is contained in:
Nicolas Stepien 2012-10-01 17:33:05 +02:00
parent f411eb3e99
commit 027836b78f
3 changed files with 225 additions and 83 deletions

View File

@ -1738,7 +1738,7 @@
$.on(link.firstChild, 'click', function() { $.on(link.firstChild, 'click', function() {
QR.open(); QR.open();
if (!g.REPLY) { if (!g.REPLY) {
$('select', QR.el).value = 'new'; QR.threadSelector.value = 'new';
} }
return $('textarea', QR.el).focus(); return $('textarea', QR.el).focus();
}); });
@ -1836,44 +1836,118 @@
}, },
cooldown: { cooldown: {
init: function() { init: function() {
var length, timeout, _ref;
if (!Conf['Cooldown']) { if (!Conf['Cooldown']) {
return; return;
} }
_ref = $.get("/" + g.BOARD + "/cooldown", {}), timeout = _ref.timeout, length = _ref.length; QR.cooldown.types = {
if (timeout) { thread: (function() {
QR.cooldown.start(timeout, length); switch (g.BOARD) {
case 'q':
return 86400;
case 'b':
case 'soc':
case 'r9k':
return 600;
default:
return 300;
} }
return $.sync("/" + g.BOARD + "/cooldown", QR.cooldown.start); })(),
sage: g.BOARD === 'q' ? 600 : 60,
file: g.BOARD === 'q' ? 300 : 30,
post: g.BOARD === 'q' ? 60 : 30
};
QR.cooldown.cooldowns = $.get("" + g.BOARD + ".cooldown", {});
QR.cooldown.start();
return $.sync("" + g.BOARD + ".cooldown", QR.cooldown.sync);
}, },
start: function(timeout, length) { start: function() {
var seconds; if (QR.cooldown.isCounting) {
seconds = Math.floor((timeout - Date.now()) / 1000); return;
return QR.cooldown.count(seconds, length); }
QR.cooldown.isCounting = true;
return QR.cooldown.count();
}, },
set: function(seconds) { sync: function(cooldowns) {
QR.cooldown.cooldowns = cooldowns;
return QR.cooldown.start();
},
set: function(data) {
var cooldown, hasFile, isReply, isSage, start, type;
if (!Conf['Cooldown']) { if (!Conf['Cooldown']) {
return; return;
} }
QR.cooldown.count(seconds, seconds); start = Date.now();
return $.set("/" + g.BOARD + "/cooldown", { if (data.delay) {
timeout: Date.now() + seconds * $.SECOND, cooldown = {
length: seconds delay: data.delay
}); };
} else {
isSage = /sage/i.test(data.post.email);
hasFile = !!data.post.file;
isReply = data.isReply;
type = !isReply ? 'thread' : isSage ? 'sage' : hasFile ? 'file' : 'post';
cooldown = {
isReply: isReply,
isSage: isSage,
hasFile: hasFile,
timeout: start + QR.cooldown.types[type] * $.SECOND
};
}
QR.cooldown.cooldowns[start] = cooldown;
$.set("" + g.BOARD + ".cooldown", QR.cooldown.cooldowns);
return QR.cooldown.start();
}, },
count: function(seconds, length) { unset: function(id) {
if (!((0 <= seconds && seconds <= length))) { delete QR.cooldown.cooldowns[id];
return $.set("" + g.BOARD + ".cooldown", QR.cooldown.cooldowns);
},
count: function() {
var cooldown, cooldowns, elapsed, hasFile, isReply, isSage, now, post, seconds, start, type, types, _ref;
if (Object.keys(QR.cooldown.cooldowns).length) {
setTimeout(QR.cooldown.count, 1000);
} else {
$["delete"]("" + g.BOARD + ".cooldown");
QR.cooldown.isCounting = false;
return; return;
} }
setTimeout(QR.cooldown.count, 1000, seconds - 1, length); if ((isReply = g.REPLY ? true : QR.threadSelector.value !== 'new')) {
post = QR.replies[0];
isSage = /sage/i.test(post.email);
hasFile = !!post.file;
}
now = Date.now();
seconds = null;
_ref = QR.cooldown, types = _ref.types, cooldowns = _ref.cooldowns;
for (start in cooldowns) {
cooldown = cooldowns[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;
}
type = isReply && cooldown.isReply ? isSage && cooldown.isSage ? 'sage' : hasFile && cooldown.hasFile ? 'file' : 'post' : !(isReply || cooldown.isReply) ? type = 'thread' : void 0;
if (type) {
elapsed = Math.floor((now - start) / 1000);
if (elapsed >= 0) {
seconds = Math.max(seconds, types[type] - elapsed);
}
type = '';
}
if (!((start <= now && now <= cooldown.timeout))) {
QR.cooldown.unset(start);
}
}
QR.cooldown.seconds = seconds; QR.cooldown.seconds = seconds;
if (seconds === 0) { if (seconds !== null) {
$["delete"]("/" + g.BOARD + "/cooldown"); QR.status();
if (QR.cooldown.auto) {
QR.submit();
} }
if (seconds === 0 && QR.cooldown.auto) {
return QR.submit();
} }
return QR.status();
} }
}, },
quote: function(e) { quote: function(e) {
@ -1883,7 +1957,7 @@
} }
QR.open(); QR.open();
if (!g.REPLY) { if (!g.REPLY) {
$('select', QR.el).value = $.x('ancestor::div[parent::div[@class="board"]]', this).id.slice(1); QR.threadSelector.value = $.x('ancestor::div[parent::div[@class="board"]]', this).id.slice(1);
} }
id = this.previousSibling.hash.slice(2); id = this.previousSibling.hash.slice(2);
text = ">>" + id + "\n"; text = ">>" + id + "\n";
@ -2173,10 +2247,7 @@
(QR.replies[index - 1] || QR.replies[index + 1]).select(); (QR.replies[index - 1] || QR.replies[index + 1]).select();
} }
QR.replies.splice(index, 1); QR.replies.splice(index, 1);
if (typeof (_base1 = window.URL || window.webkitURL).revokeObjectURL === "function") { return typeof (_base1 = window.URL || window.webkitURL).revokeObjectURL === "function" ? _base1.revokeObjectURL(this.url) : void 0;
_base1.revokeObjectURL(this.url);
}
return delete this;
}; };
return _Class; return _Class;
@ -2342,11 +2413,12 @@
id = thread.id.slice(1); id = thread.id.slice(1);
threads += "<option value=" + id + ">Thread " + id + "</option>"; threads += "<option value=" + id + ">Thread " + id + "</option>";
} }
$.prepend($('.move > span', QR.el), $.el('select', { QR.threadSelector = $.el('select', {
innerHTML: threads, innerHTML: threads,
title: 'Create a new thread / Reply to a thread' title: 'Create a new thread / Reply to a thread'
})); });
$.on($('select', QR.el), 'mousedown', function(e) { $.prepend($('.move > span', QR.el), QR.threadSelector);
$.on(QR.threadSelector, 'mousedown', function(e) {
return e.stopPropagation(); return e.stopPropagation();
}); });
} }
@ -2380,7 +2452,7 @@
$.on($("[name=" + name + "]", QR.el), 'input', function() { $.on($("[name=" + name + "]", QR.el), 'input', function() {
var _ref2; var _ref2;
QR.selected[this.name] = this.value; QR.selected[this.name] = this.value;
if (QR.cooldown.auto && QR.selected === QR.replies[0] && (0 < (_ref2 = QR.cooldown.seconds) && _ref2 < 6)) { if (QR.cooldown.auto && QR.selected === QR.replies[0] && (0 < (_ref2 = QR.cooldown.seconds) && _ref2 <= 5)) {
return QR.cooldown.auto = false; return QR.cooldown.auto = false;
} }
}); });
@ -2406,7 +2478,7 @@
} }
QR.abort(); QR.abort();
reply = QR.replies[0]; reply = QR.replies[0];
threadID = g.THREAD_ID || $('select', QR.el).value; threadID = g.THREAD_ID || QR.threadSelector.value;
if (threadID === 'new') { if (threadID === 'new') {
if (((_ref = g.BOARD) === 'vg' || _ref === 'q') && !reply.sub) { if (((_ref = g.BOARD) === 'vg' || _ref === 'q') && !reply.sub) {
err = 'New threads require a subject.'; err = 'New threads require a subject.';
@ -2506,7 +2578,7 @@
return QR.ajax = $.ajax($.id('postForm').parentNode.action, callbacks, opts); return QR.ajax = $.ajax($.id('postForm').parentNode.action, callbacks, opts);
}, },
response: function(html) { response: function(html) {
var bs, doc, err, msg, persona, postID, reply, sage, seconds, threadID, _, _ref, _ref1; var bs, doc, err, msg, persona, postID, reply, threadID, _, _ref, _ref1;
doc = d.implementation.createHTMLDocument(''); doc = d.implementation.createHTMLDocument('');
doc.documentElement.innerHTML = html; doc.documentElement.innerHTML = html;
if (doc.title === '4chan - Banned') { if (doc.title === '4chan - Banned') {
@ -2527,7 +2599,9 @@
err.textContent = 'Error: You seem to have mistyped the CAPTCHA.'; err.textContent = 'Error: You seem to have mistyped the CAPTCHA.';
} }
QR.cooldown.auto = QR.captchaIsEnabled ? !!$.get('captchas', []).length : true; QR.cooldown.auto = QR.captchaIsEnabled ? !!$.get('captchas', []).length : true;
QR.cooldown.set(2); QR.cooldown.set({
delay: 2
});
} else { } else {
QR.cooldown.auto = false; QR.cooldown.auto = false;
} }
@ -2551,13 +2625,14 @@
postID: postID postID: postID
} }
})); }));
QR.cooldown.set({
post: reply,
isReply: threadID !== '0'
});
if (threadID === '0') { if (threadID === '0') {
location.pathname = "/" + g.BOARD + "/res/" + postID; location.pathname = "/" + g.BOARD + "/res/" + postID;
} else { } else {
QR.cooldown.auto = QR.replies.length > 1; QR.cooldown.auto = QR.replies.length > 1;
sage = /sage/i.test(reply.email);
seconds = g.BOARD === 'q' ? sage ? 600 : reply.file ? 300 : 60 : sage ? 60 : 30;
QR.cooldown.set(seconds);
if (Conf['Open Reply in New Tab'] && !g.REPLY && !QR.cooldown.auto) { if (Conf['Open Reply in New Tab'] && !g.REPLY && !QR.cooldown.auto) {
$.open("//boards.4chan.org/" + g.BOARD + "/res/" + threadID + "#p" + postID); $.open("//boards.4chan.org/" + g.BOARD + "/res/" + threadID + "#p" + postID);
} }

View File

@ -1,4 +1,8 @@
master master
- Mayhem
Added thread creation QR cooldown.
Fix QR cooldown timer between non-sage and sage posts. You can submit a non-sage post 30 seconds after a sage one.
Fix /q/ QR cooldowns.
2.35.4 2.35.4
- Mayhem - Mayhem

View File

@ -1342,7 +1342,7 @@ QR =
link = $.el 'h1', innerHTML: "<a href=javascript:;>#{if g.REPLY then 'Reply to Thread' else 'Start a Thread'}</a>" link = $.el 'h1', innerHTML: "<a href=javascript:;>#{if g.REPLY then 'Reply to Thread' else 'Start a Thread'}</a>"
$.on link.firstChild, 'click', -> $.on link.firstChild, 'click', ->
QR.open() QR.open()
$('select', QR.el).value = 'new' unless g.REPLY QR.threadSelector.value = 'new' unless g.REPLY
$('textarea', QR.el).focus() $('textarea', QR.el).focus()
$.before $.id('postForm'), link $.before $.id('postForm'), link
@ -1418,32 +1418,108 @@ QR =
cooldown: cooldown:
init: -> init: ->
return unless Conf['Cooldown'] return unless Conf['Cooldown']
{timeout, length} = $.get "/#{g.BOARD}/cooldown", {} QR.cooldown.types =
QR.cooldown.start timeout, length if timeout thread: switch g.BOARD
$.sync "/#{g.BOARD}/cooldown", QR.cooldown.start when 'q' then 86400
start: (timeout, length) -> when 'b', 'soc', 'r9k' then 600
seconds = Math.floor (timeout - Date.now()) / 1000 else 300
QR.cooldown.count seconds, length sage: if g.BOARD is 'q' then 600 else 60
set: (seconds) -> file: if g.BOARD is 'q' then 300 else 30
post: if g.BOARD is 'q' then 60 else 30
QR.cooldown.cooldowns = $.get "#{g.BOARD}.cooldown", {}
QR.cooldown.start()
$.sync "#{g.BOARD}.cooldown", QR.cooldown.sync
start: ->
return if QR.cooldown.isCounting
QR.cooldown.isCounting = true
QR.cooldown.count()
sync: (cooldowns) ->
QR.cooldown.cooldowns = cooldowns
QR.cooldown.start()
set: (data) ->
return unless Conf['Cooldown'] return unless Conf['Cooldown']
QR.cooldown.count seconds, seconds start = Date.now()
$.set "/#{g.BOARD}/cooldown", if data.delay
timeout: Date.now() + seconds * $.SECOND cooldown = delay: data.delay
length: seconds else
count: (seconds, length) -> isSage = /sage/i.test data.post.email
return unless 0 <= seconds <= length hasFile = !!data.post.file
setTimeout QR.cooldown.count, 1000, seconds-1, length isReply = data.isReply
type =
unless isReply
'thread'
else
if isSage
'sage'
else if hasFile
'file'
else
'post'
cooldown =
isReply: isReply
isSage: isSage
hasFile: hasFile
timeout: start + QR.cooldown.types[type] * $.SECOND
QR.cooldown.cooldowns[start] = cooldown
$.set "#{g.BOARD}.cooldown", QR.cooldown.cooldowns
QR.cooldown.start()
unset: (id) ->
delete QR.cooldown.cooldowns[id]
$.set "#{g.BOARD}.cooldown", QR.cooldown.cooldowns
count: ->
if Object.keys(QR.cooldown.cooldowns).length
setTimeout QR.cooldown.count, 1000
else
$.delete "#{g.BOARD}.cooldown"
QR.cooldown.isCounting = false
return
if (isReply = if g.REPLY then true else QR.threadSelector.value isnt 'new')
post = QR.replies[0]
isSage = /sage/i.test post.email
hasFile = !!post.file
now = Date.now()
seconds = null
{types, cooldowns} = QR.cooldown
for start, cooldown of cooldowns
if 'delay' of cooldown
if cooldown.delay
seconds = Math.max seconds, cooldown.delay--
else
seconds = Math.max seconds, 0
QR.cooldown.unset start
continue
# Only cooldowns relevant to this post can set the seconds value.
# Unset outdated cooldowns that can no longer impact us.
type =
if isReply and cooldown.isReply
if isSage and cooldown.isSage
'sage'
else if hasFile and cooldown.hasFile
'file'
else
'post'
else unless isReply or cooldown.isReply
type = 'thread'
if type
elapsed = Math.floor (now - start) / 1000
if elapsed >= 0 # clock changed since then?
seconds = Math.max seconds, types[type] - elapsed
type = ''
unless start <= now <= cooldown.timeout
QR.cooldown.unset start
QR.cooldown.seconds = seconds QR.cooldown.seconds = seconds
if seconds is 0 QR.status() if seconds isnt null
$.delete "/#{g.BOARD}/cooldown" QR.submit() if seconds is 0 and QR.cooldown.auto
QR.submit() if QR.cooldown.auto
QR.status()
quote: (e) -> quote: (e) ->
e?.preventDefault() e?.preventDefault()
QR.open() QR.open()
unless g.REPLY unless g.REPLY
$('select', QR.el).value = $.x('ancestor::div[parent::div[@class="board"]]', @).id[1..] QR.threadSelector.value = $.x('ancestor::div[parent::div[@class="board"]]', @).id[1..]
# Make sure we get the correct number, even with XXX censors # Make sure we get the correct number, even with XXX censors
id = @previousSibling.hash[2..] id = @previousSibling.hash[2..]
text = ">>#{id}\n" text = ">>#{id}\n"
@ -1674,7 +1750,6 @@ QR =
(QR.replies[index-1] or QR.replies[index+1]).select() (QR.replies[index-1] or QR.replies[index+1]).select()
QR.replies.splice index, 1 QR.replies.splice index, 1
(window.URL or window.webkitURL).revokeObjectURL? @url (window.URL or window.webkitURL).revokeObjectURL? @url
delete @
captcha: captcha:
init: -> init: ->
@ -1804,10 +1879,11 @@ QR =
for thread in $$ '.thread' for thread in $$ '.thread'
id = thread.id[1..] id = thread.id[1..]
threads += "<option value=#{id}>Thread #{id}</option>" threads += "<option value=#{id}>Thread #{id}</option>"
$.prepend $('.move > span', QR.el), $.el 'select' QR.threadSelector = $.el 'select'
innerHTML: threads innerHTML: threads
title: 'Create a new thread / Reply to a thread' title: 'Create a new thread / Reply to a thread'
$.on $('select', QR.el), 'mousedown', (e) -> e.stopPropagation() $.prepend $('.move > span', QR.el), QR.threadSelector
$.on QR.threadSelector, 'mousedown', (e) -> e.stopPropagation()
$.on $('#autohide', QR.el), 'change', QR.toggleHide $.on $('#autohide', QR.el), 'change', QR.toggleHide
$.on $('.close', QR.el), 'click', QR.close $.on $('.close', QR.el), 'click', QR.close
$.on $('#dump', QR.el), 'click', -> QR.el.classList.toggle 'dump' $.on $('#dump', QR.el), 'click', -> QR.el.classList.toggle 'dump'
@ -1828,7 +1904,7 @@ QR =
QR.selected[@name] = @value QR.selected[@name] = @value
# Disable auto-posting if you're typing in the first reply # Disable auto-posting if you're typing in the first reply
# during the last 5 seconds of the cooldown. # during the last 5 seconds of the cooldown.
if QR.cooldown.auto and QR.selected is QR.replies[0] and 0 < QR.cooldown.seconds < 6 if QR.cooldown.auto and QR.selected is QR.replies[0] and 0 < QR.cooldown.seconds <= 5
QR.cooldown.auto = false QR.cooldown.auto = false
QR.status.input = $ 'input[type=submit]', QR.el QR.status.input = $ 'input[type=submit]', QR.el
@ -1851,7 +1927,7 @@ QR =
QR.abort() QR.abort()
reply = QR.replies[0] reply = QR.replies[0]
threadID = g.THREAD_ID or $('select', QR.el).value threadID = g.THREAD_ID or QR.threadSelector.value
# prevent errors # prevent errors
if threadID is 'new' if threadID is 'new'
@ -1972,7 +2048,7 @@ QR =
true true
# Too many frequent mistyped captchas will auto-ban you! # Too many frequent mistyped captchas will auto-ban you!
# On connection error, the post most likely didn't go through. # On connection error, the post most likely didn't go through.
QR.cooldown.set 2 QR.cooldown.set delay: 2
else # stop auto-posting else # stop auto-posting
QR.cooldown.auto = false QR.cooldown.auto = false
QR.status() QR.status()
@ -1997,29 +2073,16 @@ QR =
threadID: threadID threadID: threadID
postID: postID postID: postID
QR.cooldown.set
post: reply
isReply: threadID isnt '0'
if threadID is '0' # new thread if threadID is '0' # new thread
# auto-noko # auto-noko
location.pathname = "/#{g.BOARD}/res/#{postID}" location.pathname = "/#{g.BOARD}/res/#{postID}"
else else
# Enable auto-posting if we have stuff to post, disable it otherwise. # Enable auto-posting if we have stuff to post, disable it otherwise.
QR.cooldown.auto = QR.replies.length > 1 QR.cooldown.auto = QR.replies.length > 1
sage = /sage/i.test reply.email
seconds =
# 300 seconds cooldown for new threads
# q: 86400 seconds
# b soc r9k: 600 seconds
if g.BOARD is 'q'
if sage
600
else if reply.file
300
else
60
else if sage
60
else
30
QR.cooldown.set seconds
if Conf['Open Reply in New Tab'] and !g.REPLY and !QR.cooldown.auto if Conf['Open Reply in New Tab'] and !g.REPLY and !QR.cooldown.auto
$.open "//boards.4chan.org/#{g.BOARD}/res/#{threadID}#p#{postID}" $.open "//boards.4chan.org/#{g.BOARD}/res/#{threadID}#p#{postID}"