openvibers/openvibe.live Commits
Popout chat: get off /chat — that's the SPA's global chat page
Changes
@@@ -8335,13 +8335,15 @@ document.addEventListener('DOMContentLoaded', async () => {// Route from current URL instead of always going home — but not in the popout// chat window, which drives its own chat UI and has no SPA pages to route to.-- if (!location.pathname.startsWith('/popout-chat')) {++ // Covers /popout-chat.html AND the pretty /popout/<user>[/<id>] URLs.++ if (!location.pathname.startsWith('/popout')) {routeFromURL();}});// Handle browser back/forward — wait for auth to be resolved firstwindow.addEventListener('popstate', () => {++ if (location.pathname.startsWith('/popout')) return; // popout window: no SPA routingif (_userLoaded) {routeFromURL();}@@@ -6613,15 +6613,16 @@ function popoutChat(mode = 'global', streamId = null, username = null) {const left = window.screenX + window.outerWidth - w - 20;const top = window.screenY + 80;-- // Pretty URL: /chat/<username>[/<streamId>] (the popout auto-follows the channel's-- // live state from there). Legacy query form only when no username is known.++ // Pretty URL: /popout/<username>[/<streamId>] (the popout auto-follows the++ // channel's live state from there). NOT /chat/… — that's the SPA's global chat++ // page. Legacy query form only when no username is known.let url;if (mode === 'stream' && username) {-- url = `/chat/${encodeURIComponent(username)}${streamId ? '/' + streamId : ''}`;++ url = `/popout/${encodeURIComponent(username)}${streamId ? '/' + streamId : ''}`;} else if (mode === 'stream' && streamId) {url = `/popout-chat.html?popout=1&mode=stream&stream=${encodeURIComponent(streamId)}`; // popout resolves + upgrades} else {-- url = '/chat/global';++ url = '/popout/global';}const popup = window.open(url, `openvibe_chat_${key}`,@@@ -285,8 +285,9 @@let activeStreamId = null; // stream id the chat is currently joined to (null = channel chat)(function parseUrl() {-- const seg = window.location.pathname.split('/').filter(Boolean); // ['chat', user?, id?]-- if (seg[0] === 'chat') {++ const seg = window.location.pathname.split('/').filter(Boolean); // ['popout'|'popout-chat', user?, id?]++ if (seg[0] === 'popout' || seg[0] === 'popout-chat') {++ // No username (or explicit "global") → global chat.if (!seg[1] || seg[1].toLowerCase() === 'global') { mode = 'global'; return; }mode = 'channel';channelName = decodeURIComponent(seg[1]);@@@ -302,8 +303,8 @@})();function prettyPath() {-- if (mode !== 'channel' || !channelName) return '/chat/global';-- return '/chat/' + encodeURIComponent(channelName) + (activeStreamId ? '/' + activeStreamId : '');++ if (mode !== 'channel' || !channelName) return '/popout/global';++ return '/popout/' + encodeURIComponent(channelName) + (activeStreamId ? '/' + activeStreamId : '');}// Keep the address bar honest without polluting history — swaps replace, they// don't stack, so Back still leaves the popout instead of replaying old streams.@@@ -663,11 +663,13 @@ app.get(['/kiosk', '/kiosk.html'], (req, res) => {res.sendFile(path.join(__dirname, '../public/kiosk.html'));});--// Popout chat pretty URLs: /chat/global, /chat/:username (channel chat) and--// /chat/:username/:streamId (pinned stream, auto-follows the channel's live state).++// Popout chat pretty URLs: /popout/global, /popout/:username (channel chat) and++// /popout/:username/:streamId (pinned stream, auto-follows the channel's live state).++// NOT /chat/… — the SPA's global chat page (voice channels et al) lives there.// The legacy /popout-chat.html?mode=…&stream=… form keeps working (static file) and// self-upgrades to the pretty URL client-side.--app.get(['/chat', '/chat/*'], (req, res) => {++// /popout-chat/… works as an alias; with no username both prefixes mean global chat.++app.get(['/popout', '/popout/*', '/popout-chat', '/popout-chat/*'], (req, res) => {res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');res.sendFile(path.join(__dirname, '../public/popout-chat.html'));});
@@ -8335,13 +8335,15 @@ document.addEventListener('DOMContentLoaded', async () => {
@@ -8335,13 +8335,15 @@ document.addEventListener('DOMContentLoaded', async () => {
// Route from current URL instead of always going home — but not in the popout
// Route from current URL instead of always going home — but not in the popout
// chat window, which drives its own chat UI and has no SPA pages to route to.
// chat window, which drives its own chat UI and has no SPA pages to route to.
- if (!location.pathname.startsWith('/popout-chat')) {
+ // Covers /popout-chat.html AND the pretty /popout/<user>[/<id>] URLs.
+ if (!location.pathname.startsWith('/popout')) {
routeFromURL();
routeFromURL();
}
}
});
});
// Handle browser back/forward — wait for auth to be resolved first
// Handle browser back/forward — wait for auth to be resolved first
window.addEventListener('popstate', () => {
window.addEventListener('popstate', () => {
+ if (location.pathname.startsWith('/popout')) return; // popout window: no SPA routing
if (_userLoaded) {
if (_userLoaded) {
routeFromURL();
routeFromURL();
}
}
@@ -6613,15 +6613,16 @@ function popoutChat(mode = 'global', streamId = null, username = null) {
@@ -6613,15 +6613,16 @@ function popoutChat(mode = 'global', streamId = null, username = null) {
const left = window.screenX + window.outerWidth - w - 20;
const left = window.screenX + window.outerWidth - w - 20;
const top = window.screenY + 80;
const top = window.screenY + 80;
- // Pretty URL: /chat/<username>[/<streamId>] (the popout auto-follows the channel's
- // live state from there). Legacy query form only when no username is known.
+ // Pretty URL: /popout/<username>[/<streamId>] (the popout auto-follows the
+ // channel's live state from there). NOT /chat/… — that's the SPA's global chat
+ // page. Legacy query form only when no username is known.
let url;
let url;
if (mode === 'stream' && username) {
if (mode === 'stream' && username) {
- url = `/chat/${encodeURIComponent(username)}${streamId ? '/' + streamId : ''}`;
+ url = `/popout/${encodeURIComponent(username)}${streamId ? '/' + streamId : ''}`;
} else if (mode === 'stream' && streamId) {
} else if (mode === 'stream' && streamId) {
url = `/popout-chat.html?popout=1&mode=stream&stream=${encodeURIComponent(streamId)}`; // popout resolves + upgrades
url = `/popout-chat.html?popout=1&mode=stream&stream=${encodeURIComponent(streamId)}`; // popout resolves + upgrades
} else {
} else {
- url = '/chat/global';
+ url = '/popout/global';
}
}
const popup = window.open(url, `openvibe_chat_${key}`,
const popup = window.open(url, `openvibe_chat_${key}`,
@@ -285,8 +285,9 @@
@@ -285,8 +285,9 @@
let activeStreamId = null; // stream id the chat is currently joined to (null = channel chat)
let activeStreamId = null; // stream id the chat is currently joined to (null = channel chat)
(function parseUrl() {
(function parseUrl() {
- const seg = window.location.pathname.split('/').filter(Boolean); // ['chat', user?, id?]
- if (seg[0] === 'chat') {
+ const seg = window.location.pathname.split('/').filter(Boolean); // ['popout'|'popout-chat', user?, id?]
+ if (seg[0] === 'popout' || seg[0] === 'popout-chat') {
+ // No username (or explicit "global") → global chat.
if (!seg[1] || seg[1].toLowerCase() === 'global') { mode = 'global'; return; }
if (!seg[1] || seg[1].toLowerCase() === 'global') { mode = 'global'; return; }
mode = 'channel';
mode = 'channel';
channelName = decodeURIComponent(seg[1]);
channelName = decodeURIComponent(seg[1]);
@@ -302,8 +303,8 @@
@@ -302,8 +303,8 @@
})();
})();
function prettyPath() {
function prettyPath() {
- if (mode !== 'channel' || !channelName) return '/chat/global';
- return '/chat/' + encodeURIComponent(channelName) + (activeStreamId ? '/' + activeStreamId : '');
+ if (mode !== 'channel' || !channelName) return '/popout/global';
+ return '/popout/' + encodeURIComponent(channelName) + (activeStreamId ? '/' + activeStreamId : '');
}
}
// Keep the address bar honest without polluting history — swaps replace, they
// Keep the address bar honest without polluting history — swaps replace, they
// don't stack, so Back still leaves the popout instead of replaying old streams.
// don't stack, so Back still leaves the popout instead of replaying old streams.
@@ -663,11 +663,13 @@ app.get(['/kiosk', '/kiosk.html'], (req, res) => {
@@ -663,11 +663,13 @@ app.get(['/kiosk', '/kiosk.html'], (req, res) => {
res.sendFile(path.join(__dirname, '../public/kiosk.html'));
res.sendFile(path.join(__dirname, '../public/kiosk.html'));
});
});
-// Popout chat pretty URLs: /chat/global, /chat/:username (channel chat) and
-// /chat/:username/:streamId (pinned stream, auto-follows the channel's live state).
+// Popout chat pretty URLs: /popout/global, /popout/:username (channel chat) and
+// /popout/:username/:streamId (pinned stream, auto-follows the channel's live state).
+// NOT /chat/… — the SPA's global chat page (voice channels et al) lives there.
// The legacy /popout-chat.html?mode=…&stream=… form keeps working (static file) and
// The legacy /popout-chat.html?mode=…&stream=… form keeps working (static file) and
// self-upgrades to the pretty URL client-side.
// self-upgrades to the pretty URL client-side.
-app.get(['/chat', '/chat/*'], (req, res) => {
+// /popout-chat/… works as an alias; with no username both prefixes mean global chat.
+app.get(['/popout', '/popout/*', '/popout-chat', '/popout-chat/*'], (req, res) => {
res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
res.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');
res.sendFile(path.join(__dirname, '../public/popout-chat.html'));
res.sendFile(path.join(__dirname, '../public/popout-chat.html'));
});
});