forked from lavender/watch-party
		
	Add option to pop out the chat to a seperate window.
This commit is contained in:
		
							parent
							
								
									8da286fad9
								
							
						
					
					
						commit
						4885e5b747
					
				
					 4 changed files with 127 additions and 22 deletions
				
			
		
							
								
								
									
										22
									
								
								frontend/chat.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								frontend/chat.html
									
									
									
									
									
										Normal 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> | ||||||
|  | @ -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> | ||||||
|  |  | ||||||
|  | @ -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); | ||||||
| 
 | 
 | ||||||
|   fixChatSize(); |   if (!poppedOut) { | ||||||
|   window.addEventListener("resize", () => { |  | ||||||
|     fixChatSize(); |     fixChatSize(); | ||||||
|   }); |     window.addEventListener("resize", resizeCallback); | ||||||
|  |   } 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); | ||||||
|  |  | ||||||
|  | @ -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; | ||||||
|  | } | ||||||
|  |  | ||||||
		Loading…
	
		Reference in a new issue