asdkjlfhlaskjdhf

This commit is contained in:
2026-03-11 01:20:31 -04:00
parent 2fea81d46b
commit 3160d96c15
5 changed files with 25 additions and 58 deletions

View File

@@ -29,10 +29,8 @@ document.addEventListener("DOMContentLoaded", () => {
primeNotifications(); primeNotifications();
const defaultName = "Anon"; const defaultName = "Anon";
const MAX_NAME_LEN = 15; // server limit is NAME_MAX_LENGTH-1 (15 chars) const MAX_NAME_LEN = 15;
// Fetch WebSocket domain from the client server so deployments can point to a
// remote websocket host without rebuilding the bundle.
fetch("/ws-domain") fetch("/ws-domain")
.then((res) => res.json()) .then((res) => res.json())
.then(({ domain }) => domain || "") .then(({ domain }) => domain || "")
@@ -118,7 +116,8 @@ document.addEventListener("DOMContentLoaded", () => {
input.focus(); input.focus();
}); });
// Global Escape handler: clear reply context, focus input, and clear focused message. // Global Escape handler: clear reply context, focus input, and clear
// focused message.
document.addEventListener("keydown", (e) => { document.addEventListener("keydown", (e) => {
if (e.key === "Escape") { if (e.key === "Escape") {
setReplyTo(null); setReplyTo(null);

View File

@@ -1,50 +1,41 @@
// coms/client/public/data.js
// Data module: holds the inmemory threads, notices and reply state
import { notifyNotice } from "./notifications.js"; import { notifyNotice } from "./notifications.js";
// Map of all messages and notices by ID (string IDs) // Clients own session ID.
// Clients own session ID
let myId = null; let myId = null;
// Map of all messages and notices by ID (string IDs).
const threads = new Map(); const threads = new Map();
// Map of connected users by unique ID // Map of connected users by unique ID.
const users = new Map(); const users = new Map();
// Ordered list of rootlevel IDs (messages and notices, stored as strings) // Ordered list of rootlevel IDs (messages and notices, stored as strings).
const rootIds = []; const rootIds = [];
// Negative counter to generate unique IDs for notices // Negative counter to generate unique IDs for notices.
let noticeCounter = -1; let noticeCounter = -1;
// ID of the message were currently replying to (string or null) // ID of the message were currently replying to (string or null).
let replyTo = null; let replyTo = null;
// ID of the message currently focused for navigation (string or null) // ID of the message currently focused for navigation (string or null).
let focusedId = null; let focusedId = null;
/** // Set the focused message ID (or null to clear).
* Set the focused message ID (or null to clear).
* @param {string|null} id
*/
function setFocused(id) { function setFocused(id) {
focusedId = id; focusedId = id;
} }
/**
* Get the currently focused message ID. // Get the currently focused message ID.
* @returns {string|null}
*/
function getFocused() { function getFocused() {
return focusedId; return focusedId;
} }
/**
* Clear the current focus.
*/
function clearFocused() { function clearFocused() {
focusedId = null; focusedId = null;
} }
// -- User management API --- // USER MANAGEMENT STUFF.
/** /**
* Register a user with their unique ID. * Register a user with their unique ID.

View File

@@ -1,7 +1,3 @@
// Simple notification helpers for the chat client.
const APP_NAME = "COMS";
function supportsNotifications() { function supportsNotifications() {
return typeof Notification !== "undefined"; return typeof Notification !== "undefined";
} }
@@ -12,9 +8,6 @@ function stripHtml(input) {
return div.textContent || div.innerText || ""; return div.textContent || div.innerText || "";
} }
/**
* Ask for permission if not already granted/denied.
*/
function primeNotifications() { function primeNotifications() {
if (!supportsNotifications()) return; if (!supportsNotifications()) return;
if (Notification.permission === "default") { if (Notification.permission === "default") {
@@ -34,14 +27,10 @@ function showNotification(title, body) {
} }
} }
/**
* Notify the user of a system notice.
* @param {string} content - HTML or text content of the notice.
*/
function notifyNotice(content) { function notifyNotice(content) {
const text = stripHtml(content); const text = stripHtml(content);
if (!text) return; if (!text) return;
showNotification(`${APP_NAME} notice`, text); showNotification(`COMS`, text);
} }
/** /**
@@ -53,7 +42,7 @@ function notifyDirectReply(authorName, content) {
const text = stripHtml(content); const text = stripHtml(content);
if (!text) return; if (!text) return;
const name = authorName || "Anon"; const name = authorName || "Anon";
showNotification(`${name} replied to your thread`, text); showNotification(`${name} replied`, text);
} }
export { primeNotifications, notifyNotice, notifyDirectReply }; export { primeNotifications, notifyNotice, notifyDirectReply };

View File

@@ -1,11 +1,7 @@
// Render module: handles chat UI rendering of messages and notices // this one sucked.
import { getThreads, getRootIds, getReplyTo, getFocused } from "./data.js"; import { getThreads, getRootIds, getReplyTo, getFocused } from "./data.js";
/** // Render the chat history and input container into the provided chat element.
* Render the chat history and input container into the provided chat element.
* @param {HTMLElement} chatEl - The container element for chat entries.
* @param {HTMLElement} inputContainer - The message input area to append at bottom.
*/
export function renderChat(chatEl, inputContainer) { export function renderChat(chatEl, inputContainer) {
// Clear existing content. // Clear existing content.
chatEl.innerHTML = ""; chatEl.innerHTML = "";
@@ -49,7 +45,7 @@ export function renderChat(chatEl, inputContainer) {
const shortTimestamp = `${h}:${m} ${ampm}`; const shortTimestamp = `${h}:${m} ${ampm}`;
const tsSpan = `<span class="ts" title="${fullTimestamp}">${shortTimestamp}</span>`; const tsSpan = `<span class="ts" title="${fullTimestamp}">${shortTimestamp}</span>`;
// Distinguish notice vs normal message. // Distinguish notices and normal messages.
if (msg.username) { if (msg.username) {
div.classList.add("msg"); div.classList.add("msg");
if (getFocused() === id) div.classList.add("focused"); if (getFocused() === id) div.classList.add("focused");
@@ -59,7 +55,7 @@ export function renderChat(chatEl, inputContainer) {
div.innerHTML = `${tsSpan} ${msg.content}`; div.innerHTML = `${tsSpan} ${msg.content}`;
} }
// Append to chat and render children. // Append to chat and render the children.
chatEl.appendChild(div); chatEl.appendChild(div);
msg.children.forEach((childId) => renderNode(childId, depth + 1)); msg.children.forEach((childId) => renderNode(childId, depth + 1));
} }
@@ -91,14 +87,12 @@ export function renderChat(chatEl, inputContainer) {
} }
} }
// Scroll to bottom. // Scroll to bottom. Or at least try. Let the browser know that is our
// intention. May or may not actually work.
chatEl.scrollTop = chatEl.scrollHeight; chatEl.scrollTop = chatEl.scrollHeight;
const input = inputContainer.querySelector("input"); const input = inputContainer.querySelector("input");
if (input) { if (input) {
input.focus(); input.focus();
// Ensure inputContainer margin resets if at root. if (replyTo === null) inputContainer.style.marginLeft = "0";
if (replyTo === null) {
inputContainer.style.marginLeft = "0";
}
} }
} }

View File

@@ -1,9 +1,3 @@
/**
* coms/client/public/wsModule.js
* WebSocket module: handles connection, dispatching incoming packets to
* data and render modules, and provides a sendMessage API.
*/
import { import {
addMessage, addMessage,
addNotice, addNotice,