-
Notifications
You must be signed in to change notification settings - Fork 7
[Broadcaster] Add chat #13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,6 +1,6 @@ | ||
| // If you want to use Phoenix channels, run `mix help phx.gen.channel` | ||
| // to get started and then uncomment the line below. | ||
| import "./user_socket.js" | ||
| // import "./user_socket.js" | ||
|
|
||
| // You can include dependencies in two ways. | ||
| // | ||
|
|
@@ -18,12 +18,12 @@ import "./user_socket.js" | |
| // Include phoenix_html to handle method=PUT/DELETE in forms and buttons. | ||
| import "phoenix_html" | ||
| // Establish Phoenix Socket and LiveView configuration. | ||
| import {Socket} from "phoenix" | ||
| import {LiveSocket} from "phoenix_live_view" | ||
| import { Socket } from "phoenix" | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. vscode formatts this by default. I will try to add linter in a separate PR |
||
| import { LiveSocket } from "phoenix_live_view" | ||
| import topbar from "../vendor/topbar" | ||
|
|
||
| import {Home} from "./home.js" | ||
| import {Player} from "./player.js" | ||
| import { Home } from "./home.js" | ||
| import { Player } from "./player.js" | ||
|
|
||
| let Hooks = {} | ||
| Hooks.Home = Home | ||
|
|
@@ -32,12 +32,12 @@ Hooks.Player = Player | |
| let csrfToken = document.querySelector("meta[name='csrf-token']").getAttribute("content") | ||
| let liveSocket = new LiveSocket("/live", Socket, { | ||
| longPollFallbackMs: 2500, | ||
| params: {_csrf_token: csrfToken}, | ||
| params: { _csrf_token: csrfToken }, | ||
| hooks: Hooks, | ||
| }) | ||
|
|
||
| // Show progress bar on live navigation and form submits | ||
| topbar.config({barColors: {0: "#29d"}, shadowColor: "rgba(0, 0, 0, .3)"}) | ||
| topbar.config({ barColors: { 0: "#29d" }, shadowColor: "rgba(0, 0, 0, .3)" }) | ||
| window.addEventListener("phx:page-loading-start", _info => topbar.show(300)) | ||
| window.addEventListener("phx:page-loading-stop", _info => topbar.hide()) | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,105 @@ | ||
| import { Socket, Presence } from "phoenix" | ||
|
|
||
| export async function connectChat() { | ||
| const viewercount = document.getElementById("viewercount"); | ||
| const chatToggler = document.getElementById("chat-toggler"); | ||
| const chat = document.getElementById("chat"); | ||
| const chatMessages = document.getElementById("chat-messages"); | ||
| const chatInput = document.getElementById("chat-input"); | ||
| const chatNickname = document.getElementById("chat-nickname"); | ||
| const chatButton = document.getElementById("chat-button"); | ||
|
|
||
| let socket = new Socket("/socket", { params: { token: window.userToken } }); | ||
|
|
||
| socket.connect(); | ||
|
|
||
| const channel = socket.channel("stream:chat"); | ||
| const presence = new Presence(channel); | ||
|
|
||
| send = function() { | ||
| body = chatInput.value.trim(); | ||
| if (body != "") { | ||
| channel.push("chat_msg", { body: body }); | ||
| chatInput.value = ""; | ||
| } | ||
| } | ||
|
|
||
| presence.onSync(() => { | ||
| viewercount.innerText = presence.list().length; | ||
| }); | ||
|
|
||
| channel.join() | ||
| .receive("ok", resp => { console.log("Joined chat channel successfully", resp) }) | ||
| .receive("error", resp => { console.log("Unable to join chat channel", resp) }); | ||
|
|
||
| channel.on("join_chat_resp", resp => { | ||
| if (resp.result === 'success') { | ||
| chatButton.innerText = "Send"; | ||
| chatButton.onclick = send; | ||
| chatNickname.disabled = true; | ||
| chatInput.disabled = false; | ||
| chatInput.onkeydown = (ev) => { | ||
| if (ev.key === 'Enter') { | ||
| // prevent from adding a new line in our text area | ||
| ev.preventDefault(); | ||
| send(); | ||
| } | ||
| } | ||
| } else { | ||
| chatNickname.classList.add('invalid-input'); | ||
| } | ||
| }); | ||
|
|
||
| channel.on("chat_msg", msg => { | ||
| if (msg.nickname == undefined || msg.body == undefined) return; | ||
|
|
||
| const chatMessage = document.createElement('div'); | ||
| chatMessage.classList.add('chat-message'); | ||
|
|
||
| const nickname = document.createElement('div'); | ||
| nickname.classList.add('chat-nickname'); | ||
| nickname.innerText = msg.nickname; | ||
|
|
||
| const body = document.createElement('div'); | ||
| body.innerText = msg.body; | ||
|
|
||
| chatMessage.appendChild(nickname); | ||
| chatMessage.appendChild(body); | ||
|
|
||
| chatMessages.appendChild(chatMessage); | ||
|
|
||
| // scroll to the bottom after adding a message | ||
| chatMessages.scrollTop = chatMessages.scrollHeight; | ||
|
|
||
| // allow for 1 scroll history | ||
| if (chatMessages.scrollHeight > 2 * chatMessages.clientHeight) { | ||
| chatMessages.removeChild(chatMessages.children[0]); | ||
| } | ||
| }) | ||
|
|
||
| chatButton.onclick = () => { | ||
| channel.push("join_chat", { nickname: chatNickname.value }); | ||
| }; | ||
|
|
||
| chatNickname.onclick = () => { | ||
| chatNickname.classList.remove("invalid-input"); | ||
| } | ||
|
|
||
| chatToggler.onclick = () => { | ||
| if (window.getComputedStyle(chat).display === "none") { | ||
| chat.style.display = "flex"; | ||
|
|
||
| // For screen's width lower than 1024, | ||
| // eiter show video player or chat at the same time. | ||
| if (window.innerWidth < 1024) { | ||
| document.getElementById("videoplayer-wrapper").style.display = "none"; | ||
| } | ||
| } else { | ||
| chat.style.display = "none"; | ||
|
|
||
| if (window.innerWidth < 1024) { | ||
| document.getElementById("videoplayer-wrapper").style.display = "block"; | ||
| } | ||
| } | ||
| } | ||
| } |
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,7 +11,7 @@ | |
| <script defer phx-track-static type="text/javascript" src={~p"/assets/app.js"}> | ||
| </script> | ||
| </head> | ||
| <body class="bg-white antialiased w-screen h-screen flex flex-col"> | ||
| <body class="bg-white antialiased h-svh flex flex-col"> | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| <%= @inner_content %> | ||
| </body> | ||
| </html> | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Importing user_socket this way, we count our player panel into the viewers. It could also be tricky to make sure that HTML chat elements are already loaded so I've renamed this file to
chat.js, wrapped everything into a function and import this function in home.js.This way, chat.js is only loaded and used when needed.