Update static/js/04-main.js

This commit is contained in:
dev 2026-10-31 09:23:39 +00:00
parent c04b19602e
commit 49494e5399

View File

@ -12,6 +12,8 @@ Glow.openCallPanel = async () => {
overlay?.classList.remove("hidden"); overlay?.classList.remove("hidden");
participants?.classList.remove("hidden"); participants?.classList.remove("hidden");
Glow.restoreCallPanelPosition?.();
if (Glow.state.calls.activeCall?.groupSession?.id) { if (Glow.state.calls.activeCall?.groupSession?.id) {
await Glow.calls.refreshBackendParticipants(); await Glow.calls.refreshBackendParticipants();
} }
@ -66,6 +68,100 @@ Glow.loadRooms = async () => {
Glow.updateChatControls(); Glow.updateChatControls();
}; };
Glow.restoreCallPanelPosition = () => {
const overlay = Glow.els.callOverlay;
if (!overlay) return;
const savedX = localStorage.getItem("glow_call_panel_x");
const savedY = localStorage.getItem("glow_call_panel_y");
if (savedX == null || savedY == null) return;
const x = Number(savedX);
const y = Number(savedY);
if (!Number.isFinite(x) || !Number.isFinite(y)) return;
Glow.state.calls.drag.x = x;
Glow.state.calls.drag.y = y;
overlay.style.left = `${x}px`;
overlay.style.top = `${y}px`;
overlay.style.right = "auto";
overlay.style.bottom = "auto";
overlay.style.alignItems = "flex-start";
overlay.style.justifyContent = "flex-start";
};
Glow.persistCallPanelPosition = () => {
const drag = Glow.state.calls?.drag;
if (!drag) return;
if (!Number.isFinite(drag.x) || !Number.isFinite(drag.y)) return;
localStorage.setItem("glow_call_panel_x", String(drag.x));
localStorage.setItem("glow_call_panel_y", String(drag.y));
};
Glow.confirmDirtySettingsBeforeNavigate = async action => {
if (Glow.state.activeView !== "settings" || !Glow.isSettingsDirty()) {
await action();
return true;
}
Glow.syncSettingsSavePanel?.();
const values = await Glow.openDialog({
title: "Unsaved settings changes",
body: "You have unsaved changes. Would you like to save before leaving this page?",
confirmText: "Save and leave",
cancelText: "Stay"
});
if (values === null) {
const discard = await Glow.openDialog({
title: "Discard changes?",
body: "If you leave now, your unsaved settings changes will be lost.",
confirmText: "Discard changes",
cancelText: "Stay",
danger: true
});
if (!discard) {
return false;
}
Glow.discardSettingsDraft?.();
await action();
return true;
}
try {
await Glow.saveSettingsDraft?.();
await action();
return true;
} catch (error) {
Glow.showToast(error.message || "Could not save settings.", "error");
return false;
}
};
Glow.navigateToView = async (view, options = {}) => {
return Glow.confirmDirtySettingsBeforeNavigate(async () => {
if (typeof options.before === "function") {
await options.before();
}
Glow.state.activeView = view;
Glow.updateViewUI();
if (typeof options.after === "function") {
await options.after();
}
if (options.schedulePoll !== false) {
Glow.schedulePoll?.();
}
});
};
Glow.updateViewUI = () => { Glow.updateViewUI = () => {
const view = Glow.state.activeView || "feed"; const view = Glow.state.activeView || "feed";
const room = Glow.state.activeRoom; const room = Glow.state.activeRoom;
@ -89,6 +185,8 @@ Glow.updateViewUI = () => {
Glow.els.composerWrap.classList.toggle("hidden", !chatActive); Glow.els.composerWrap.classList.toggle("hidden", !chatActive);
Glow.els.threadComposerWrap?.classList.toggle("hidden", !threadActive); Glow.els.threadComposerWrap?.classList.toggle("hidden", !threadActive);
Glow.syncSettingsSavePanel?.();
if (!chatActive) { if (!chatActive) {
Glow.state.typingUsers = []; Glow.state.typingUsers = [];
Glow.state.dmTypingUsers = []; Glow.state.dmTypingUsers = [];
@ -220,7 +318,7 @@ Glow.updateAuthUI = () => {
Glow.els.logoutButton.classList.toggle("hidden", !authenticated); Glow.els.logoutButton.classList.toggle("hidden", !authenticated);
Glow.els.headerAccount.textContent = Glow.els.headerAccount.textContent =
user ? `${user.username} · ${user.role}` : "not signed in"; user ? `${user.username} · ${user.role}` : "not signed in";
document.body.classList.toggle("is-moderator", Glow.canModerate()); document.body.classList.toggle("is-moderator", Glow.canModerate());
document.body.classList.toggle("is-admin", Glow.isAdmin()); document.body.classList.toggle("is-admin", Glow.isAdmin());
@ -397,6 +495,9 @@ Glow.logout = async () => {
Glow.state.activePage = null; Glow.state.activePage = null;
Glow.state.activeProfile = null; Glow.state.activeProfile = null;
Glow.state.settings = null; Glow.state.settings = null;
Glow.state.settingsSaved = null;
Glow.state.settingsDraft = null;
Glow.state.settingsDirty = false;
Glow.clearMessages(); Glow.clearMessages();
Glow.clearFeed(); Glow.clearFeed();
@ -574,6 +675,23 @@ Glow.els.threadInput?.addEventListener("input", () => {
}); });
Glow.els.messageInput.addEventListener("keydown", event => { Glow.els.messageInput.addEventListener("keydown", event => {
if (Glow.state.emojiAutocomplete?.open) {
if (event.key === "Enter" || event.key === "Tab") {
if (typeof Glow.applyEmojiSuggestion === "function") {
event.preventDefault();
Glow.applyEmojiSuggestion();
return;
}
}
if (event.key === "Escape") {
if (typeof Glow.closeEmojiAutocomplete === "function") {
event.preventDefault();
Glow.closeEmojiAutocomplete();
return;
}
}
}
if (event.key === "Enter" && !event.shiftKey) { if (event.key === "Enter" && !event.shiftKey) {
event.preventDefault(); event.preventDefault();
Glow.sendMessage(event); Glow.sendMessage(event);
@ -581,6 +699,23 @@ Glow.els.messageInput.addEventListener("keydown", event => {
}); });
Glow.els.threadInput?.addEventListener("keydown", event => { Glow.els.threadInput?.addEventListener("keydown", event => {
if (Glow.state.emojiAutocomplete?.open && Glow.state.emojiAutocomplete.owner === "thread") {
if (event.key === "Enter" || event.key === "Tab") {
if (typeof Glow.applyEmojiSuggestion === "function") {
event.preventDefault();
Glow.applyEmojiSuggestion();
return;
}
}
if (event.key === "Escape") {
if (typeof Glow.closeEmojiAutocomplete === "function") {
event.preventDefault();
Glow.closeEmojiAutocomplete();
return;
}
}
}
if (event.key === "Enter" && !event.shiftKey) { if (event.key === "Enter" && !event.shiftKey) {
event.preventDefault(); event.preventDefault();
Glow.sendThreadReply?.(event); Glow.sendThreadReply?.(event);
@ -625,20 +760,33 @@ Glow.els.threadAttachmentInput?.addEventListener("change", () => {
Glow.setSelectedThreadAttachment?.(files); Glow.setSelectedThreadAttachment?.(files);
}); });
Glow.els.feedButton.addEventListener("click", Glow.openFeed); Glow.els.feedButton.addEventListener("click", async () => {
await Glow.navigateToView("feed", {
Glow.els.dmsButton?.addEventListener("click", async () => { before: async () => {
Glow.state.activeView = "dms"; Glow.state.activeDm = null;
Glow.updateViewUI(); },
await Glow.loadDms?.(); after: async () => {
Glow.schedulePoll(); await Glow.loadFeed();
}
});
}); });
Glow.els.pagesButton?.addEventListener("click", () => { Glow.els.dmsButton?.addEventListener("click", async () => {
await Glow.navigateToView("dms", {
after: async () => {
await Glow.loadDms?.();
}
});
});
Glow.els.pagesButton?.addEventListener("click", async () => {
await Glow.confirmDirtySettingsBeforeNavigate(async () => {
Glow.openPages?.(); Glow.openPages?.();
});
}); });
Glow.els.backButton?.addEventListener("click", async () => { Glow.els.backButton?.addEventListener("click", async () => {
await Glow.confirmDirtySettingsBeforeNavigate(async () => {
if (Glow.state.activeView === "thread") { if (Glow.state.activeView === "thread") {
await Glow.returnToChannel?.(); await Glow.returnToChannel?.();
} else if (Glow.state.activeView === "page") { } else if (Glow.state.activeView === "page") {
@ -650,6 +798,7 @@ Glow.els.backButton?.addEventListener("click", async () => {
Glow.updateViewUI(); Glow.updateViewUI();
await Glow.loadDms?.(); await Glow.loadDms?.();
} }
});
}); });
Glow.els.loginButton.addEventListener("click", () => { Glow.els.loginButton.addEventListener("click", () => {
@ -675,6 +824,7 @@ Glow.els.roomSelect.addEventListener("change", async () => {
); );
if (!selected) return; if (!selected) return;
await Glow.confirmDirtySettingsBeforeNavigate(async () => {
Glow.state.activeDm = null; Glow.state.activeDm = null;
Glow.state.activeRoom = selected; Glow.state.activeRoom = selected;
Glow.state.activeView = "room"; Glow.state.activeView = "room";
@ -688,6 +838,7 @@ Glow.els.roomSelect.addEventListener("change", async () => {
Glow.pingPresence?.(); Glow.pingPresence?.();
Glow.refreshPresence?.(); Glow.refreshPresence?.();
Glow.schedulePoll(); Glow.schedulePoll();
});
}); });
Glow.els.teamSelect?.addEventListener("change", () => { Glow.els.teamSelect?.addEventListener("change", () => {
@ -700,8 +851,8 @@ Glow.els.adminFab.addEventListener("click", Glow.openAdminPanel);
Glow.els.closeAdminButton.addEventListener("click", Glow.closeAdminPanel); Glow.els.closeAdminButton.addEventListener("click", Glow.closeAdminPanel);
Glow.els.createRoomButton.addEventListener("click", Glow.createRoom); Glow.els.createRoomButton.addEventListener("click", Glow.createRoom);
Glow.els.clearMessagesButton.addEventListener("click", Glow.clearActiveRoom); Glow.els.clearMessagesButton.addEventListener("click", Glow.clearActiveRoom);
Glow.els.typingToggleButton.addEventListener("click", Glow.toggleTypingIndicators); Glow.els.typingToggleButton?.addEventListener("click", Glow.toggleTypingIndicators);
Glow.els.notificationsToggleButton.addEventListener("click", Glow.toggleNotifications); Glow.els.notificationsToggleButton?.addEventListener("click", Glow.toggleNotifications);
Glow.els.themeButton?.addEventListener("click", Glow.openAccentColorPicker); Glow.els.themeButton?.addEventListener("click", Glow.openAccentColorPicker);
Glow.els.settingsButton?.addEventListener("click", () => { Glow.els.settingsButton?.addEventListener("click", () => {
@ -765,9 +916,10 @@ document.getElementById("closeCallPanelButton")?.addEventListener("click", () =>
Glow.calls.ensureState(); Glow.calls.ensureState();
Glow.state.calls.panelOpen = false; Glow.state.calls.panelOpen = false;
document.getElementById("callOverlay")?.classList.add("hidden"); document.getElementById("callOverlay")?.classList.add("hidden");
Glow.persistCallPanelPosition?.();
}); });
document.addEventListener("keydown", event => { document.addEventListener("keydown", async event => {
if (event.key !== "Escape") return; if (event.key !== "Escape") return;
if (!Glow.els.dialogOverlay.classList.contains("hidden")) { if (!Glow.els.dialogOverlay.classList.contains("hidden")) {
@ -775,6 +927,11 @@ document.addEventListener("keydown", event => {
return; return;
} }
if (!Glow.els.imageCropOverlay?.classList.contains("hidden")) {
Glow.profileResetCropState?.();
return;
}
if (!Glow.els.mediaOverlay?.classList.contains("hidden")) { if (!Glow.els.mediaOverlay?.classList.contains("hidden")) {
Glow.closeMediaModal?.(); Glow.closeMediaModal?.();
return; return;
@ -794,23 +951,30 @@ document.addEventListener("keydown", event => {
Glow.calls.ensureState(); Glow.calls.ensureState();
Glow.state.calls.panelOpen = false; Glow.state.calls.panelOpen = false;
Glow.els.callOverlay.classList.add("hidden"); Glow.els.callOverlay.classList.add("hidden");
Glow.persistCallPanelPosition?.();
return; return;
} }
if (Glow.state.activeView === "thread") { if (Glow.state.activeView === "thread") {
await Glow.confirmDirtySettingsBeforeNavigate(async () => {
Glow.returnToChannel?.(); Glow.returnToChannel?.();
});
return; return;
} }
if (Glow.state.activeView === "page") { if (Glow.state.activeView === "page") {
await Glow.confirmDirtySettingsBeforeNavigate(async () => {
Glow.openPages?.(); Glow.openPages?.();
});
return; return;
} }
if (Glow.state.activeView === "dm") { if (Glow.state.activeView === "dm") {
await Glow.confirmDirtySettingsBeforeNavigate(async () => {
Glow.state.activeView = "dms"; Glow.state.activeView = "dms";
Glow.updateViewUI(); Glow.updateViewUI();
Glow.loadDms?.(); Glow.loadDms?.();
});
return; return;
} }
@ -894,7 +1058,13 @@ setInterval(() => {
} }
}, 10000); }, 10000);
window.addEventListener("beforeunload", () => { window.addEventListener("beforeunload", event => {
if (Glow.state.activeView === "settings" && Glow.isSettingsDirty()) {
event.preventDefault();
event.returnValue = "";
return "";
}
const sessionId = Glow.state.calls.activeCall?.groupSession?.id; const sessionId = Glow.state.calls.activeCall?.groupSession?.id;
if (!sessionId || !navigator.sendBeacon) return; if (!sessionId || !navigator.sendBeacon) return;
@ -926,4 +1096,5 @@ Glow.autoResizeComposer();
Glow.updateMessageCount(); Glow.updateMessageCount();
Glow.autoResizeThreadComposer?.(); Glow.autoResizeThreadComposer?.();
Glow.updateThreadMessageCount?.(); Glow.updateThreadMessageCount?.();
Glow.state.dmLayoutMode = Glow.loadDmLayoutPreference();
Glow.checkAuth(); Glow.checkAuth();