Update static/js/00-config.js
This commit is contained in:
parent
869b2857e4
commit
6098483251
@ -1,6 +1,8 @@
|
||||
// static/js/00-config.js
|
||||
"use strict";
|
||||
|
||||
window.Glow = window.Glow || {};
|
||||
|
||||
Glow.els = {
|
||||
chatBox: document.getElementById("chatBox"),
|
||||
dmBox: document.getElementById("dmBox"),
|
||||
@ -85,15 +87,19 @@ Glow.els = {
|
||||
callOverlay: document.getElementById("callOverlay"),
|
||||
callStatus: document.getElementById("callStatus"),
|
||||
callPeerLabel: document.getElementById("callPeerLabel"),
|
||||
callParticipants: document.getElementById("callParticipants"),
|
||||
callPendingInvites: document.getElementById("callPendingInvites"),
|
||||
remoteAudioContainer: document.getElementById("remoteAudioContainer"),
|
||||
callStatusChip: document.getElementById("callStatusChip"),
|
||||
startCallButton: document.getElementById("startCallButton"),
|
||||
answerCallButton: document.getElementById("answerCallButton"),
|
||||
retryCallButton: document.getElementById("retryCallButton"),
|
||||
addToCallButton: document.getElementById("addToCallButton"),
|
||||
muteCallButton: document.getElementById("muteCallButton"),
|
||||
hangupCallButton: document.getElementById("hangupCallButton"),
|
||||
closeCallPanelButton: document.getElementById("closeCallPanelButton"),
|
||||
remoteAudio: document.getElementById("remoteAudio"),
|
||||
emojiAutocomplete: document.getElementById("emojiAutocomplete")
|
||||
endCallButton: document.getElementById("endCallButton"),
|
||||
closeCallPanelButton: document.getElementById("closeCallPanelButton")
|
||||
};
|
||||
|
||||
Glow.state = {
|
||||
currentUser: null,
|
||||
csrfToken: "",
|
||||
@ -148,8 +154,6 @@ Glow.state = {
|
||||
originalTitle: document.title,
|
||||
dialogResolver: null,
|
||||
lastFocusedElement: null,
|
||||
emojiSuggestions: [],
|
||||
emojiActiveInput: null,
|
||||
presence: {
|
||||
roomOnlineCount: 0,
|
||||
channelOnlineCount: 0,
|
||||
@ -164,40 +168,38 @@ Glow.state = {
|
||||
selfPeerId: null,
|
||||
peerConnections: new Map(),
|
||||
remoteStreams: new Map(),
|
||||
participantAudioEls: new Map(),
|
||||
peers: [],
|
||||
reconnectTimer: null,
|
||||
invitePollTimer: null,
|
||||
participantPollTimer: null,
|
||||
heartbeatTimer: null,
|
||||
invites: [],
|
||||
invitePollTimer: null
|
||||
reconnecting: false,
|
||||
joining: false,
|
||||
leaving: false,
|
||||
permissions: {
|
||||
can_manage: false,
|
||||
can_end: false,
|
||||
can_invite: false
|
||||
},
|
||||
backendParticipants: [],
|
||||
scope: null,
|
||||
statusText: "Idle"
|
||||
}
|
||||
};
|
||||
|
||||
Glow.MAX_MESSAGE_LENGTH = 1000;
|
||||
Glow.MAX_ATTACHMENT_BYTES = 5 * 1024 * 1024;
|
||||
Glow.DEFAULT_ACCENT_COLOR = "#f7dce8";
|
||||
Glow.EMOJI_ALIASES = {
|
||||
smile: "😄",
|
||||
grin: "😁",
|
||||
joy: "😂",
|
||||
heart: "❤️",
|
||||
thumbs_up: "👍",
|
||||
fire: "🔥",
|
||||
tada: "🎉",
|
||||
clap: "👏",
|
||||
eyes: "👀",
|
||||
rocket: "🚀",
|
||||
wave: "👋",
|
||||
sparkles: "✨",
|
||||
thinking: "🤔",
|
||||
cry: "😢",
|
||||
check: "✅",
|
||||
bulb: "💡",
|
||||
shrug: "¯\\_(ツ)_/¯"
|
||||
};
|
||||
|
||||
Glow.normalizeAccentColor = value => {
|
||||
if (typeof value !== "string") return null;
|
||||
const color = value.trim();
|
||||
if (!/^#[0-9a-fA-F]{6}$/.test(color)) return null;
|
||||
return color.toLowerCase();
|
||||
};
|
||||
|
||||
Glow.normalizeNameColor = value => {
|
||||
if (value == null || value === "") return null;
|
||||
if (typeof value !== "string") return null;
|
||||
@ -205,6 +207,7 @@ Glow.normalizeNameColor = value => {
|
||||
if (!/^#[0-9a-fA-F]{6}$/.test(color)) return null;
|
||||
return color.toLowerCase();
|
||||
};
|
||||
|
||||
Glow.hexToRgb = hex => {
|
||||
const normalized = Glow.normalizeAccentColor(hex);
|
||||
if (!normalized) return null;
|
||||
@ -214,6 +217,7 @@ Glow.hexToRgb = hex => {
|
||||
b: parseInt(normalized.slice(5, 7), 16)
|
||||
};
|
||||
};
|
||||
|
||||
Glow.relativeLuminance = hex => {
|
||||
const rgb = Glow.hexToRgb(hex);
|
||||
if (!rgb) return 0;
|
||||
@ -229,9 +233,11 @@ Glow.relativeLuminance = hex => {
|
||||
0.0722 * channel(rgb.b)
|
||||
);
|
||||
};
|
||||
|
||||
Glow.accentTextColor = hex => {
|
||||
return Glow.relativeLuminance(hex) >= 0.18 ? hex : "#f2f2f4";
|
||||
};
|
||||
|
||||
Glow.applyAccentColor = value => {
|
||||
const accent =
|
||||
Glow.normalizeAccentColor(value) || Glow.DEFAULT_ACCENT_COLOR;
|
||||
@ -251,10 +257,12 @@ Glow.applyAccentColor = value => {
|
||||
localStorage.setItem("glow_accent_color", accent);
|
||||
Glow.updateThemeButton?.();
|
||||
};
|
||||
|
||||
Glow.resetAccentColor = () => {
|
||||
localStorage.removeItem("glow_accent_color");
|
||||
Glow.applyAccentColor(Glow.DEFAULT_ACCENT_COLOR);
|
||||
};
|
||||
|
||||
Glow.roleDefaultNameColor = role => {
|
||||
switch (String(role || "").toLowerCase()) {
|
||||
case "admin":
|
||||
@ -265,6 +273,7 @@ Glow.roleDefaultNameColor = role => {
|
||||
return "#f5f5f7";
|
||||
}
|
||||
};
|
||||
|
||||
Glow.resolveUserNameColor = userish => {
|
||||
const explicit =
|
||||
Glow.normalizeNameColor(userish?.name_color) ||
|
||||
@ -272,18 +281,22 @@ Glow.resolveUserNameColor = userish => {
|
||||
if (explicit) return explicit;
|
||||
return Glow.roleDefaultNameColor(userish?.role || userish?.user_role);
|
||||
};
|
||||
|
||||
Glow.applyUserColor = (element, userish) => {
|
||||
if (!(element instanceof HTMLElement)) return;
|
||||
element.style.color = Glow.resolveUserNameColor(userish);
|
||||
};
|
||||
|
||||
Glow.canModerate = () => {
|
||||
const user = Glow.state.currentUser;
|
||||
return Boolean(user && ["moderator", "admin"].includes(user.role));
|
||||
};
|
||||
|
||||
Glow.isAdmin = () => {
|
||||
const user = Glow.state.currentUser;
|
||||
return Boolean(user && user.role === "admin");
|
||||
};
|
||||
|
||||
Glow.showToast = (message, type = "") => {
|
||||
clearTimeout(Glow.state.toastTimer);
|
||||
Glow.els.statusToast.textContent = String(message);
|
||||
@ -292,14 +305,17 @@ Glow.showToast = (message, type = "") => {
|
||||
Glow.els.statusToast.className = "status-toast";
|
||||
}, 3500);
|
||||
};
|
||||
|
||||
Glow.showAuthNotice = (message, type = "error") => {
|
||||
Glow.els.authNotice.textContent = String(message);
|
||||
Glow.els.authNotice.className = `notice show ${type}`;
|
||||
};
|
||||
|
||||
Glow.clearAuthNotice = () => {
|
||||
Glow.els.authNotice.textContent = "";
|
||||
Glow.els.authNotice.className = "notice";
|
||||
};
|
||||
|
||||
Glow.showBlocked = message => {
|
||||
Glow.els.blockedMessage.textContent = message || "Access has been blocked.";
|
||||
Glow.els.blockedOverlay.classList.remove("hidden");
|
||||
@ -311,6 +327,7 @@ Glow.showBlocked = message => {
|
||||
Glow.els.attachmentButton.classList.add("disabled");
|
||||
clearTimeout(Glow.state.pollTimer);
|
||||
};
|
||||
|
||||
Glow.relativeTime = iso => {
|
||||
const seconds = Math.max(
|
||||
0,
|
||||
@ -324,6 +341,7 @@ Glow.relativeTime = iso => {
|
||||
if (hours < 24) return `${hours}h`;
|
||||
return `${Math.floor(hours / 24)}d`;
|
||||
};
|
||||
|
||||
Glow.formatDateLabel = iso => {
|
||||
const date = new Date(iso);
|
||||
const now = new Date();
|
||||
@ -339,6 +357,7 @@ Glow.formatDateLabel = iso => {
|
||||
day: "numeric"
|
||||
});
|
||||
};
|
||||
|
||||
Glow.dateKey = iso => {
|
||||
const date = new Date(iso);
|
||||
return [
|
||||
@ -347,6 +366,7 @@ Glow.dateKey = iso => {
|
||||
String(date.getDate()).padStart(2, "0")
|
||||
].join("-");
|
||||
};
|
||||
|
||||
Glow.isNearBottom = () => {
|
||||
const activeBox =
|
||||
Glow.state.activeView === "feed"
|
||||
@ -359,34 +379,41 @@ Glow.isNearBottom = () => {
|
||||
if (!activeBox) return true;
|
||||
return activeBox.scrollHeight - activeBox.scrollTop - activeBox.clientHeight < 100;
|
||||
};
|
||||
|
||||
Glow.autoResizeComposer = () => {
|
||||
const input = Glow.els.messageInput;
|
||||
input.style.height = "auto";
|
||||
input.style.height = `${Math.min(input.scrollHeight, 150)}px`;
|
||||
};
|
||||
|
||||
Glow.updateMessageCount = () => {
|
||||
const count = Glow.els.messageInput.value.length;
|
||||
Glow.els.messageCount.textContent = `${count} / ${Glow.MAX_MESSAGE_LENGTH}`;
|
||||
};
|
||||
|
||||
Glow.updateDocumentTitle = () => {
|
||||
if (!Glow.state.unreadMessages) {
|
||||
document.title = Glow.state.originalTitle;
|
||||
return;
|
||||
}
|
||||
document.title = `(${Glow.state.unreadMessages}) ${Glow.state.originalTitle}`;
|
||||
document.title = `(${Glow.state.unreadMessages})` + Glow.state.originalTitle;
|
||||
};
|
||||
|
||||
Glow.resetUnreadMessages = () => {
|
||||
Glow.state.unreadMessages = 0;
|
||||
Glow.updateDocumentTitle();
|
||||
Glow.els.newMessagesBar.classList.add("hidden");
|
||||
};
|
||||
|
||||
Glow.showNewMessages = () => {
|
||||
Glow.els.newMessagesBar.classList.remove("hidden");
|
||||
};
|
||||
|
||||
Glow.normalizeSelectedFiles = fileList => {
|
||||
if (!fileList) return [];
|
||||
return [...fileList].filter(Boolean);
|
||||
};
|
||||
|
||||
Glow.openDialog = ({
|
||||
title,
|
||||
body,
|
||||
@ -398,10 +425,12 @@ Glow.openDialog = ({
|
||||
if (Glow.state.dialogResolver) {
|
||||
Glow.closeDialog(null);
|
||||
}
|
||||
|
||||
Glow.state.lastFocusedElement = document.activeElement;
|
||||
Glow.els.dialogTitle.textContent = title;
|
||||
Glow.els.dialogBody.replaceChildren();
|
||||
Glow.els.dialogActions.replaceChildren();
|
||||
|
||||
if (typeof body === "string") {
|
||||
const paragraph = document.createElement("p");
|
||||
paragraph.textContent = body;
|
||||
@ -409,17 +438,20 @@ Glow.openDialog = ({
|
||||
} else if (body instanceof Node) {
|
||||
Glow.els.dialogBody.append(body);
|
||||
}
|
||||
|
||||
const fieldElements = {};
|
||||
for (const field of fields) {
|
||||
const label = document.createElement("label");
|
||||
label.className = "dialog-label";
|
||||
label.textContent = field.label;
|
||||
|
||||
const isMultiline = Boolean(field.multiline);
|
||||
const input = document.createElement(isMultiline ? "textarea" : "input");
|
||||
input.className = "field";
|
||||
input.name = field.name;
|
||||
input.value = field.value || "";
|
||||
input.placeholder = field.placeholder || "";
|
||||
|
||||
if (isMultiline) {
|
||||
input.rows = field.rows || 3;
|
||||
input.maxLength = field.maxLength || 300;
|
||||
@ -432,20 +464,26 @@ Glow.openDialog = ({
|
||||
input.step = field.step || "1";
|
||||
}
|
||||
}
|
||||
|
||||
label.append(input);
|
||||
Glow.els.dialogBody.append(label);
|
||||
fieldElements[field.name] = input;
|
||||
}
|
||||
|
||||
const cancel = document.createElement("button");
|
||||
cancel.className = "button secondary";
|
||||
cancel.type = "button";
|
||||
cancel.textContent = cancelText;
|
||||
|
||||
const confirmButton = document.createElement("button");
|
||||
confirmButton.className = danger ? "danger-button" : "button";
|
||||
confirmButton.type = "button";
|
||||
confirmButton.textContent = confirmText;
|
||||
|
||||
Glow.els.dialogActions.append(cancel, confirmButton);
|
||||
|
||||
Glow.els.dialogOverlay.classList.remove("hidden");
|
||||
|
||||
return new Promise(resolve => {
|
||||
Glow.state.dialogResolver = resolve;
|
||||
cancel.addEventListener("click", () => Glow.closeDialog(null), { once: true });
|
||||
@ -466,6 +504,7 @@ Glow.openDialog = ({
|
||||
}, 0);
|
||||
});
|
||||
};
|
||||
|
||||
Glow.closeDialog = (result = null) => {
|
||||
Glow.els.dialogOverlay.classList.add("hidden");
|
||||
const resolve = Glow.state.dialogResolver;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user