Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
Synchronet
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Container Registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Main
Synchronet
Commits
b83b1ad2
Commit
b83b1ad2
authored
4 years ago
by
echicken
Browse files
Options
Downloads
Patches
Plain Diff
More new forum work in progress.
parent
7abd7707
No related branches found
No related tags found
1 merge request
!463
MRC mods by Codefenix (2024-10-20)
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
webv4/root/js/xjs-forum.js
+301
-169
301 additions, 169 deletions
webv4/root/js/xjs-forum.js
with
301 additions
and
169 deletions
webv4/root/js/xjs-forum.js
+
301
−
169
View file @
b83b1ad2
let
__v4_forum_offset
=
0
;
// Feels hacky
function
LoadingMessage
()
{
let
pos
=
0
;
let
cursor
=
[
'
|
'
,
'
/
'
,
'
—
'
,
'
\\
'
];
let
evt
;
const
flc
=
document
.
getElementById
(
'
forum-list-container
'
);
this
.
start
=
function
()
{
const
elem
=
document
.
querySelector
(
'
div[data-loading-template]
'
).
cloneNode
(
true
);
const
sc
=
elem
.
querySelector
(
'
span[data-spinning-cursor]
'
);
elem
.
removeAttribute
(
'
hidden
'
);
flc
.
appendChild
(
elem
);
evt
=
setInterval
(()
=>
{
sc
.
innerHTML
=
cursor
[
pos
%
cursor
.
length
];
pos
++
;
},
250
);
}
this
.
stop
=
function
()
{
flc
.
removeChild
(
flc
.
querySelector
(
'
div[data-loading-template]
'
));
clearInterval
(
evt
);
}
}
function
formatMessageDate
(
t
)
{
return
(
new
Date
(
t
*
1000
)).
toLocaleString
();
}
async
function
setScanCfg
(
sub
,
cfg
)
{
var
opts
=
[
'
scan-cfg-off
'
,
'
scan-cfg-new
'
,
'
scan-cfg-youonly
'
,
];
const
data
=
await
v4_get
(
`./api/forum.ssjs?call=set-scan-cfg&sub=
${
sub
}
&cfg=
${
cfg
}
`
);
if
(
!
data
.
success
)
return
;
opts
.
forEach
((
e
,
i
)
=>
{
const
elem
=
document
.
getElementById
(
`
${
e
}
`
);
if
(
cfg
==
i
)
{
elem
.
classList
.
add
(
'
btn-primary
'
);
elem
.
classList
.
remove
(
'
btn-default
'
);
}
else
{
elem
.
classList
.
add
(
'
btn-default
'
);
elem
.
classList
.
remove
(
'
btn-primary
'
);
}
});
}
async
function
addNew
(
sub
)
{
...
...
@@ -170,61 +218,15 @@ function addPollField(type, target) {
}
async
function
setScanCfg
(
sub
,
cfg
)
{
var
opts
=
[
'
scan-cfg-off
'
,
'
scan-cfg-new
'
,
'
scan-cfg-youonly
'
,
];
const
data
=
await
v4_get
(
`./api/forum.ssjs?call=set-scan-cfg&sub=
${
sub
}
&cfg=
${
cfg
}
`
);
if
(
!
data
.
success
)
return
;
opts
.
forEach
((
e
,
i
)
=>
{
const
elem
=
document
.
getElementById
(
`
${
e
}
`
);
if
(
cfg
==
i
)
{
elem
.
classList
.
add
(
'
btn-primary
'
);
elem
.
classList
.
remove
(
'
btn-default
'
);
}
else
{
elem
.
classList
.
add
(
'
btn-default
'
);
elem
.
classList
.
remove
(
'
btn-primary
'
);
}
});
}
function
LoadingMessage
()
{
let
pos
=
0
;
let
cursor
=
[
'
|
'
,
'
/
'
,
'
—
'
,
'
\\
'
];
let
evt
;
const
flc
=
document
.
getElementById
(
'
forum-list-container
'
);
this
.
start
=
function
()
{
const
elem
=
document
.
querySelector
(
'
div[data-loading-template]
'
).
cloneNode
(
true
);
const
sc
=
elem
.
querySelector
(
'
span[data-spinning-cursor]
'
);
elem
.
removeAttribute
(
'
hidden
'
);
flc
.
appendChild
(
elem
);
evt
=
setInterval
(()
=>
{
sc
.
innerHTML
=
cursor
[
pos
%
cursor
.
length
];
pos
++
;
},
250
);
}
this
.
stop
=
function
()
{
flc
.
removeChild
(
flc
.
querySelector
(
'
div[data-loading-template]
'
));
clearInterval
(
evt
);
}
}
// Message list
function
loading
(
l
)
{
var
flc
=
document
.
getElementById
(
'
forum-list-container
'
);
if
(
l
)
{
var
elem
=
document
.
querySelector
(
'
div[data-loading-template]
'
).
cloneNode
(
true
);
elem
.
removeAttribute
(
'
hidden
'
);
flc
.
appendChild
(
elem
);
}
else
{
flc
.
removeChild
(
flc
.
querySelector
(
'
div[data-loading-template]
'
));
}
function
lastVisibleMessage
()
{
const
lastMessageElement
=
Array
.
from
(
document
.
querySelectorAll
(
'
li[data-message]
'
)).
pop
();
if
(
!
lastMessageElement
)
return
null
;
const
ret
=
parseInt
(
lastMessageElement
.
getAttribute
(
'
data-message
'
),
10
);
if
(
isNaN
(
ret
)
||
ret
<
0
)
return
null
;
return
ret
;
}
async
function
listMessages
(
sub
,
thread
,
count
,
after
)
{
...
...
@@ -234,24 +236,46 @@ async function listMessages(sub, thread, count, after) {
dlmm
.
setAttribute
(
'
hidden
'
,
true
);
blmm
.
setAttribute
(
'
disabled
'
,
true
);
const
lm
=
new
LoadingMessage
();
lm
.
start
();
let
_data
;
const
loadingMessage
=
new
LoadingMessage
();
loadingMessage
.
start
();
let
data
=
JSON
.
parse
(
localStorage
.
getItem
(
`
${
sub
}
-
${
thread
}
`
));
if
(
data
===
null
)
{
data
=
await
v4_fetch_jsonl
(
`./api/forum.ssjs?call=get-thread&sub=
${
sub
}
&thread=
${
thread
}
&count=
${
count
}
`
);
if
(
data
===
null
)
{
// We have no local cache
if
(
after
)
{
// User clicked "Load more" but we don't know what the newest visible message is meant to be
const
lastMessage
=
lastVisibleMessage
();
if
(
lastMessage
===
null
)
{
// No messages in view, so start at the beginning
data
=
await
v4_fetch_jsonl
(
`./api/forum.ssjs?call=get-thread&sub=
${
sub
}
&thread=
${
thread
}
&count=
${
count
}
`
);
}
else
{
// Messages are in view, but we have no cache
// Rebuild cache and get next 'count' messages
data
=
await
v4_fetch_jsonl
(
`./api/forum.ssjs?call=get-thread&sub=
${
sub
}
&thread=
${
thread
}
&count=
${
count
}
&after=
${
lastMessage
}
&reload=true`
);
const
lmi
=
data
.
findIndex
(
e
=>
e
.
number
===
lastMessage
);
if
(
lmi
>
-
1
)
_data
=
data
.
slice
(
lmi
+
1
);
// If our lastMessage is cached, set _data to everything after it
}
}
else
{
// A clean first load of the page, or reload of first 'count' messages
data
=
await
v4_fetch_jsonl
(
`./api/forum.ssjs?call=get-thread&sub=
${
sub
}
&thread=
${
thread
}
&count=
${
count
}
`
);
}
}
else
if
(
after
)
{
_data
=
await
v4_fetch_jsonl
(
`./api/forum.ssjs?call=get-thread&sub=
${
sub
}
&thread=
${
thread
}
&count=
${
count
}
&after=
${
data
[
data
.
length
-
1
].
number
}
`
);
data
=
data
.
concat
(
_data
);
}
else
{
// TO DO: check for any newer messages than the newest we have on hand; prepend them
}
localStorage
.
setItem
(
`
${
sub
}
-
${
thread
}
`
,
JSON
.
stringify
(
data
));
l
m
.
stop
();
l
oadingMessage
.
stop
();
// TO DO: what about poll messages? If they may show up in (_data || data) then they need to be handled differently and a template created in forum.xjs
const
users
=
[];
(
_data
||
data
).
forEach
((
e
,
i
)
=>
{
let
akey
;
const
elem
=
document
.
getElementById
(
'
forum-message-template
'
).
cloneNode
(
true
);
elem
.
id
=
elem
.
id
.
replace
(
/template$/
,
e
.
number
);
let
elem
;
let
append
=
false
;
const
elemId
=
`forum-message-
${
e
.
number
}
`
;
if
((
elem
=
document
.
getElementById
(
elemId
))
===
null
)
{
elem
=
document
.
getElementById
(
'
forum-message-template
'
).
cloneNode
(
true
);
elem
.
id
=
elemId
;
elem
.
setAttribute
(
'
data-message
'
,
e
.
number
);
append
=
true
;
}
elem
.
querySelector
(
'
a[data-message-anchor]
'
).
id
=
e
.
number
;
if
(
i
==
0
&&
!
after
&&
e
.
subject
!==
undefined
)
elem
.
querySelector
(
'
strong[data-message-subject]
'
).
innerHTML
=
e
.
subject
;
elem
.
querySelector
(
'
strong[data-message-from]
'
).
innerHTML
=
e
.
from
;
...
...
@@ -270,7 +294,7 @@ async function listMessages(sub, thread, count, after) {
elem
.
querySelector
(
'
div[data-message-body]
'
).
innerHTML
=
e
.
body
;
elem
.
querySelector
(
'
a[data-direct-link]
'
).
setAttribute
(
'
href
'
,
`#
${
e
.
number
}
`
);
elem
.
removeAttribute
(
'
hidden
'
);
document
.
getElementById
(
'
forum-list-container
'
).
appendChild
(
elem
);
if
(
append
)
document
.
getElementById
(
'
forum-list-container
'
).
appendChild
(
elem
);
if
(
users
.
indexOf
(
akey
)
<
0
)
users
.
push
(
akey
);
});
...
...
@@ -281,6 +305,9 @@ async function listMessages(sub, thread, count, after) {
}
// Thread list
function
onThreadStats
(
data
)
{
Object
.
entries
(
data
).
forEach
(([
k
,
v
])
=>
{
...
...
@@ -348,6 +375,74 @@ function onThreadStats(data) {
}
function
lastVisibleThread
()
{
const
lastThreadElement
=
Array
.
from
(
document
.
querySelectorAll
(
'
li[data-thread]
'
)).
pop
();
if
(
!
lastThreadElement
)
return
null
;
const
ret
=
parseInt
(
lastThreadElement
.
getAttribute
(
'
data-thread
'
),
10
);
if
(
isNaN
(
ret
)
||
ret
<
0
)
return
null
;
return
ret
;
}
async
function
listThread
(
e
)
{
let
elem
;
let
append
=
false
;
const
elemId
=
`forum-thread-link-
${
e
.
id
}
`
;
if
((
elem
=
document
.
getElementById
(
elemId
))
===
null
)
{
elem
=
document
.
getElementById
(
'
forum-thread-link-template
'
).
cloneNode
(
true
);
elem
.
id
=
elemId
;
elem
.
setAttribute
(
'
data-thread
'
,
e
.
id
);
elem
.
setAttribute
(
'
href
'
,
`
${
elem
.
getAttribute
(
'
href
'
)}
&thread=
${
e
.
id
}
`
);
append
=
true
;
}
elem
.
querySelector
(
'
strong[data-thread-subject]
'
).
innerHTML
=
e
.
subject
;
elem
.
querySelector
(
'
strong[data-thread-from]
'
).
innerHTML
=
e
.
first
.
from
;
elem
.
querySelector
(
'
span[data-thread-date-start]
'
).
innerHTML
=
formatMessageDate
(
e
.
first
.
when_written_time
);
if
(
e
.
messages
>
1
)
{
elem
.
querySelector
(
'
strong[data-message-count]
'
).
innerHTML
=
e
.
messages
-
1
;
if
(
e
.
messages
==
2
)
{
elem
.
querySelector
(
'
span[data-suffix-reply]
'
).
removeAttribute
(
'
hidden
'
);
}
else
{
elem
.
querySelector
(
'
span[data-suffix-replies]
'
).
removeAttribute
(
'
hidden
'
);
}
elem
.
querySelector
(
'
strong[data-last-from]
'
).
innerHTML
=
e
.
last
.
from
;
elem
.
querySelector
(
'
span[data-last-time]
'
).
innerHTML
=
formatMessageDate
(
e
.
last
.
when_written_time
);
elem
.
querySelector
(
'
div[data-replies]
'
).
removeAttribute
(
'
hidden
'
);
}
const
stats
=
elem
.
querySelector
(
'
div[data-stats]
'
);
if
(
e
.
unread
)
{
const
sub
=
await
sbbs
.
forum
.
getSub
(
e
.
sub
);
const
urm
=
stats
.
querySelector
(
'
span[data-unread-messages]
'
);
if
(
urm
!==
null
)
{
// If user is guest, this element will not exist
urm
.
innerHTML
=
e
.
unread
;
if
(
sub
.
scan_cfg
&
(
1
<<
1
)
||
sub
.
scan_cfg
&
5
||
sub
.
scan_cfg
&
(
1
<<
8
))
{
urm
.
classList
.
add
(
'
scanned
'
);
}
else
{
urm
.
classList
.
remove
(
'
scanned
'
);
}
urm
.
removeAttribute
(
'
hidden
'
);
stats
.
removeAttribute
(
'
hidden
'
);
}
}
if
(
e
.
votes
.
total
)
{
if
(
e
.
votes
.
up
.
t
)
{
stats
.
querySelector
(
'
span[data-upvotes]
'
).
innerHTML
=
`
${
e
.
votes
.
up
.
p
}
/
${
e
.
votes
.
up
.
t
}
`
;
stats
.
querySelector
(
'
span[data-upvotes-badge]
'
).
style
.
setProperty
(
'
display
'
,
''
);
}
if
(
e
.
votes
.
down
.
t
)
{
stats
.
querySelector
(
'
span[data-downvotes]
'
).
innerHTML
=
`
${
e
.
votes
.
down
.
p
}
/
${
e
.
votes
.
down
.
t
}
`
;
stats
.
querySelector
(
'
span[data-downvotes-badge]
'
).
style
.
setProperty
(
'
display
'
,
''
);
}
stats
.
removeAttribute
(
'
hidden
'
);
}
elem
.
removeAttribute
(
'
hidden
'
);
if
(
append
)
document
.
getElementById
(
'
forum-list-container
'
).
appendChild
(
elem
);
}
async
function
listThreads
(
sub
,
count
,
after
)
{
const
dlmt
=
document
.
getElementById
(
'
forum-load-more-threads
'
);
...
...
@@ -357,144 +452,181 @@ async function listThreads(sub, count, after) {
const
lm
=
new
LoadingMessage
();
lm
.
start
();
let
_data
;
let
data
=
JSON
.
parse
(
localStorage
.
getItem
(
`
${
sub
}
-threadList`
));
if
(
data
===
null
)
{
data
=
await
v4_get
(
`./api/forum.ssjs?call=list-threads&sub=
${
sub
}
&count=
${
count
}
`
);
let
response
;
let
data
=
await
sbbs
.
forum
.
getThreads
(
v
=>
v
.
sub
===
sub
);
if
(
data
===
undefined
||
!
data
.
length
)
{
// We have no local cache
if
(
after
)
{
// User clicked "Load more" but we don't know what the newest visible thread is meant to be
const
lastThread
=
lastVisibleThread
();
if
(
lastThread
===
null
)
{
// No threads in view, so start at the beginning
response
=
await
v4_get
(
`./api/forum.ssjs?call=list-threads&sub=
${
sub
}
&count=
${
count
}
`
);
}
else
{
// Threads are in view, but we have no cache
// Rebuild cache and get next 'count' threads
response
=
await
v4_get
(
`./api/forum.ssjs?call=list-threads&sub=
${
sub
}
&count=
${
count
}
&after=
${
lastThread
}
&reload=true`
);
}
}
else
{
// A clean first load of the page, or reload of first 'count' threads
response
=
await
v4_get
(
`./api/forum.ssjs?call=list-threads&sub=
${
sub
}
&count=
${
count
}
`
);
}
}
else
if
(
after
)
{
_data
=
await
v4_get
(
`./api/forum.ssjs?call=list-threads&sub=
${
sub
}
&count=
${
count
}
&after=
${
data
.
threads
[
data
.
threads
.
length
-
1
].
id
}
`
);
data
.
total
=
_data
.
total
;
data
.
threads
=
data
.
threads
.
concat
(
_data
.
threads
);
response
=
await
v4_get
(
`./api/forum.ssjs?call=list-threads&sub=
${
sub
}
&count=
${
count
}
&after=
${
data
[
data
.
length
-
1
].
id
}
`
);
data
=
data
.
concat
(
response
.
threads
);
}
else
{
// TO DO: check for NEWER threads than what we have on hand
// fetch however many newer threads there are
// prepend them to the list
}
localStorage
.
setItem
(
`
${
sub
}
-threadList`
,
JSON
.
stringify
(
data
));
lm
.
stop
();
(
_data
||
data
).
threads
.
forEach
(
e
=>
{
const
elem
=
document
.
getElementById
(
'
forum-thread-link-template
'
).
cloneNode
(
true
);
elem
.
id
=
elem
.
id
.
replace
(
/template$/
,
e
.
id
);
elem
.
setAttribute
(
'
href
'
,
`
${
elem
.
getAttribute
(
'
href
'
)}
&thread=
${
e
.
id
}
`
);
elem
.
querySelector
(
'
strong[data-thread-subject]
'
).
innerHTML
=
e
.
subject
;
elem
.
querySelector
(
'
strong[data-thread-from]
'
).
innerHTML
=
e
.
first
.
from
;
elem
.
querySelector
(
'
span[data-thread-date-start]
'
).
innerHTML
=
formatMessageDate
(
e
.
first
.
when_written_time
);
if
(
e
.
messages
>
1
)
{
elem
.
querySelector
(
'
strong[data-message-count]
'
).
innerHTML
=
e
.
messages
-
1
;
if
(
e
.
messages
==
2
)
{
elem
.
querySelector
(
'
span[data-suffix-reply]
'
).
removeAttribute
(
'
hidden
'
);
}
else
{
elem
.
querySelector
(
'
span[data-suffix-replies]
'
).
removeAttribute
(
'
hidden
'
);
}
elem
.
querySelector
(
'
strong[data-last-from]
'
).
innerHTML
=
e
.
last
.
from
;
elem
.
querySelector
(
'
span[data-last-time]
'
).
innerHTML
=
formatMessageDate
(
e
.
last
.
when_written_time
);
elem
.
querySelector
(
'
div[data-replies]
'
).
removeAttribute
(
'
hidden
'
);
}
const
stats
=
elem
.
querySelector
(
'
div[data-stats]
'
);
if
(
e
.
unread
)
{
const
urm
=
stats
.
querySelector
(
'
span[data-unread-messages]
'
);
if
(
urm
!==
null
)
{
// If user is guest, this element will not exist
urm
.
innerHTML
=
e
.
unread
;
if
(
data
.
scan_cfg
&
(
1
<<
1
)
||
data
.
scan_cfg
&
5
||
data
.
scan_cfg
&
(
1
<<
8
))
{
urm
.
classList
.
add
(
'
scanned
'
);
}
else
{
urm
.
classList
.
remove
(
'
scanned
'
);
}
urm
.
removeAttribute
(
'
hidden
'
);
stats
.
removeAttribute
(
'
hidden
'
);
}
}
if
(
e
.
votes
.
total
)
{
if
(
e
.
votes
.
up
.
t
)
{
stats
.
querySelector
(
'
span[data-upvotes]
'
).
innerHTML
=
`
${
e
.
votes
.
up
.
p
}
/
${
e
.
votes
.
up
.
t
}
`
;
stats
.
querySelector
(
'
span[data-upvotes-badge]
'
).
style
.
setProperty
(
'
display
'
,
''
);
}
if
(
e
.
votes
.
down
.
t
)
{
stats
.
querySelector
(
'
span[data-downvotes]
'
).
innerHTML
=
`
${
e
.
votes
.
down
.
p
}
/
${
e
.
votes
.
down
.
t
}
`
;
stats
.
querySelector
(
'
span[data-downvotes-badge]
'
).
style
.
setProperty
(
'
display
'
,
''
);
}
stats
.
removeAttribute
(
'
hidden
'
);
}
elem
.
removeAttribute
(
'
hidden
'
);
document
.
getElementById
(
'
forum-list-container
'
).
appendChild
(
elem
);
});
if
(
response
)
{
response
.
threads
.
forEach
(
e
=>
{
sbbs
.
forum
.
setThread
(
e
);
listThread
(
e
);
});
}
else
{
data
.
forEach
(
listThread
);
}
dlmt
.
removeAttribute
(
'
hidden
'
);
blmt
.
removeAttribute
(
'
disabled
'
);
}
async
function
listGroups
()
{
loading
(
true
);
const
data
=
await
v4_get
(
`./api/forum.ssjs?call=list-groups`
);
loading
(
false
);
// Sub list
data
.
forEach
(
e
=>
{
const
elem
=
document
.
getElementById
(
'
forum-group-link-template
'
).
cloneNode
(
true
);
elem
.
id
=
elem
.
id
.
replace
(
/template$/
,
e
.
index
);
elem
.
setAttribute
(
'
href
'
,
`
${
elem
.
getAttribute
(
'
href
'
)}
&group=
${
e
.
index
}
`
);
elem
.
querySelector
(
'
strong[data-group-name]
'
).
innerHTML
=
e
.
name
;
elem
.
querySelector
(
'
span[data-unread-unscanned]
'
).
innerHTML
=
''
;
elem
.
querySelector
(
'
span[data-unread-scanned]
'
).
innerHTML
=
''
;
elem
.
querySelector
(
'
span[data-group-description]
'
).
innerHTML
=
e
.
description
;
elem
.
querySelector
(
'
span[data-group-sub-count]
'
).
innerHTML
=
e
.
sub_count
;
document
.
getElementById
(
'
forum-list-container
'
).
appendChild
(
elem
);
});
function
showNewestMessage
(
elem
,
msg
)
{
elem
.
querySelector
(
'
strong[data-newest-message-subject]
'
).
innerHTML
=
msg
.
subject
;
elem
.
querySelector
(
'
span[data-newest-message-from]
'
).
innerHTML
=
msg
.
from
;
elem
.
querySelector
(
'
span[data-newest-message-date]
'
).
innerHTML
=
formatMessageDate
(
msg
.
date
);
elem
.
querySelector
(
'
span[data-newest-message-container]
'
).
removeAttribute
(
'
hidden
'
);
}
async
function
onNewestSubMessage
(
sub
,
msg
)
{
const
rec
=
await
sbbs
.
forum
.
getSub
(
sub
);
if
(
rec
!==
undefined
)
{
rec
.
newest_message
=
msg
;
sbbs
.
forum
.
setSub
(
rec
);
}
const
elem
=
document
.
getElementById
(
`forum-sub-link-
${
sub
}
`
);
if
(
elem
!==
null
)
showNewestMessage
(
elem
,
msg
);
}
async
function
listSubs
(
group
)
{
async
function
getNewestMessagePerSub
(
group
)
{
const
data
=
await
v4_get
(
`./api/forum.ssjs?call=get-newest-message-per-sub&group=
${
group
}
`
);
Object
.
entries
(
data
).
forEach
(([
k
,
v
])
=>
onNewestSubMessage
(
k
,
v
));
}
loading
(
true
);
const
data
=
await
v4_get
(
`./api/forum.ssjs?call=list-subs&group=
${
group
}
`
);
loading
(
false
);
function
showSubUnreadCount
(
elem
,
s
,
u
)
{
// sub link element, sub code, { total, scanned, newest }
if
(
u
.
total
-
u
.
scanned
>
0
)
elem
.
querySelector
(
'
span[data-unread-unscanned]
'
).
innerHTML
=
u
.
total
-
u
.
scanned
;
if
(
u
.
scanned
>
0
)
elem
.
querySelector
(
'
span[data-unread-scanned]
'
).
innerHTML
=
u
.
scanned
;
}
data
.
forEach
(
e
=>
{
const
elem
=
document
.
getElementById
(
'
forum-sub-link-template
'
).
cloneNode
(
true
);
elem
.
id
=
elem
.
id
.
replace
(
/template$/
,
e
.
code
);
elem
.
setAttribute
(
'
href
'
,
`
${
elem
.
getAttribute
(
'
href
'
)}
&sub=
${
e
.
code
}
`
);
function
onSubUnreadCount
(
data
)
{
Object
.
entries
(
data
).
forEach
(
async
([
k
,
v
])
=>
{
const
sub
=
await
sbbs
.
forum
.
getSub
(
k
);
if
(
sub
!==
undefined
)
{
sub
.
unread
=
v
;
await
sbbs
.
forum
.
setSub
(
sub
);
}
const
elem
=
document
.
getElementById
(
`forum-sub-link-
${
k
}
`
);
if
(
elem
!==
null
)
showSubUnreadCount
(
elem
,
k
,
v
);
});
}
function
onSubList
(
data
)
{
data
.
sort
((
a
,
b
)
=>
a
.
index
<
b
.
index
?
-
1
:
1
).
forEach
(
e
=>
{
let
elem
;
let
append
=
false
;
const
elemId
=
`forum-sub-link-
${
e
.
code
}
`
;
if
((
elem
=
document
.
getElementById
(
elemId
))
===
null
)
{
elem
=
document
.
getElementById
(
'
forum-sub-link-template
'
).
cloneNode
(
true
);
elem
.
id
=
elem
.
id
.
replace
(
/template$/
,
e
.
code
);
elem
.
setAttribute
(
'
href
'
,
`
${
elem
.
getAttribute
(
'
href
'
)}
&sub=
${
e
.
code
}
`
);
append
=
true
;
}
elem
.
querySelector
(
'
strong[data-sub-name]
'
).
innerHTML
=
e
.
name
;
elem
.
querySelector
(
'
p[data-sub-description]
'
).
innerHTML
=
e
.
description
;
document
.
getElementById
(
'
forum-list-container
'
).
appendChild
(
elem
);
showNewestMessage
(
elem
,
e
.
newest
);
if
(
e
.
unread
!==
null
)
showSubUnreadCount
(
elem
,
e
.
code
,
e
.
unread
);
if
(
append
)
document
.
getElementById
(
'
forum-list-container
'
).
appendChild
(
elem
);
});
}
function
onNewestSubMessage
(
sub
,
msg
)
{
const
elem
=
document
.
getElementById
(
`forum-sub-link-
${
sub
}
`
);
elem
.
querySelector
(
'
strong[data-newest-message-subject]
'
).
innerHTML
=
msg
.
subject
;
elem
.
querySelector
(
'
span[data-newest-message-from]
'
).
innerHTML
=
msg
.
from
;
elem
.
querySelector
(
'
span[data-newest-message-date]
'
).
innerHTML
=
formatMessageDate
(
msg
.
date
);
elem
.
querySelector
(
'
span[data-newest-message-container]
'
).
removeAttribute
(
'
hidden
'
);
}
async
function
listSubs
(
group
)
{
const
lm
=
new
LoadingMessage
();
lm
.
start
();
let
data
=
await
sbbs
.
forum
.
getSubs
(
v
=>
v
.
grp_index
===
group
);
if
(
data
===
undefined
||
!
data
.
length
)
{
data
=
await
v4_get
(
`./api/forum.ssjs?call=list-subs&group=
${
group
}
`
);
data
.
forEach
(
async
e
=>
await
sbbs
.
forum
.
setSub
(
e
));
}
else
{
// TO DO: add a TTL for this data instead of refreshing every time
v4_get
(
`./api/forum.ssjs?call=list-subs&group=
${
group
}
`
).
then
(
onSubList
);
}
lm
.
stop
();
onSubList
(
data
);
async
function
getNewestMessagePerSub
(
group
)
{
const
data
=
await
v4_get
(
`./api/forum.ssjs?call=get-newest-message-per-sub&group=
${
group
}
`
);
Object
.
entries
(
data
).
forEach
(([
k
,
v
])
=>
{
onNewestSubMessage
(
k
,
v
)
});
}
function
formatMessageDate
(
t
)
{
return
(
new
Date
(
t
*
1000
)).
toLocaleString
();
// Group list
function
showGroupUnreadCount
(
elem
,
u
)
{
if
(
u
.
total
-
u
.
scanned
>
0
)
elem
.
querySelector
(
'
span[data-unread-unscanned]
'
).
innerHTML
=
u
.
total
-
u
.
scanned
;
if
(
u
.
scanned
>
0
)
elem
.
querySelector
(
'
span[data-unread-scanned]
'
).
innerHTML
=
u
.
scanned
;
}
function
onGroupUnreadCount
(
data
)
{
Object
.
entries
(
data
).
forEach
(([
k
,
v
])
=>
{
Object
.
entries
(
data
).
forEach
(
async
([
k
,
v
])
=>
{
const
elem
=
document
.
getElementById
(
`forum-group-link-
${
k
}
`
);
if
(
v
.
total
-
v
.
scanned
>
0
)
elem
.
querySelector
(
'
span[data-unread-unscanned]
'
).
innerHTML
=
v
.
total
-
v
.
scanned
;
if
(
v
.
scanned
>
0
)
elem
.
querySelector
(
'
span[data-unread-scanned]
'
).
innerHTML
=
v
.
scanned
;
showGroupUnreadCount
(
elem
,
v
);
const
grp
=
await
sbbs
.
forum
.
getGroup
(
parseInt
(
k
,
10
));
if
(
grp
!==
undefined
)
{
grp
.
unread
=
v
;
await
sbbs
.
forum
.
setGroup
(
grp
);
}
});
}
function
onSubUnreadCount
(
data
)
{
Object
.
entries
(
data
).
forEach
(([
k
,
v
])
=>
{
const
elem
=
document
.
getElementById
(
`forum-sub-link-
${
k
}
`
);
if
(
v
.
total
-
v
.
scanned
>
0
)
elem
.
querySelector
(
'
span[data-unread-unscanned]
'
).
innerHTML
=
v
.
total
-
v
.
scanned
;
if
(
v
.
scanned
>
0
)
elem
.
querySelector
(
'
span[data-unread-scanned]
'
).
innerHTML
=
v
.
scanned
;
if
(
v
.
newest
)
onNewestSubMessage
(
k
,
v
.
newest
);
function
onGroupList
(
data
)
{
data
.
forEach
(
e
=>
{
let
elem
;
let
append
=
false
;
const
elemId
=
`forum-group-link-
${
e
.
index
}
`
;
if
((
elem
=
document
.
getElementById
(
elemId
))
===
null
)
{
elem
=
document
.
getElementById
(
'
forum-group-link-template
'
).
cloneNode
(
true
);
elem
.
id
=
elem
.
id
.
replace
(
/template$/
,
e
.
index
);
elem
.
setAttribute
(
'
href
'
,
`
${
elem
.
getAttribute
(
'
href
'
)}
&group=
${
e
.
index
}
`
);
append
=
true
;
}
elem
.
querySelector
(
'
strong[data-group-name]
'
).
innerHTML
=
e
.
name
;
elem
.
querySelector
(
'
span[data-unread-unscanned]
'
).
innerHTML
=
''
;
elem
.
querySelector
(
'
span[data-unread-scanned]
'
).
innerHTML
=
''
;
elem
.
querySelector
(
'
span[data-group-description]
'
).
innerHTML
=
e
.
description
;
elem
.
querySelector
(
'
span[data-group-sub-count]
'
).
innerHTML
=
e
.
sub_count
;
if
(
e
.
unread
!==
null
)
showGroupUnreadCount
(
elem
,
e
.
unread
);
if
(
append
)
document
.
getElementById
(
'
forum-list-container
'
).
appendChild
(
elem
);
});
}
async
function
listGroups
()
{
const
lm
=
new
LoadingMessage
();
lm
.
start
();
let
data
=
await
sbbs
.
forum
.
getGroups
();
if
(
data
===
undefined
)
{
console
.
debug
(
'
groups not in cache, fetching
'
);
data
=
await
v4_get
(
'
./api/forum.ssjs?call=list-groups
'
);
data
.
forEach
(
async
e
=>
await
sbbs
.
forum
.
setGroup
(
e
));
}
else
{
// TO DO: add a TTL for this data instead of refreshing every time
v4_get
(
'
./api/forum.ssjs?call=list-groups
'
).
then
(
async
data
=>
{
for
(
const
e
of
data
)
{
await
sbbs
.
forum
.
setGroup
(
e
);
}
onGroupList
(
data
);
});
}
onGroupList
(
data
);
lm
.
stop
();
}
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment