Files
coms/client/public/data.js
2026-02-14 16:02:53 -05:00

195 lines
3.8 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// coms/client/public/data.js
// Data module: holds the inmemory threads, notices and reply state
// Map of all messages and notices by ID
// Clients own session ID
let myId = null;
const threads = new Map();
// Map of connected users by unique ID
const users = new Map();
// Ordered list of rootlevel IDs (messages and notices)
const rootIds = [];
// Negative counter to generate unique IDs for notices
let noticeCounter = -1;
// ID of the message were currently replying to (or null)
let replyTo = null;
// ID of the message currently focused for navigation (or null)
let focusedId = null;
/**
* Set the focused message ID (or null to clear).
* @param {number|null} id
*/
function setFocused(id) {
focusedId = id;
}
/**
* Get the currently focused message ID.
* @returns {number|null}
*/
function getFocused() {
return focusedId;
}
/**
* Clear the current focus.
*/
function clearFocused() {
focusedId = null;
}
// -- User management API ---
/**
* Register a user with their unique ID.
* @param {number} id
* @param {string} name
*/
function addUser(id, name) {
users.set(id, name);
}
/**
* Remove a user by their ID.
* @param {number} id
*/
function removeUser(id) {
users.delete(id);
}
/**
* Update a users name.
* @param {number} id
* @param {string} name
*/
function updateUser(id, name) {
users.set(id, name);
}
/**
* Get a list of {id, name} objects for all users.
* @returns {{id:number, name:string}[]}
*/
function getUsers() {
return Array.from(users.entries()).map(([id, name]) => ({ id, name }));
}
/**
* Get grouped display strings: e.g. ["Anon (3x)", "Alice (1x)"]
* @returns {string[]}
*/
function getGroupedUsers() {
const counts = {};
for (const name of users.values()) {
counts[name] = (counts[name] || 0) + 1;
}
return Object.entries(counts).map(([name, count]) => {
const nameSpan = `<span class="name">${new Option(name).innerHTML}</span>`;
return count > 1 ? `${nameSpan} (${count}x)` : nameSpan;
});
}
/**
* Add a new chat message to the thread structure.
* @param {{id: number, username: string, content: string, ts: number, parent?: number}} msg
*/
function addMessage({ id, username, content, ts, parent = null }) {
threads.set(id, { id, username, content, ts, parent, children: [] });
if (parent !== null && threads.has(parent)) {
threads.get(parent).children.push(id);
} else {
rootIds.push(id);
}
}
/**
* Insert a system notice as a rootlevel thread item.
* @param {string} content — HTML or plain text for the notice
*/
function addNotice(content) {
const ts = Math.floor(Date.now() / 1000);
const id = noticeCounter--;
threads.set(id, {
id,
username: "",
content,
ts,
parent: null,
children: [],
});
rootIds.push(id);
}
/**
* Reset all data (useful for unit tests or full reinitialization).
*/
function clearData() {
threads.clear();
rootIds.length = 0;
noticeCounter = -1;
replyTo = null;
}
/** @returns {Map<number,object>} The threads map. */
function getThreads() {
return threads;
}
/** @returns {number[]} The ordered list of rootlevel IDs. */
function getRootIds() {
return rootIds;
}
/**
* Set this clients own session ID.
* @param {number} id
*/
function setMyId(id) {
myId = id;
}
/**
* Get this clients own session ID.
* @returns {number|null}
*/
function getMyId() {
return myId;
}
/** @returns {number|null} The current replyto ID. */
function getReplyTo() {
return replyTo;
}
/** @param {number|null} id — Set the current replyto ID. */
function setReplyTo(id) {
replyTo = id;
}
export {
threads,
rootIds,
users,
addMessage,
addNotice,
addUser,
removeUser,
updateUser,
getUsers,
getGroupedUsers,
clearData,
getThreads,
getRootIds,
getReplyTo,
setReplyTo,
getFocused,
setFocused,
clearFocused,
setMyId,
getMyId,
};