Add option to pop out the chat to a seperate window. #1

Closed
nyancrimew wants to merge 1 commits from nyancrimew/watch-party:chat-popout into main
4 changed files with 127 additions and 22 deletions

22
frontend/chat.html Normal file
View File

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>watch party chat <3</title>
<link rel="stylesheet" href="/styles.css?v=3" />
</head>
<body>
<noscript>
This site will <em>not</em> work without JavaScript, and there's not
really any way around that :(
</noscript>
<div id="chatbox-container" class="popped-out">
<div id="chatbox"></div>
<form id="chatbox-send">
<input type="text" placeholder="Message..." />
</form>
</div>
</body>
</html>

View File

@ -3,7 +3,7 @@
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<title>watch party :D</title> <title>watch party :D</title>
<link rel="stylesheet" href="/styles.css?v=2" /> <link rel="stylesheet" href="/styles.css?v=3" />
</head> </head>
<body> <body>
@ -43,10 +43,11 @@
<div id="chatbox-container"> <div id="chatbox-container">
<div id="chatbox"></div> <div id="chatbox"></div>
<form id="chatbox-send"> <form id="chatbox-send">
<input type="text" placeholder="Message..." /> <input type="text" id="message-box" placeholder="Message..." />
<input type="button" id="pop-chat" value="Pop out chat" />
</form> </form>
</div> </div>
<script type="module" src="/main.mjs?v=1"></script> <script type="module" src="/main.mjs?v=2"></script>
</body> </body>
</html> </html>

View File

@ -1,8 +1,14 @@
var win = window;
var poppedOut = false;
const setupChatboxEvents = (socket) => { const setupChatboxEvents = (socket) => {
// clear events by just reconstructing the form // clear events by just reconstructing the form
const oldChatForm = document.querySelector("#chatbox-send"); const oldChatForm = win.document.querySelector("#chatbox-send");
const chatForm = oldChatForm.cloneNode(true); const chatForm = oldChatForm.cloneNode(true);
oldChatForm.replaceWith(chatForm); oldChatForm.replaceWith(chatForm);
if (!poppedOut) {
setupPopoutEvent(socket);
}
chatForm.addEventListener("submit", (e) => { chatForm.addEventListener("submit", (e) => {
e.preventDefault(); e.preventDefault();
@ -24,6 +30,13 @@ const setupChatboxEvents = (socket) => {
}); });
}; };
const setupPopoutEvent = (socket) => {
const button = document.querySelector("#pop-chat");
button.addEventListener("click", () => {
openPopout(socket);
});
};
const fixChatSize = () => { const fixChatSize = () => {
const video = document.querySelector("video"); const video = document.querySelector("video");
const chatbox = document.querySelector("#chatbox"); const chatbox = document.querySelector("#chatbox");
@ -38,21 +51,72 @@ const fixChatSize = () => {
} }
}; };
// TODO: transfer chat history to popout and back?
const openPopout = async (socket) => {
win.document.querySelector("#chatbox-container").style["display"] = "none";
const popout = window.open("/chat.html", "popout", "width=800,height=1000");
win = popout;
poppedOut = true;
// I am aware of the fact that this is incredibly cursed,
// but apparently this is the only way to wait for a child window to load....
// I love browsers :)
function defer(callback) {
var channel = new MessageChannel();
channel.port1.onmessage = function (e) {
callback();
};
channel.port2.postMessage(null);
}
win.addEventListener("unload", () => {
defer(() => {
if (popout.document.readyState === "complete") {
setupChat(socket);
// pop the chat back into the parent window on close
win.addEventListener("unload", () => {
popBackChat(socket);
});
} else {
win.document.addEventListener("DOMContentLoaded", () => {
setupChat(socket);
// pop the chat back into the parent window on close
win.addEventListener("unload", () => {
popBackChat(socket);
});
});
}
});
});
};
const popBackChat = async (socket) => {
win = window;
poppedOut = false;
setupChat(socket);
};
const resizeCallback = () => {
fixChatSize();
};
/** /**
* @param {WebSocket} socket * @param {WebSocket} socket
*/ */
export const setupChat = async (socket) => { export const setupChat = async (socket) => {
document.querySelector("#chatbox-container").style["display"] = "block"; win.document.querySelector("#chatbox-container").style["display"] = "block";
setupChatboxEvents(socket); setupChatboxEvents(socket);
if (!poppedOut) {
fixChatSize(); fixChatSize();
window.addEventListener("resize", () => { window.addEventListener("resize", resizeCallback);
fixChatSize(); } else {
}); window.removeEventListener("resize", resizeCallback);
}
}; };
const printToChat = (elem) => { const printToChat = (elem) => {
const chatbox = document.querySelector("#chatbox"); const chatbox = win.document.querySelector("#chatbox");
chatbox.appendChild(elem); chatbox.appendChild(elem);
chatbox.scrollTop = chatbox.scrollHeight; chatbox.scrollTop = chatbox.scrollHeight;
}; };
@ -61,37 +125,35 @@ export const handleChatEvent = (event) => {
switch (event.op) { switch (event.op) {
case "UserJoin": { case "UserJoin": {
// print something to the chat // print something to the chat
const chatMessage = document.createElement("div"); const chatMessage = win.document.createElement("div");
chatMessage.classList.add("chat-message"); chatMessage.classList.add("chat-message");
chatMessage.classList.add("user-join"); chatMessage.classList.add("user-join");
const userName = document.createElement("strong"); const userName = win.document.createElement("strong");
userName.textContent = event.data; userName.textContent = event.data;
chatMessage.appendChild(userName); chatMessage.appendChild(userName);
chatMessage.appendChild(document.createTextNode(" joined")); chatMessage.appendChild(win.document.createTextNode(" joined"));
printToChat(chatMessage); printToChat(chatMessage);
break; break;
} }
case "UserLeave": { case "UserLeave": {
const chatMessage = document.createElement("div"); const chatMessage = win.document.createElement("div");
chatMessage.classList.add("chat-message"); chatMessage.classList.add("chat-message");
chatMessage.classList.add("user-leave"); chatMessage.classList.add("user-leave");
const userName = document.createElement("strong"); const userName = win.document.createElement("strong");
userName.textContent = event.data; userName.textContent = event.data;
chatMessage.appendChild(userName); chatMessage.appendChild(userName);
chatMessage.appendChild(document.createTextNode(" left")); chatMessage.appendChild(win.document.createTextNode(" left"));
printToChat(chatMessage); printToChat(chatMessage);
break; break;
} }
case "ChatMessage": { case "ChatMessage": {
const chatMessage = document.createElement("div"); const chatMessage = win.document.createElement("div");
chatMessage.classList.add("chat-message"); chatMessage.classList.add("chat-message");
const userName = document.createElement("strong"); const userName = win.document.createElement("strong");
userName.innerText = event.data.user; userName.innerText = event.data.user;
chatMessage.appendChild(userName); chatMessage.appendChild(userName);
chatMessage.appendChild(document.createTextNode(" ")); chatMessage.appendChild(win.document.createTextNode(" "));
const messageContent = document.createElement("span"); const messageContent = win.document.createElement("span");
messageContent.classList.add("message-content"); messageContent.classList.add("message-content");
messageContent.textContent = event.data.message; messageContent.textContent = event.data.message;
chatMessage.appendChild(messageContent); chatMessage.appendChild(messageContent);

View File

@ -23,6 +23,7 @@ html {
html, html,
body { body {
margin: 0; margin: 0;
height: 100%;
} }
video { video {
@ -67,7 +68,8 @@ input[type="text"] {
overflow-y: scroll; overflow-y: scroll;
} }
button { button,
input[type="button"] {
background-color: var(--accent); background-color: var(--accent);
border: var(--accent); border: var(--accent);
border-radius: 6px; border-radius: 6px;
@ -118,6 +120,15 @@ button.small-button {
display: none; display: none;
} }
#chatbox-container.popped-out {
width: 100%;
height: 100%;
}
#chatbox-container.popped-out > #chatbox {
height: calc(100vh - 5em);
}
.user-join, .user-join,
.user-leave { .user-leave {
font-style: italic; font-style: italic;
@ -145,3 +156,12 @@ button.small-button {
#chatbox-send > input { #chatbox-send > input {
font-size: 0.75em; font-size: 0.75em;
} }
#message-box {
display: inline-block;
}
#pop-chat {
width: auto;
float: right;
}