Skip to content
Snippets Groups Projects
Commit 5e7699f9 authored by Rob Swindell's avatar Rob Swindell :speech_balloon:
Browse files

Merge remote-tracking branch 'origin/master'

parents 9e0dc7b5 f42e3a87
No related branches found
No related tags found
1 merge request!463MRC mods by Codefenix (2024-10-20)
...@@ -4,6 +4,7 @@ var last_subs; ...@@ -4,6 +4,7 @@ var last_subs;
var last_groups; var last_groups;
var last_threads; var last_threads;
var last_run = 0; var last_run = 0;
const is_real_user = is_user();
const frequency = (settings.refresh_interval || 60000) / 1000; const frequency = (settings.refresh_interval || 60000) / 1000;
// Where 'a' is the previous data and 'b' is new // Where 'a' is the previous data and 'b' is new
...@@ -46,7 +47,7 @@ function scan_subs(group) { ...@@ -46,7 +47,7 @@ function scan_subs(group) {
} }
function scan_threads(sub, offset, page_size) { function scan_threads(sub, offset, page_size) {
const scan = getThreadStats(sub, offset, page_size); const scan = getThreadStats(sub, offset, page_size, !is_real_user);
if (!last_threads) { if (!last_threads) {
forum_emit('threads', scan); forum_emit('threads', scan);
} else { } else {
...@@ -66,11 +67,10 @@ function scan_threads(sub, offset, page_size) { ...@@ -66,11 +67,10 @@ function scan_threads(sub, offset, page_size) {
} }
function cycle() { function cycle() {
if (!is_user()) return;
if (time() - last_run <= frequency) return; if (time() - last_run <= frequency) return;
last_run = time(); last_run = time();
if (Request.has_param('groups_unread')) scan_groups(); if (is_real_user && Request.has_param('groups_unread')) scan_groups();
if (Request.has_param('subs_unread')) scan_subs(Request.get_param('subs_unread')); if (is_real_user && Request.has_param('subs_unread')) scan_subs(Request.get_param('subs_unread'));
if (Request.has_param('threads')) scan_threads(Request.get_param('threads'), Request.get_param('offset'), Request.get_param('page_size')); if (Request.has_param('threads')) scan_threads(Request.get_param('threads'), Request.get_param('offset'), Request.get_param('page_size'));
} }
......
...@@ -45,15 +45,13 @@ function listSubs(group) { ...@@ -45,15 +45,13 @@ function listSubs(group) {
}); });
} }
function listThreads(sub, offset, count, page_offset) { function listThreads(sub, offset, count) {
offset = parseInt(offset); offset = parseInt(offset);
if (isNaN(offset) || offset < 0) return false; if (isNaN(offset) || offset < 0) return false;
count = parseInt(count); count = parseInt(count);
if (isNaN(count) || count < 1) return false; if (isNaN(count) || count < 1) return false;
if (page_offset) offset = offset * count;
var threads = getMessageThreads(sub, settings.max_messages); var threads = getMessageThreads(sub, settings.max_messages);
if (offset >= threads.order.length) return false; if (offset >= threads.order.length) return false;
...@@ -72,6 +70,36 @@ function listThreads(sub, offset, count, page_offset) { ...@@ -72,6 +70,36 @@ function listThreads(sub, offset, count, page_offset) {
} }
function getNewestMessageInSub(sub) {
const mb = new MsgBase(sub.code);
if (!mb.open()) return;
var h;
var ret;
for (var m = mb.last_msg; m >= mb.first_msg; m--) {
h = mb.get_msg_header(m);
if (h === null) continue;
ret = {
from: h.from,
subject: h.subject,
when_written_time: h.when_written_time,
};
break;
}
mb.close();
return ret;
}
function getNewestMessagePerSub(grp) {
grp = parseInt(grp, 10);
if (isNaN(grp) || grp < 0 || !msg_area.grp_list[grp]) return [];
return msg_area.grp_list[grp].sub_list.reduce(function (a, c) {
const s = getNewestMessageInSub(c);
if (s !== undefined) a[c.code] = s;
log(LOG_DEBUG, JSON.stringify(s));
return a;
}, {});
}
function getSubUnreadCount(sub) { function getSubUnreadCount(sub) {
var ret = { var ret = {
scanned: 0, scanned: 0,
...@@ -157,7 +185,7 @@ function getThreadVoteTotals(thread, mkeys) { ...@@ -157,7 +185,7 @@ function getThreadVoteTotals(thread, mkeys) {
} }
// { [thread_id]: { total, unread, votes: { up: { parent, total }, down: { parent, total }, total }, newest } } // { [thread_id]: { total, unread, votes: { up: { parent, total }, down: { parent, total }, total }, newest } }
function getThreadStats(sub, offset, page_size) { function getThreadStats(sub, offset, page_size, guest) {
const threads = getMessageThreads(sub, settings.max_messages); const threads = getMessageThreads(sub, settings.max_messages);
const ret = {}; const ret = {};
if (!offset) offset = 0; if (!offset) offset = 0;
...@@ -169,7 +197,7 @@ function getThreadStats(sub, offset, page_size) { ...@@ -169,7 +197,7 @@ function getThreadStats(sub, offset, page_size) {
var mkeys = Object.keys(thread.messages); var mkeys = Object.keys(thread.messages);
ret[threads.order[n]] = { ret[threads.order[n]] = {
total: mkeys.length, total: mkeys.length,
unread: getUnreadInThread(sub, thread, mkeys), unread: guest ? 0 : getUnreadInThread(sub, thread, mkeys),
votes: getThreadVoteTotals(thread, mkeys), votes: getThreadVoteTotals(thread, mkeys),
newest: { newest: {
from: thread.messages[mkeys[mkeys.length - 1]].from, from: thread.messages[mkeys[mkeys.length - 1]].from,
......
...@@ -74,6 +74,7 @@ label_message_to = To ...@@ -74,6 +74,7 @@ label_message_to = To
label_message_date = on label_message_date = on
label_message_subject = Subject label_message_subject = Subject
label_thread_latest_reply = Latest reply from label_thread_latest_reply = Latest reply from
label_sub_newest_message = Latest message
suffix_reply_count = reply suffix_reply_count = reply
suffix_replies_count = replies suffix_replies_count = replies
badge_poll = POLL badge_poll = POLL
......
...@@ -10,11 +10,11 @@ ...@@ -10,11 +10,11 @@
<!-- To do: Search (forum, group, sub, or thread), Sortation and data-attributes --> <!-- To do: Search (forum, group, sub, or thread), Sortation and data-attributes -->
<?xjs if (Request.has_param('sub') && Request.has_param('thread')) { ?> <? if (Request.has_param('sub') && Request.has_param('thread')) { ?>
<?xjs <?xjs
var offset = Request.has_param('offset') ? parseInt(Request.get_param('offset')) : 0; var offset = Request.has_param('offset') ? parseInt(Request.get_param('offset')) : 0;
const thread = getMessageThreads(Request.get_param('sub'), settings.max_messages).thread[Request.get_param('thread')]; var thread = getMessageThreads(Request.get_param('sub'), settings.max_messages).thread[Request.get_param('thread')];
?> ?>
<ol class="breadcrumb"> <ol class="breadcrumb">
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
</div> </div>
<?xjs } else if (Request.has_param('sub') && typeof msg_area.sub[Request.get_param('sub')] != 'undefined') { ?> <? } else if (Request.has_param('sub') && msg_area.sub[Request.get_param('sub')] !== undefined) { ?>
<ol class="breadcrumb"> <ol class="breadcrumb">
<li> <li>
...@@ -72,8 +72,8 @@ ...@@ -72,8 +72,8 @@
<?xjs <?xjs
var offset = Request.has_param('offset') ? parseInt(Request.get_param('offset')) : 0; var offset = Request.has_param('offset') ? parseInt(Request.get_param('offset')) : 0;
const threads = listThreads(Request.get_param('sub'), offset, settings.page_size, true) || { total: 0, threads: [] }; var threads = listThreads(Request.get_param('sub'), offset * settings.page_size, settings.page_size, true) || { total: 0, threads: [] };
const sub = msg_area.sub[Request.get_param('sub')]; var sub = msg_area.sub[Request.get_param('sub')];
?> ?>
<button class="btn btn-default icon" aria-label="<? locale.write('button_post_message'); ?>" title="<? locale.write('button_post_message'); ?>" onclick="addNew('<? write(sub.code); ?>')"> <button class="btn btn-default icon" aria-label="<? locale.write('button_post_message'); ?>" title="<? locale.write('button_post_message'); ?>" onclick="addNew('<? write(sub.code); ?>')">
...@@ -107,9 +107,9 @@ ...@@ -107,9 +107,9 @@
</div> </div>
<div id="forum-thread-stats-template" hidden> <div id="forum-thread-stats-template" hidden>
<?xjs if (is_user()) { ?> <? if (is_user()) { ?>
<span data-unread-messages title="<? locale.write('badge_unread_messages'); ?>" class="badge <? write(sub.scan_cfg&SCAN_CFG_NEW || sub.scan_cfg&SCAN_CFG_YONLY ? 'scanned' : ''); ?>" hidden></span> <span data-unread-messages title="<? locale.write('badge_unread_messages'); ?>" class="badge <? write(sub.scan_cfg&SCAN_CFG_NEW || sub.scan_cfg&SCAN_CFG_YONLY ? 'scanned' : ''); ?>" hidden></span>
<?xjs } ?> <? } ?>
<span data-upvotes-badge title="<? locale.write('badge_upvotes'); ?>" class="badge upvote-bg" style="display:none;"> <span data-upvotes-badge title="<? locale.write('badge_upvotes'); ?>" class="badge upvote-bg" style="display:none;">
<span class="glyphicon glyphicon-arrow-up"></span> <span class="glyphicon glyphicon-arrow-up"></span>
<span data-upvotes></span> <span data-upvotes></span>
...@@ -121,25 +121,25 @@ ...@@ -121,25 +121,25 @@
</div> </div>
<div id="forum-list-container" class="list-group"> <div id="forum-list-container" class="list-group">
<?xjs threads.threads.forEach(function (e) { ?> <? threads.threads.forEach(function (e) { ?>
<a href="./?page=<? Request.write_param('page'); ?>&sub=<? Request.write_param('sub'); ?>&thread=<? write(e.id); ?>" class="list-group-item striped"> <a href="./?page=<? Request.write_param('page'); ?>&sub=<? Request.write_param('sub'); ?>&thread=<? write(e.id); ?>" class="list-group-item striped">
<div class="row"> <div class="row">
<div id="left-<? write(e.id); ?>" class="col-sm-9"> <div id="left-<? write(e.id); ?>" class="col-sm-9">
<strong><? write(e.subject); ?></strong> <strong><? write(e.subject); ?></strong>
<p><strong><? write(e.first.from); ?></strong>, <? write(system.timestr(e.first.when_written_time)); ?></p> <p><? locale.write('label_thread_from'); ?> <strong><? write(e.first.from); ?></strong> <? locale.write('label_message_date'); ?> <? write(system.timestr(e.first.when_written_time)); ?></p>
</div> </div>
<div class="col-sm-3"> <div class="col-sm-3">
<div id="right-<? write(e.id); ?>" class="pull-right"></div> <div id="right-<? write(e.id); ?>" class="pull-right"></div>
</div> </div>
</div> </div>
</a> </a>
<?xjs }); ?> <? }); ?>
</div> </div>
<?xjs if (threads.total / settings.page_size > 1) { ?> <? if (threads.total / settings.page_size > 1) { ?>
<?xjs qs = http_request.query_string.replace(/&offset=\d+/g, ''); ?> <? var qs = http_request.query_string.replace(/&offset=\d+/g, ''); ?>
<div class="btn-group"> <div class="btn-group">
<?xjs if (offset > 0) { ?> <? if (offset > 0) { ?>
<a href="./?<? write(qs); ?>&offset=0" role="button" class="btn btn-default" title="<? locale.write('button_thread_first_page'); ?>"> <a href="./?<? write(qs); ?>&offset=0" role="button" class="btn btn-default" title="<? locale.write('button_thread_first_page'); ?>">
<span class="glyphicon glyphicon-fast-backward"></span> <span class="glyphicon glyphicon-fast-backward"></span>
</a> </a>
...@@ -149,14 +149,14 @@ ...@@ -149,14 +149,14 @@
<a href="./?<? write(qs); ?>&offset=<? write(Math.max(0, offset - 1)); ?>" role="button" class="btn btn-default" title="<? locale.write('button_thread_previous_page'); ?>"> <a href="./?<? write(qs); ?>&offset=<? write(Math.max(0, offset - 1)); ?>" role="button" class="btn btn-default" title="<? locale.write('button_thread_previous_page'); ?>">
<span class="glyphicon glyphicon-step-backward"></span> <span class="glyphicon glyphicon-step-backward"></span>
</a> </a>
<?xjs } ?> <? } ?>
<a href="./?<? write(qs); ?>&offset=<? write(offset); ?>" role="button" class="btn btn-default" disabled> <a href="./?<? write(qs); ?>&offset=<? write(offset); ?>" role="button" class="btn btn-default" disabled>
<? write(offset + 1); ?> <? write(offset + 1); ?>
</a> </a>
<?xjs for (var n = offset + 1; n < threads.total / settings.page_size && n - offset < 9; n++) { ?> <? for (var n = offset + 1; n < threads.total / settings.page_size && n - offset < 9; n++) { ?>
<a href="./?<? write(qs); ?>&offset=<? write(n); ?>" role="button" class="btn btn-default"><? write(n + 1); ?></a> <a href="./?<? write(qs); ?>&offset=<? write(n); ?>" role="button" class="btn btn-default"><? write(n + 1); ?></a>
<?xjs } ?> <? } ?>
<?xjs if (threads.total / settings.page_size > offset + 9) { ?> <? if (threads.total / settings.page_size > offset + 9) { ?>
<a href="./?<? write(qs); ?>&offset=<? write(offset + 1); ?>" role="button" class="btn btn-default" title="<? locale.write('button_thread_next_page'); ?>"> <a href="./?<? write(qs); ?>&offset=<? write(offset + 1); ?>" role="button" class="btn btn-default" title="<? locale.write('button_thread_next_page'); ?>">
<span class="glyphicon glyphicon-step-forward"></span> <span class="glyphicon glyphicon-step-forward"></span>
</a> </a>
...@@ -166,23 +166,25 @@ ...@@ -166,23 +166,25 @@
<a href="./?<? write(qs); ?>&offset=<? write(Math.floor(threads.total / settings.page_size)); ?>" role="button" class="btn btn-default" title="<? locale.write('button_thread_last_page'); ?>"> <a href="./?<? write(qs); ?>&offset=<? write(Math.floor(threads.total / settings.page_size)); ?>" role="button" class="btn btn-default" title="<? locale.write('button_thread_last_page'); ?>">
<span class="glyphicon glyphicon-fast-forward"></span> <span class="glyphicon glyphicon-fast-forward"></span>
</a> </a>
<?xjs } ?> <? } ?>
</div class="btn-group"> </div class="btn-group">
<?xjs } ?> <? } ?>
<script type="text/javascript"> <script type="text/javascript">
registerEventListener('forum', function (e) {
registerEventListener('forum', e => {
const data = JSON.parse(e.data); const data = JSON.parse(e.data);
if (data.type != 'threads') return; if (data.type != 'threads') return;
onThreadStats(data.data); onThreadStats(data.data);
}, { }, {
threads: '<? Request.write_param("sub"); ?>', threads: '<? Request.write_param("sub"); ?>',
offset: '<? write(offset); ?>', offset: '<? write(offset); ?>',
page_size: '<? write(settings.page_size); ?>' page_size: '<? write(settings.page_size); ?>',
}); });
</script> </script>
<?xjs } else if (Request.has_param('group') && typeof msg_area.grp_list[Request.get_param('group')] != 'undefined') { ?> <? } else if (Request.has_param('group') && msg_area.grp_list[Request.get_param('group')] !== undefined) { ?>
<ol class="breadcrumb"> <ol class="breadcrumb">
<li> <li>
...@@ -198,54 +200,81 @@ ...@@ -198,54 +200,81 @@
</ol> </ol>
<div id="forum-list-container" class="list-group"> <div id="forum-list-container" class="list-group">
<?xjs const subs = listSubs(Request.get_param('group')); ?> <? var subs = listSubs(Request.get_param('group')); ?>
<?xjs subs.forEach(function (e) { ?> <? subs.forEach(function (e) { ?>
<a href="./?page=<? Request.write_param('page'); ?>&sub=<? write(e.code); ?>" class="list-group-item striped"> <a href="./?page=<? Request.write_param('page'); ?>&sub=<? write(e.code); ?>" class="list-group-item striped">
<h4><strong><? write(e.name); ?></strong></h4> <h4>
<strong>
<? write(e.name); ?>
</strong>
</h4>
<span title="<? locale.write('badge_unread_messages'); ?>" class="badge <? write(e.scan_cfg&SCAN_CFG_NEW || e.scan_cfg&SCAN_CFG_YONLY ? 'scanned' : 'total'); ?>" id="badge-<? write(e.code); ?>"></span> <span title="<? locale.write('badge_unread_messages'); ?>" class="badge <? write(e.scan_cfg&SCAN_CFG_NEW || e.scan_cfg&SCAN_CFG_YONLY ? 'scanned' : 'total'); ?>" id="badge-<? write(e.code); ?>"></span>
<p><? write(e.description); ?></p> <p><? write(e.description); ?></p>
<span id="newest-msg-<? write(e.code); ?>"></span>
</a> </a>
<?xjs }); ?> <? }); ?>
</div> </div>
<?xjs if (is_user()) { ?> <? if (is_user()) { ?>
<script type="text/javascript"> <script type="text/javascript">
registerEventListener('forum', function (e) { registerEventListener('forum', e => {
const data = JSON.parse(e.data); const data = JSON.parse(e.data);
if (data.type != 'subs_unread') return; if (data.type != 'subs_unread') return;
onSubUnreadCount(data.data); onSubUnreadCount(data.data);
}, { subs_unread: '<? Request.write_param("group"); ?>' }); }, { subs_unread: '<? Request.write_param("group"); ?>' });
</script> </script>
<?xjs } ?> <? } ?>
<script type="text/javascript">
(async function getNewestMessagePerSub() {
try {
const response = await fetch('./api/forum.ssjs?call=get-newest-message-per-sub&group=<? Request.write_param('group'); ?>');
const data = await response.json();
Object.entries(data).forEach(e => {
document.getElementById(`newest-msg-${e[0]}`).innerHTML = `<? locale.write('label_sub_newest_message'); ?>: ${e[1].subject}, <? locale.write('label_thread_from'); ?> ${e[1].from} <? locale.write('label_message_date'); ?> ${new Date(e[1].when_written_time * 1000)}`;
});
} catch (err) {
console.error('Error fetching latest messages', err);
}
})();
</script>
<?xjs } else { ?> <? } else { ?>
<ol class="breadcrumb"> <ol class="breadcrumb">
<li> <li>
<a href="./?page=<? Request.write_param('page'); ?>"><? locale.write('title'); ?></a> <a href="./?page=<? Request.write_param('page'); ?>">
<? locale.write('title'); ?>
</a>
</li> </li>
</ol> </ol>
<div id="forum-list-container" class="list-group"> <div id="forum-list-container" class="list-group">
<?xjs const groups = listGroups(); ?> <? const groups = listGroups(); ?>
<?xjs groups.forEach(function (e) { ?> <? groups.forEach(function (e) { ?>
<a href="./?page=<? Request.write_param('page'); ?>&group=<? write(e.index); ?>" class="list-group-item striped"> <a href="./?page=<? Request.write_param('page'); ?>&group=<? write(e.index); ?>" class="list-group-item striped">
<h3><strong><? write(e.name); ?></strong></h3> <h3>
<strong>
<? write(e.name); ?>
</strong>
</h3>
<span title="<? locale.write('badge_unread_messages'); ?>" class="badge ignored" id="badge-ignored-<? write(e.index); ?>"></span> <span title="<? locale.write('badge_unread_messages'); ?>" class="badge ignored" id="badge-ignored-<? write(e.index); ?>"></span>
<span title="<? locale.write('badge_unread_messages'); ?>" class="badge scanned" id="badge-scanned-<? write(e.index); ?>"></span> <span title="<? locale.write('badge_unread_messages'); ?>" class="badge scanned" id="badge-scanned-<? write(e.index); ?>"></span>
<p><? write(e.description); ?>: <? write(e.sub_count); ?> <? locale.write('sub_boards'); ?></p> <p>
<? write(e.description); ?>: <? write(e.sub_count); ?> <? locale.write('sub_boards'); ?>
</p>
</a> </a>
<?xjs }); ?> <? }); ?>
</div> </div>
<?xjs if (is_user()) { ?> <? if (is_user()) { ?>
<script type="text/javascript"> <script type="text/javascript">
registerEventListener('forum', function (e) { registerEventListener('forum', e => {
const data = JSON.parse(e.data); const data = JSON.parse(e.data);
if (data.type != 'groups_unread') return; if (data.type != 'groups_unread') return;
onGroupUnreadCount(data.data); onGroupUnreadCount(data.data);
}, { groups_unread: null }); }, { groups_unread: null });
</script> </script>
<?xjs } ?> <? } ?>
<?xjs } ?> <? } ?>
...@@ -175,6 +175,10 @@ if (Request.has_param('call') && (http_request.method === 'GET' || http_request. ...@@ -175,6 +175,10 @@ if (Request.has_param('call') && (http_request.method === 'GET' || http_request.
} }
break; break;
case 'get-newest-message-per-sub':
if (Request.has_param('group')) reply = getNewestMessagePerSub(Request.get_param('group'));
break;
default: default:
break; break;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment