Update static/js/02-chat.js
This commit is contained in:
parent
f684f6ff69
commit
c5ba80129e
@ -2,6 +2,29 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
window.Glow = window.Glow || {};
|
window.Glow = window.Glow || {};
|
||||||
|
|
||||||
|
Glow.EMOJI_SHORTCODES = {
|
||||||
|
smile: "🙂",
|
||||||
|
grin: "😁",
|
||||||
|
joy: "😂",
|
||||||
|
heart: "❤️",
|
||||||
|
fire: "🔥",
|
||||||
|
thumbsup: "👍",
|
||||||
|
thumbsup: "👍",
|
||||||
|
clap: "👏",
|
||||||
|
eyes: "👀",
|
||||||
|
check: "✅",
|
||||||
|
rocket: "🚀",
|
||||||
|
thinking: "🤔",
|
||||||
|
wave: "👋",
|
||||||
|
tada: "🎉",
|
||||||
|
sparkles: "✨",
|
||||||
|
cry: "😢",
|
||||||
|
laugh: "😄",
|
||||||
|
sob: "😭",
|
||||||
|
star: "⭐",
|
||||||
|
warning: "⚠️"
|
||||||
|
};
|
||||||
|
|
||||||
Glow.clearMessages = () => {
|
Glow.clearMessages = () => {
|
||||||
Glow.state.lastSeenId = 0;
|
Glow.state.lastSeenId = 0;
|
||||||
Glow.state.knownMessageIds.clear();
|
Glow.state.knownMessageIds.clear();
|
||||||
@ -446,7 +469,7 @@ Glow.handleSlashCommand = async text => {
|
|||||||
if (!trimmed.startsWith("/")) return false;
|
if (!trimmed.startsWith("/")) return false;
|
||||||
|
|
||||||
if (trimmed === "/shrug") {
|
if (trimmed === "/shrug") {
|
||||||
Glow.els.messageInput.value = "¯\\_(ツ)_/¯";
|
Glow.els.messageInput.value = "¯\\_(ツ)_/¯";
|
||||||
Glow.autoResizeComposer();
|
Glow.autoResizeComposer();
|
||||||
Glow.updateMessageCount();
|
Glow.updateMessageCount();
|
||||||
return true;
|
return true;
|
||||||
@ -592,9 +615,6 @@ Glow.buildAttachments = attachments => {
|
|||||||
link.rel = "noopener noreferrer";
|
link.rel = "noopener noreferrer";
|
||||||
link.download = attachment.original_name;
|
link.download = attachment.original_name;
|
||||||
link.textContent = `Attachment: ${attachment.original_name} (${Glow.formatBytes(attachment.size_bytes)})`;
|
link.textContent = `Attachment: ${attachment.original_name} (${Glow.formatBytes(attachment.size_bytes)})`;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
list.append(link);
|
list.append(link);
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
@ -605,11 +625,13 @@ Glow.buildMessage = (message, grouped = false) => {
|
|||||||
const isOwnMessage =
|
const isOwnMessage =
|
||||||
Glow.state.currentUser &&
|
Glow.state.currentUser &&
|
||||||
Number(message.user_id) === Number(Glow.state.currentUser.id);
|
Number(message.user_id) === Number(Glow.state.currentUser.id);
|
||||||
|
const isDmView = Boolean(Glow.state.activeDm);
|
||||||
|
|
||||||
row.className =
|
row.className =
|
||||||
`message-row${isOwnMessage ? " self" : ""}` +
|
`message-row${isOwnMessage ? " self" : ""}` +
|
||||||
`${grouped ? " grouped" : ""}` +
|
`${grouped ? " grouped" : ""}` +
|
||||||
`${message.is_pinned ? " pinned" : ""}`;
|
`${message.is_pinned ? " pinned" : ""}` +
|
||||||
|
`${isDmView ? " is-dm-view" : ""}`;
|
||||||
|
|
||||||
row.dataset.messageId = String(message.id);
|
row.dataset.messageId = String(message.id);
|
||||||
row.dataset.userId = String(message.user_id);
|
row.dataset.userId = String(message.user_id);
|
||||||
@ -647,9 +669,9 @@ Glow.buildMessage = (message, grouped = false) => {
|
|||||||
|
|
||||||
if (Glow.reactions?.enabled !== false) {
|
if (Glow.reactions?.enabled !== false) {
|
||||||
const react = document.createElement("button");
|
const react = document.createElement("button");
|
||||||
react.className = "reaction-trigger";
|
react.className = "reaction-trigger primary";
|
||||||
react.type = "button";
|
react.type = "button";
|
||||||
react.textContent = "😊";
|
react.textContent = "😊";
|
||||||
react.setAttribute("aria-label", "Add reaction");
|
react.setAttribute("aria-label", "Add reaction");
|
||||||
react.addEventListener("click", () => {
|
react.addEventListener("click", () => {
|
||||||
Glow.openReactionPopup?.(message);
|
Glow.openReactionPopup?.(message);
|
||||||
@ -659,7 +681,7 @@ Glow.buildMessage = (message, grouped = false) => {
|
|||||||
|
|
||||||
if (!message.parent_message_id) {
|
if (!message.parent_message_id) {
|
||||||
const thread = document.createElement("button");
|
const thread = document.createElement("button");
|
||||||
thread.className = "message-action";
|
thread.className = "message-action primary";
|
||||||
thread.type = "button";
|
thread.type = "button";
|
||||||
const replyCount = Number(message.thread_reply_count) || 0;
|
const replyCount = Number(message.thread_reply_count) || 0;
|
||||||
thread.textContent =
|
thread.textContent =
|
||||||
@ -675,7 +697,7 @@ Glow.buildMessage = (message, grouped = false) => {
|
|||||||
|
|
||||||
if (Glow.canEditMessage(message)) {
|
if (Glow.canEditMessage(message)) {
|
||||||
const edit = document.createElement("button");
|
const edit = document.createElement("button");
|
||||||
edit.className = "message-action";
|
edit.className = "message-action secondary";
|
||||||
edit.type = "button";
|
edit.type = "button";
|
||||||
edit.textContent = "Edit";
|
edit.textContent = "Edit";
|
||||||
edit.addEventListener("click", () => {
|
edit.addEventListener("click", () => {
|
||||||
@ -685,7 +707,7 @@ Glow.buildMessage = (message, grouped = false) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const copy = document.createElement("button");
|
const copy = document.createElement("button");
|
||||||
copy.className = "message-action";
|
copy.className = "message-action secondary";
|
||||||
copy.type = "button";
|
copy.type = "button";
|
||||||
copy.textContent = "Copy";
|
copy.textContent = "Copy";
|
||||||
copy.addEventListener("click", () => {
|
copy.addEventListener("click", () => {
|
||||||
@ -693,11 +715,10 @@ Glow.buildMessage = (message, grouped = false) => {
|
|||||||
});
|
});
|
||||||
actions.append(copy);
|
actions.append(copy);
|
||||||
|
|
||||||
|
|
||||||
const urls = Glow.extractUrls(message.text);
|
const urls = Glow.extractUrls(message.text);
|
||||||
if (urls.length) {
|
if (urls.length) {
|
||||||
const copyUrl = document.createElement("button");
|
const copyUrl = document.createElement("button");
|
||||||
copyUrl.className = "message-action";
|
copyUrl.className = "message-action secondary";
|
||||||
copyUrl.type = "button";
|
copyUrl.type = "button";
|
||||||
copyUrl.textContent = "URL";
|
copyUrl.textContent = "URL";
|
||||||
copyUrl.addEventListener("click", () => {
|
copyUrl.addEventListener("click", () => {
|
||||||
@ -707,7 +728,7 @@ Glow.buildMessage = (message, grouped = false) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const receipts = document.createElement("button");
|
const receipts = document.createElement("button");
|
||||||
receipts.className = "message-action";
|
receipts.className = "message-action secondary";
|
||||||
receipts.type = "button";
|
receipts.type = "button";
|
||||||
receipts.textContent = `Seen ${Number(message.read_receipt_count) || 0}`;
|
receipts.textContent = `Seen ${Number(message.read_receipt_count) || 0}`;
|
||||||
receipts.addEventListener("click", () => Glow.openReceiptDetails(message));
|
receipts.addEventListener("click", () => Glow.openReceiptDetails(message));
|
||||||
@ -715,9 +736,9 @@ Glow.buildMessage = (message, grouped = false) => {
|
|||||||
|
|
||||||
if (Glow.canModerate()) {
|
if (Glow.canModerate()) {
|
||||||
const remove = document.createElement("button");
|
const remove = document.createElement("button");
|
||||||
remove.className = "admin-delete";
|
remove.className = "admin-delete secondary";
|
||||||
remove.type = "button";
|
remove.type = "button";
|
||||||
remove.textContent = "×";
|
remove.textContent = "×";
|
||||||
remove.setAttribute("aria-label", "Delete message");
|
remove.setAttribute("aria-label", "Delete message");
|
||||||
remove.addEventListener("click", () => {
|
remove.addEventListener("click", () => {
|
||||||
Glow.deleteMessage(message.id);
|
Glow.deleteMessage(message.id);
|
||||||
@ -729,6 +750,7 @@ Glow.buildMessage = (message, grouped = false) => {
|
|||||||
bubble.className = "message-bubble";
|
bubble.className = "message-bubble";
|
||||||
|
|
||||||
const text = document.createElement("div");
|
const text = document.createElement("div");
|
||||||
|
text.className = "message-text";
|
||||||
text.textContent = message.text;
|
text.textContent = message.text;
|
||||||
bubble.append(text);
|
bubble.append(text);
|
||||||
|
|
||||||
@ -748,7 +770,10 @@ Glow.buildMessage = (message, grouped = false) => {
|
|||||||
? [message.attachment]
|
? [message.attachment]
|
||||||
: [];
|
: [];
|
||||||
if (attachments.length) {
|
if (attachments.length) {
|
||||||
bubble.append(Glow.buildAttachments(attachments));
|
const mediaSection = document.createElement("div");
|
||||||
|
mediaSection.className = "message-media-section";
|
||||||
|
mediaSection.append(Glow.buildAttachments(attachments));
|
||||||
|
bubble.append(mediaSection);
|
||||||
}
|
}
|
||||||
|
|
||||||
Glow.renderReactionBar(message, bubble);
|
Glow.renderReactionBar(message, bubble);
|
||||||
@ -1079,6 +1104,38 @@ Glow.loadDmMessages = async dm => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Glow.renderDmToolbar = () => {
|
||||||
|
const toolbar = document.createElement("div");
|
||||||
|
toolbar.className = "dm-toolbar";
|
||||||
|
|
||||||
|
const actions = document.createElement("div");
|
||||||
|
actions.className = "dm-toolbar-actions";
|
||||||
|
|
||||||
|
const create = document.createElement("button");
|
||||||
|
create.className = "button";
|
||||||
|
create.type = "button";
|
||||||
|
create.textContent = "New DM";
|
||||||
|
create.addEventListener("click", () => Glow.openCreateDmDialog());
|
||||||
|
|
||||||
|
const layout = document.createElement("button");
|
||||||
|
layout.className = "button secondary";
|
||||||
|
layout.type = "button";
|
||||||
|
layout.id = "dmLayoutToggle";
|
||||||
|
layout.textContent =
|
||||||
|
Glow.state.dmLayoutMode === "compact"
|
||||||
|
? "Layout: compact"
|
||||||
|
: "Layout: cards";
|
||||||
|
layout.addEventListener("click", () => {
|
||||||
|
const next = Glow.state.dmLayoutMode === "compact" ? "cards" : "compact";
|
||||||
|
Glow.saveDmLayoutPreference(next);
|
||||||
|
Glow.renderDmList();
|
||||||
|
});
|
||||||
|
|
||||||
|
actions.append(create, layout);
|
||||||
|
toolbar.append(actions);
|
||||||
|
return toolbar;
|
||||||
|
};
|
||||||
|
|
||||||
Glow.renderDmList = () => {
|
Glow.renderDmList = () => {
|
||||||
const box = Glow.els.dmBox;
|
const box = Glow.els.dmBox;
|
||||||
box.replaceChildren();
|
box.replaceChildren();
|
||||||
@ -1087,22 +1144,7 @@ Glow.renderDmList = () => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const header = document.createElement("div");
|
box.append(Glow.renderDmToolbar());
|
||||||
header.className = "pages-header";
|
|
||||||
const copy = document.createElement("div");
|
|
||||||
const title = document.createElement("h2");
|
|
||||||
title.textContent = "Direct messages";
|
|
||||||
const subtitle = document.createElement("p");
|
|
||||||
subtitle.textContent = "Private conversations with other users.";
|
|
||||||
copy.append(title, subtitle);
|
|
||||||
|
|
||||||
const create = document.createElement("button");
|
|
||||||
create.className = "button";
|
|
||||||
create.type = "button";
|
|
||||||
create.textContent = "New DM";
|
|
||||||
create.addEventListener("click", () => Glow.openCreateDmDialog());
|
|
||||||
header.append(copy, create);
|
|
||||||
box.append(header);
|
|
||||||
|
|
||||||
if (!(Glow.state.dms || []).length) {
|
if (!(Glow.state.dms || []).length) {
|
||||||
const empty = document.createElement("div");
|
const empty = document.createElement("div");
|
||||||
@ -1116,7 +1158,8 @@ Glow.renderDmList = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const list = document.createElement("div");
|
const list = document.createElement("div");
|
||||||
list.className = "dm-list";
|
list.className =
|
||||||
|
`dm-list ${Glow.state.dmLayoutMode === "compact" ? "compact" : "cards"}`;
|
||||||
for (const dm of Glow.state.dms) {
|
for (const dm of Glow.state.dms) {
|
||||||
list.append(Glow.buildDmCard(dm));
|
list.append(Glow.buildDmCard(dm));
|
||||||
}
|
}
|
||||||
@ -1124,8 +1167,9 @@ Glow.renderDmList = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Glow.buildDmCard = dm => {
|
Glow.buildDmCard = dm => {
|
||||||
|
const compact = Glow.state.dmLayoutMode === "compact";
|
||||||
const article = document.createElement("article");
|
const article = document.createElement("article");
|
||||||
article.className = "page-card dm-card";
|
article.className = `page-card dm-card${compact ? " compact" : ""}`;
|
||||||
article.tabIndex = 0;
|
article.tabIndex = 0;
|
||||||
|
|
||||||
const peer =
|
const peer =
|
||||||
@ -1133,19 +1177,31 @@ Glow.buildDmCard = dm => {
|
|||||||
member => Number(member.id) !== Number(Glow.state.currentUser?.id)
|
member => Number(member.id) !== Number(Glow.state.currentUser?.id)
|
||||||
) || dm.other_user || dm.members?.[0];
|
) || dm.other_user || dm.members?.[0];
|
||||||
|
|
||||||
|
const unread = Number(dm.unread_count || 0) > 0;
|
||||||
|
if (unread) {
|
||||||
|
article.classList.add("unread");
|
||||||
|
}
|
||||||
|
|
||||||
const title = document.createElement("h3");
|
const title = document.createElement("h3");
|
||||||
title.textContent = peer?.display_name || peer?.username || "Conversation";
|
title.textContent = peer?.display_name || peer?.username || "Conversation";
|
||||||
if (peer) Glow.applyUserColor(title, peer);
|
if (peer) Glow.applyUserColor(title, peer);
|
||||||
|
|
||||||
|
const sender = document.createElement("div");
|
||||||
|
sender.className = "dm-card-sender";
|
||||||
|
sender.textContent = peer?.username ? `@${peer.username}` : "direct message";
|
||||||
|
|
||||||
const subtitle = document.createElement("p");
|
const subtitle = document.createElement("p");
|
||||||
subtitle.className = "page-card-excerpt";
|
subtitle.className = "page-card-excerpt dm-card-preview";
|
||||||
subtitle.textContent =
|
subtitle.textContent =
|
||||||
dm.latest_message?.text || dm.last_message_text || "No messages yet.";
|
dm.latest_message?.text || dm.last_message_text || "No messages yet.";
|
||||||
|
|
||||||
const footer = document.createElement("div");
|
const footer = document.createElement("div");
|
||||||
footer.className = "page-card-footer";
|
footer.className = "page-card-footer dm-card-footer";
|
||||||
|
|
||||||
const left = document.createElement("span");
|
const left = document.createElement("span");
|
||||||
left.textContent = peer?.username ? `@${peer.username}` : "DM";
|
left.textContent =
|
||||||
|
unread ? `${dm.unread_count} unread` : (peer?.status_message || " ");
|
||||||
|
|
||||||
const updated = document.createElement("time");
|
const updated = document.createElement("time");
|
||||||
updated.dateTime = dm.latest_message?.created_at || dm.last_message_created_at || dm.created_at;
|
updated.dateTime = dm.latest_message?.created_at || dm.last_message_created_at || dm.created_at;
|
||||||
updated.title = new Date(dm.latest_message?.created_at || dm.last_message_created_at || dm.created_at).toLocaleString();
|
updated.title = new Date(dm.latest_message?.created_at || dm.last_message_created_at || dm.created_at).toLocaleString();
|
||||||
@ -1153,6 +1209,7 @@ Glow.buildDmCard = dm => {
|
|||||||
dm.latest_message?.created_at || dm.last_message_created_at
|
dm.latest_message?.created_at || dm.last_message_created_at
|
||||||
? `Updated ${Glow.relativeTime(dm.latest_message?.created_at || dm.last_message_created_at)}`
|
? `Updated ${Glow.relativeTime(dm.latest_message?.created_at || dm.last_message_created_at)}`
|
||||||
: `Created ${Glow.relativeTime(dm.created_at)}`;
|
: `Created ${Glow.relativeTime(dm.created_at)}`;
|
||||||
|
|
||||||
footer.append(left, updated);
|
footer.append(left, updated);
|
||||||
|
|
||||||
const open = async () => {
|
const open = async () => {
|
||||||
@ -1179,7 +1236,7 @@ Glow.buildDmCard = dm => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
article.append(title, subtitle, footer);
|
article.append(title, sender, subtitle, footer);
|
||||||
return article;
|
return article;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1357,6 +1414,198 @@ Glow.uploadSelectedAttachments = async files => {
|
|||||||
return uploaded;
|
return uploaded;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Glow.parseEmojiShortcodeAtCursor = input => {
|
||||||
|
if (!(input instanceof HTMLTextAreaElement)) return null;
|
||||||
|
const value = input.value || "";
|
||||||
|
const caret = input.selectionStart ?? value.length;
|
||||||
|
const before = value.slice(0, caret);
|
||||||
|
const match = before.match(/::([a-z0-9_+-]{0,24})$/i);
|
||||||
|
if (!match) return null;
|
||||||
|
return {
|
||||||
|
query: match[1].toLowerCase(),
|
||||||
|
start: caret - match[0].length,
|
||||||
|
end: caret
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
Glow.getEmojiSuggestions = query => {
|
||||||
|
const entries = Object.entries(Glow.EMOJI_SHORTCODES);
|
||||||
|
if (!query) {
|
||||||
|
return entries.slice(0, 8).map(([name, emoji]) => ({ name, emoji }));
|
||||||
|
}
|
||||||
|
return entries
|
||||||
|
.filter(([name]) => name.includes(query))
|
||||||
|
.slice(0, 8)
|
||||||
|
.map(([name, emoji]) => ({ name, emoji }));
|
||||||
|
};
|
||||||
|
|
||||||
|
Glow.renderEmojiAutocomplete = () => {
|
||||||
|
const state = Glow.state.emojiAutocomplete;
|
||||||
|
const panel =
|
||||||
|
state.owner === "thread"
|
||||||
|
? Glow.els.threadEmojiAutocomplete
|
||||||
|
: Glow.els.emojiAutocomplete;
|
||||||
|
|
||||||
|
const otherPanel =
|
||||||
|
state.owner === "thread"
|
||||||
|
? Glow.els.emojiAutocomplete
|
||||||
|
: Glow.els.threadEmojiAutocomplete;
|
||||||
|
|
||||||
|
otherPanel?.classList.add("hidden");
|
||||||
|
otherPanel?.replaceChildren();
|
||||||
|
|
||||||
|
if (!panel) return;
|
||||||
|
|
||||||
|
panel.replaceChildren();
|
||||||
|
|
||||||
|
if (!state.open || !state.suggestions.length) {
|
||||||
|
panel.classList.add("hidden");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
state.suggestions.forEach((item, index) => {
|
||||||
|
const button = document.createElement("button");
|
||||||
|
button.className = "emoji-suggestion";
|
||||||
|
button.type = "button";
|
||||||
|
button.textContent = `${item.emoji} ::${item.name}`;
|
||||||
|
if (index === state.selectedIndex) {
|
||||||
|
button.classList.add("active");
|
||||||
|
}
|
||||||
|
button.addEventListener("click", () => {
|
||||||
|
Glow.applyEmojiSuggestion(index);
|
||||||
|
});
|
||||||
|
panel.append(button);
|
||||||
|
});
|
||||||
|
|
||||||
|
panel.classList.remove("hidden");
|
||||||
|
};
|
||||||
|
|
||||||
|
Glow.openEmojiAutocomplete = (owner, query, triggerIndex) => {
|
||||||
|
const suggestions = Glow.getEmojiSuggestions(query);
|
||||||
|
Glow.state.emojiAutocomplete = {
|
||||||
|
open: suggestions.length > 0,
|
||||||
|
owner,
|
||||||
|
query,
|
||||||
|
suggestions,
|
||||||
|
selectedIndex: 0,
|
||||||
|
triggerIndex
|
||||||
|
};
|
||||||
|
Glow.renderEmojiAutocomplete();
|
||||||
|
};
|
||||||
|
|
||||||
|
Glow.closeEmojiAutocomplete = () => {
|
||||||
|
Glow.state.emojiAutocomplete = {
|
||||||
|
open: false,
|
||||||
|
owner: "main",
|
||||||
|
query: "",
|
||||||
|
suggestions: [],
|
||||||
|
selectedIndex: 0,
|
||||||
|
triggerIndex: -1
|
||||||
|
};
|
||||||
|
Glow.els.emojiAutocomplete?.classList.add("hidden");
|
||||||
|
Glow.els.threadEmojiAutocomplete?.classList.add("hidden");
|
||||||
|
};
|
||||||
|
|
||||||
|
Glow.moveEmojiSelection = delta => {
|
||||||
|
const state = Glow.state.emojiAutocomplete;
|
||||||
|
if (!state.open || !state.suggestions.length) return;
|
||||||
|
const size = state.suggestions.length;
|
||||||
|
state.selectedIndex = (state.selectedIndex + delta + size) % size;
|
||||||
|
Glow.renderEmojiAutocomplete();
|
||||||
|
};
|
||||||
|
|
||||||
|
Glow.applyEmojiSuggestion = (forcedIndex = null) => {
|
||||||
|
const state = Glow.state.emojiAutocomplete;
|
||||||
|
if (!state.open || !state.suggestions.length) return false;
|
||||||
|
|
||||||
|
const index =
|
||||||
|
forcedIndex == null ? state.selectedIndex : forcedIndex;
|
||||||
|
const chosen = state.suggestions[index];
|
||||||
|
if (!chosen) return false;
|
||||||
|
|
||||||
|
const input =
|
||||||
|
state.owner === "thread"
|
||||||
|
? Glow.els.threadInput
|
||||||
|
: Glow.els.messageInput;
|
||||||
|
|
||||||
|
if (!(input instanceof HTMLTextAreaElement)) return false;
|
||||||
|
|
||||||
|
const parsed = Glow.parseEmojiShortcodeAtCursor(input);
|
||||||
|
if (!parsed) {
|
||||||
|
Glow.closeEmojiAutocomplete();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const value = input.value;
|
||||||
|
input.value =
|
||||||
|
value.slice(0, parsed.start) +
|
||||||
|
chosen.emoji +
|
||||||
|
value.slice(parsed.end);
|
||||||
|
|
||||||
|
const nextPos = parsed.start + chosen.emoji.length;
|
||||||
|
input.setSelectionRange(nextPos, nextPos);
|
||||||
|
|
||||||
|
if (state.owner === "thread") {
|
||||||
|
Glow.autoResizeThreadComposer?.();
|
||||||
|
Glow.updateThreadMessageCount?.();
|
||||||
|
} else {
|
||||||
|
Glow.autoResizeComposer();
|
||||||
|
Glow.updateMessageCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
Glow.closeEmojiAutocomplete();
|
||||||
|
input.focus();
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
Glow.handleEmojiAutocompleteInput = owner => {
|
||||||
|
const input =
|
||||||
|
owner === "thread"
|
||||||
|
? Glow.els.threadInput
|
||||||
|
: Glow.els.messageInput;
|
||||||
|
|
||||||
|
const parsed = Glow.parseEmojiShortcodeAtCursor(input);
|
||||||
|
if (!parsed) {
|
||||||
|
if (Glow.state.emojiAutocomplete.open && Glow.state.emojiAutocomplete.owner === owner) {
|
||||||
|
Glow.closeEmojiAutocomplete();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Glow.openEmojiAutocomplete(owner, parsed.query, parsed.start);
|
||||||
|
};
|
||||||
|
|
||||||
|
Glow.handleEmojiAutocompleteKeydown = event, owner => {
|
||||||
|
const state = Glow.state.emojiAutocomplete;
|
||||||
|
if (!state.open || state.owner !== owner) return false;
|
||||||
|
|
||||||
|
if (event.key === "ArrowDown") {
|
||||||
|
event.preventDefault();
|
||||||
|
Glow.moveEmojiSelection(1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.key === "ArrowUp") {
|
||||||
|
event.preventDefault();
|
||||||
|
Glow.moveEmojiSelection(-1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.key === "Escape") {
|
||||||
|
event.preventDefault();
|
||||||
|
Glow.closeEmojiAutocomplete();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event.key === "Enter" || event.key === "Tab") {
|
||||||
|
event.preventDefault();
|
||||||
|
Glow.applyEmojiSuggestion();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
Glow.sendTyping = async (isTyping = true) => {
|
Glow.sendTyping = async (isTyping = true) => {
|
||||||
const channel = Glow.getActiveChannel();
|
const channel = Glow.getActiveChannel();
|
||||||
if (
|
if (
|
||||||
@ -1416,8 +1665,8 @@ Glow.renderTyping = () => {
|
|||||||
const names = users.map(user => user.username);
|
const names = users.map(user => user.username);
|
||||||
Glow.els.typingBar.textContent =
|
Glow.els.typingBar.textContent =
|
||||||
names.length === 1
|
names.length === 1
|
||||||
? `${names[0]} is typing…`
|
? `${names[0]} is typing…`
|
||||||
: `${names.slice(0, -1).join(", ")} and ${names.at(-1)} are typing…`;
|
: `${names.slice(0, -1).join(", ")} and ${names.at(-1)} are typing…`;
|
||||||
Glow.els.typingBar.classList.remove("hidden");
|
Glow.els.typingBar.classList.remove("hidden");
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1481,6 +1730,7 @@ Glow.sendMessage = async event => {
|
|||||||
Glow.updateMessageCount();
|
Glow.updateMessageCount();
|
||||||
Glow.els.attachmentInput.value = "";
|
Glow.els.attachmentInput.value = "";
|
||||||
Glow.setSelectedAttachment([]);
|
Glow.setSelectedAttachment([]);
|
||||||
|
Glow.closeEmojiAutocomplete();
|
||||||
Glow.appendMessages([data.message], true, false);
|
Glow.appendMessages([data.message], true, false);
|
||||||
Glow.sendTyping(false);
|
Glow.sendTyping(false);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@ -1743,6 +1993,7 @@ Glow.sendThreadReply = async event => {
|
|||||||
Glow.updateThreadMessageCount();
|
Glow.updateThreadMessageCount();
|
||||||
Glow.els.threadAttachmentInput.value = "";
|
Glow.els.threadAttachmentInput.value = "";
|
||||||
Glow.setSelectedThreadAttachment([]);
|
Glow.setSelectedThreadAttachment([]);
|
||||||
|
Glow.closeEmojiAutocomplete();
|
||||||
Glow.renderThread();
|
Glow.renderThread();
|
||||||
Glow.refreshRootReplyCount(root.id, Glow.state.threadReplies.length);
|
Glow.refreshRootReplyCount(root.id, Glow.state.threadReplies.length);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user