Some tyhigns.
This commit is contained in:
@@ -29,118 +29,127 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
const defaultName = "Anon";
|
||||
const MAX_NAME_LEN = 15; // server limit is NAME_MAX_LENGTH-1 (15 chars)
|
||||
|
||||
const { socket, sendMessage, sendName } = initWebSocket(
|
||||
defaultName,
|
||||
chat,
|
||||
inputContainer,
|
||||
usersList,
|
||||
);
|
||||
|
||||
// Renames.
|
||||
nameButton.addEventListener("click", () => {
|
||||
const newName = nameInput.value.trim() || defaultName;
|
||||
if (newName.length > MAX_NAME_LEN) {
|
||||
addNotice(
|
||||
`<span class="err">Name may be at most ${MAX_NAME_LEN} characters.</span>`,
|
||||
// Fetch WebSocket domain from the client server so deployments can point to a
|
||||
// remote websocket host without rebuilding the bundle.
|
||||
fetch("/ws-domain")
|
||||
.then((res) => res.json())
|
||||
.then(({ domain }) => domain || "")
|
||||
.catch(() => "")
|
||||
.then((wsDomain) => {
|
||||
const { socket, sendMessage, sendName } = initWebSocket(
|
||||
defaultName,
|
||||
chat,
|
||||
inputContainer,
|
||||
usersList,
|
||||
wsDomain,
|
||||
);
|
||||
renderChat(chat, inputContainer);
|
||||
nameInput.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
sendName(newName);
|
||||
updateUser(getMyId(), newName);
|
||||
const groups = getGroupedUsers();
|
||||
usersList.innerHTML = "Online: " + groups.join(", ");
|
||||
// Renames.
|
||||
nameButton.addEventListener("click", () => {
|
||||
const newName = nameInput.value.trim() || defaultName;
|
||||
if (newName.length > MAX_NAME_LEN) {
|
||||
addNotice(
|
||||
`<span class="err">Name may be at most ${MAX_NAME_LEN} characters.</span>`,
|
||||
);
|
||||
renderChat(chat, inputContainer);
|
||||
nameInput.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
nameInput.value = "";
|
||||
nameInput.placeholder = `Name: ${newName}`;
|
||||
input.focus();
|
||||
});
|
||||
sendName(newName);
|
||||
updateUser(getMyId(), newName);
|
||||
const groups = getGroupedUsers();
|
||||
usersList.innerHTML = "Online: " + groups.join(", ");
|
||||
|
||||
// Enter to set name.
|
||||
nameInput.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Enter") nameButton.click();
|
||||
});
|
||||
nameInput.value = "";
|
||||
nameInput.placeholder = `Name: ${newName}`;
|
||||
input.focus();
|
||||
});
|
||||
|
||||
// Button to send.
|
||||
sendButton.addEventListener("click", () => {
|
||||
const text = input.value.trim();
|
||||
if (!text) return;
|
||||
sendMessage(text);
|
||||
input.value = "";
|
||||
input.focus();
|
||||
});
|
||||
// Enter to set name.
|
||||
nameInput.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Enter") nameButton.click();
|
||||
});
|
||||
|
||||
// Enter to send and escape to go to root.
|
||||
input.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Enter") {
|
||||
sendButton.click();
|
||||
} else if (e.key === "Escape") {
|
||||
setReplyTo(null);
|
||||
input.placeholder = "";
|
||||
renderChat(chat, inputContainer);
|
||||
input.focus();
|
||||
}
|
||||
});
|
||||
// Button to send.
|
||||
sendButton.addEventListener("click", () => {
|
||||
const text = input.value.trim();
|
||||
if (!text) return;
|
||||
sendMessage(text);
|
||||
input.value = "";
|
||||
input.focus();
|
||||
});
|
||||
|
||||
// Click message to reply.
|
||||
chat.addEventListener("click", (e) => {
|
||||
const msgDiv = e.target.closest(".msg");
|
||||
if (!msgDiv) return;
|
||||
const id = msgDiv.dataset.id;
|
||||
if (!id) return;
|
||||
const threads = getThreads();
|
||||
const author = threads.get(id)?.username;
|
||||
setReplyTo(id);
|
||||
setFocused(id);
|
||||
input.placeholder = author ? `Replying to @${author}` : "";
|
||||
renderChat(chat, inputContainer);
|
||||
input.focus();
|
||||
});
|
||||
// Enter to send and escape to go to root.
|
||||
input.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Enter") {
|
||||
sendButton.click();
|
||||
} else if (e.key === "Escape") {
|
||||
setReplyTo(null);
|
||||
input.placeholder = "";
|
||||
renderChat(chat, inputContainer);
|
||||
input.focus();
|
||||
}
|
||||
});
|
||||
|
||||
// Go back to root.
|
||||
rootButton.addEventListener("click", () => {
|
||||
setReplyTo(null);
|
||||
clearFocused();
|
||||
input.placeholder = "";
|
||||
renderChat(chat, inputContainer);
|
||||
input.focus();
|
||||
});
|
||||
// Click message to reply.
|
||||
chat.addEventListener("click", (e) => {
|
||||
const msgDiv = e.target.closest(".msg");
|
||||
if (!msgDiv) return;
|
||||
const id = msgDiv.dataset.id;
|
||||
if (!id) return;
|
||||
const threads = getThreads();
|
||||
const author = threads.get(id)?.username;
|
||||
setReplyTo(id);
|
||||
setFocused(id);
|
||||
input.placeholder = author ? `Replying to @${author}` : "";
|
||||
renderChat(chat, inputContainer);
|
||||
input.focus();
|
||||
});
|
||||
|
||||
// Global Escape handler: clear reply context, focus input, and clear focused message.
|
||||
document.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Escape") {
|
||||
setReplyTo(null);
|
||||
clearFocused();
|
||||
input.placeholder = "";
|
||||
renderChat(chat, inputContainer);
|
||||
input.focus();
|
||||
}
|
||||
});
|
||||
// Go back to root.
|
||||
rootButton.addEventListener("click", () => {
|
||||
setReplyTo(null);
|
||||
clearFocused();
|
||||
input.placeholder = "";
|
||||
renderChat(chat, inputContainer);
|
||||
input.focus();
|
||||
});
|
||||
|
||||
// Arrow key navigation for focused messages (also sets reply target).
|
||||
document.addEventListener("keydown", (e) => {
|
||||
if (e.key === "ArrowDown" || e.key === "ArrowUp") {
|
||||
const msgs = Array.from(chat.querySelectorAll("div.msg"));
|
||||
if (!msgs.length) return;
|
||||
let idx = msgs.findIndex((div) => div.dataset.id === getFocused());
|
||||
if (idx === -1) {
|
||||
idx = e.key === "ArrowDown" ? -1 : msgs.length;
|
||||
}
|
||||
idx =
|
||||
e.key === "ArrowDown"
|
||||
? Math.min(msgs.length - 1, idx + 1)
|
||||
: Math.max(0, idx - 1);
|
||||
const newId = msgs[idx].dataset.id;
|
||||
setFocused(newId);
|
||||
setReplyTo(newId); // Move input box under focused message.
|
||||
const threads = getThreads();
|
||||
const author = threads.get(newId)?.username;
|
||||
input.placeholder = author ? `Replying to @${author}` : "";
|
||||
renderChat(chat, inputContainer);
|
||||
const newDiv = chat.querySelector(`div[data-id="${newId}"]`);
|
||||
if (newDiv) newDiv.scrollIntoView({ block: "nearest" });
|
||||
}
|
||||
});
|
||||
// Global Escape handler: clear reply context, focus input, and clear focused message.
|
||||
document.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Escape") {
|
||||
setReplyTo(null);
|
||||
clearFocused();
|
||||
input.placeholder = "";
|
||||
renderChat(chat, inputContainer);
|
||||
input.focus();
|
||||
}
|
||||
});
|
||||
|
||||
// Arrow key navigation for focused messages (also sets reply target).
|
||||
document.addEventListener("keydown", (e) => {
|
||||
if (e.key === "ArrowDown" || e.key === "ArrowUp") {
|
||||
const msgs = Array.from(chat.querySelectorAll("div.msg"));
|
||||
if (!msgs.length) return;
|
||||
let idx = msgs.findIndex((div) => div.dataset.id === getFocused());
|
||||
if (idx === -1) {
|
||||
idx = e.key === "ArrowDown" ? -1 : msgs.length;
|
||||
}
|
||||
idx =
|
||||
e.key === "ArrowDown"
|
||||
? Math.min(msgs.length - 1, idx + 1)
|
||||
: Math.max(0, idx - 1);
|
||||
const newId = msgs[idx].dataset.id;
|
||||
setFocused(newId);
|
||||
setReplyTo(newId); // Move input box under focused message.
|
||||
const threads = getThreads();
|
||||
const author = threads.get(newId)?.username;
|
||||
input.placeholder = author ? `Replying to @${author}` : "";
|
||||
renderChat(chat, inputContainer);
|
||||
const newDiv = chat.querySelector(`div[data-id="${newId}"]`);
|
||||
if (newDiv) newDiv.scrollIntoView({ block: "nearest" });
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user