From 4b28ed8f2535dd0000742e4382705bdbfed59b24 Mon Sep 17 00:00:00 2001 From: Ginger Wong Date: Sun, 23 Aug 2020 19:06:58 -0700 Subject: [PATCH] reorganize js files --- webroot/js/app2.js | 23 +- webroot/js/components.js | 64 --- .../js/{ => components}/chat/chat-input.js | 11 +- webroot/js/{ => components}/chat/chat.js | 12 +- .../{ => components}/chat/content-editable.js | 1 - webroot/js/{ => components}/chat/message.js | 8 +- webroot/js/{ => components}/chat/username.js | 4 +- webroot/js/{ => components}/player.js | 0 webroot/js/{ => components}/social.js | 4 +- webroot/js/message.js | 440 ------------------ .../standalone.js => standalone-chat-app.js} | 11 +- webroot/js/utils/chat.js | 19 +- webroot/js/utils/constants.js | 29 ++ webroot/js/{utils.js => utils/helpers.js} | 19 - webroot/js/utils/social.js | 1 - webroot/js/utils/socket-message-types.js | 11 - webroot/js/{ => utils}/websocket.js | 24 +- webroot/standalone-chat.html | 2 +- webroot/styles/app.css | 172 +++++++ webroot/styles/video.css | 55 +++ 20 files changed, 316 insertions(+), 594 deletions(-) delete mode 100644 webroot/js/components.js rename webroot/js/{ => components}/chat/chat-input.js (97%) rename webroot/js/{ => components}/chat/chat.js (94%) rename webroot/js/{ => components}/chat/content-editable.js (99%) rename webroot/js/{ => components}/chat/message.js (88%) rename webroot/js/{ => components}/chat/username.js (96%) rename webroot/js/{ => components}/player.js (100%) rename webroot/js/{ => components}/social.js (91%) delete mode 100644 webroot/js/message.js rename webroot/js/{chat/standalone.js => standalone-chat-app.js} (88%) create mode 100644 webroot/js/utils/constants.js rename webroot/js/{utils.js => utils/helpers.js} (79%) delete mode 100644 webroot/js/utils/socket-message-types.js rename webroot/js/{ => utils}/websocket.js (91%) create mode 100644 webroot/styles/app.css create mode 100644 webroot/styles/video.css diff --git a/webroot/js/app2.js b/webroot/js/app2.js index 35e6bd6bd..d0151b8f8 100644 --- a/webroot/js/app2.js +++ b/webroot/js/app2.js @@ -2,12 +2,11 @@ import { h, Component } from 'https://unpkg.com/preact?module'; import htm from 'https://unpkg.com/htm?module'; const html = htm.bind(h); - -import SocialIcon from './social.js'; -import UsernameForm from './chat/username.js'; -import Chat from './chat/chat.js'; -import Websocket from './websocket.js'; -import { OwncastPlayer } from './player.js'; +import { OwncastPlayer } from './components/player.js'; +import SocialIcon from './components/social.js'; +import UsernameForm from './components/chat/username.js'; +import Chat from './components/chat/chat.js'; +import Websocket from './utils/websocket.js'; import { getLocalStorage, @@ -15,19 +14,23 @@ import { clearLocalStorage, generateAvatar, generateUsername, + addNewlines, + pluralize, +} from './utils/helpers.js'; +import { URL_OWNCAST, URL_CONFIG, URL_STATUS, - addNewlines, - pluralize, TIMER_STATUS_UPDATE, TIMER_DISABLE_CHAT_AFTER_OFFLINE, TIMER_STREAM_DURATION_COUNTER, TEMP_IMAGE, MESSAGE_OFFLINE, MESSAGE_ONLINE, -} from './utils.js'; -import { KEY_USERNAME, KEY_AVATAR, KEY_CHAT_DISPLAYED } from './utils/chat.js'; + KEY_USERNAME, + KEY_AVATAR, + KEY_CHAT_DISPLAYED, +} from './utils/constants.js'; export default class App extends Component { constructor(props, context) { diff --git a/webroot/js/components.js b/webroot/js/components.js deleted file mode 100644 index 959e2aa1d..000000000 --- a/webroot/js/components.js +++ /dev/null @@ -1,64 +0,0 @@ -// DELETE THIS FILE LATER. - -Vue.component('owncast-footer', { - props: { - appVersion: { - type: String, - default: '0.1', - }, - }, - - template: ` - - `, -}); - - -Vue.component('stream-tags', { - props: ['tags'], - template: ` - - `, -}); - -Vue.component('user-details', { - props: ['logo', 'platforms', 'summary', 'tags'], - template: ` -
-
- -
-
-

- About - - -

- -
- -
-
- `, -}); diff --git a/webroot/js/chat/chat-input.js b/webroot/js/components/chat/chat-input.js similarity index 97% rename from webroot/js/chat/chat-input.js rename to webroot/js/components/chat/chat-input.js index 0a8d3717f..fd472626b 100644 --- a/webroot/js/chat/chat-input.js +++ b/webroot/js/components/chat/chat-input.js @@ -3,15 +3,10 @@ import htm from 'https://unpkg.com/htm?module'; const html = htm.bind(h); import { EmojiButton } from 'https://cdn.skypack.dev/@joeattardi/emoji-button'; - -import { URL_CUSTOM_EMOJIS, getLocalStorage, setLocalStorage } from '../utils.js'; -import { - KEY_CHAT_FIRST_MESSAGE_SENT, - generatePlaceholderText, - getCaretPosition, -} from '../utils/chat.js'; - import ContentEditable from './content-editable.js'; +import { generatePlaceholderText, getCaretPosition } from '../../utils/chat.js'; +import { getLocalStorage, setLocalStorage } from '../../utils/helpers.js'; +import { URL_CUSTOM_EMOJIS, KEY_CHAT_FIRST_MESSAGE_SENT } from '../../utils/constants.js'; export default class ChatInput extends Component { diff --git a/webroot/js/chat/chat.js b/webroot/js/components/chat/chat.js similarity index 94% rename from webroot/js/chat/chat.js rename to webroot/js/components/chat/chat.js index b248c48d1..119f3ea26 100644 --- a/webroot/js/chat/chat.js +++ b/webroot/js/components/chat/chat.js @@ -3,15 +3,12 @@ import htm from 'https://unpkg.com/htm?module'; // Initialize htm with Preact const html = htm.bind(h); - -import SOCKET_MESSAGE_TYPES from '../utils/socket-message-types.js'; import Message from './message.js'; import ChatInput from './chat-input.js'; -import { CALLBACKS } from '../websocket.js'; - - -import { URL_CHAT_HISTORY, setVHvar, hasTouchScreen } from '../utils.js'; -import { extraUserNamesFromMessageHistory } from '../utils/chat.js'; +import { CALLBACKS, SOCKET_MESSAGE_TYPES } from '../../utils/websocket.js'; +import { setVHvar, hasTouchScreen } from '../../utils/helpers.js'; +import { extraUserNamesFromMessageHistory } from '../../utils/chat.js'; +import { URL_CHAT_HISTORY } from '../../utils/constants.js'; export default class Chat extends Component { constructor(props, context) { @@ -199,3 +196,4 @@ export default class Chat extends Component { } } + diff --git a/webroot/js/chat/content-editable.js b/webroot/js/components/chat/content-editable.js similarity index 99% rename from webroot/js/chat/content-editable.js rename to webroot/js/components/chat/content-editable.js index 40514b8b0..08c41cf19 100644 --- a/webroot/js/chat/content-editable.js +++ b/webroot/js/components/chat/content-editable.js @@ -6,7 +6,6 @@ and here: https://stackoverflow.com/questions/22677931/react-js-onchange-event-for-contenteditable/27255103#27255103 */ - import { Component, createRef, createElement } from 'https://unpkg.com/preact?module'; function replaceCaret(el) { diff --git a/webroot/js/chat/message.js b/webroot/js/components/chat/message.js similarity index 88% rename from webroot/js/chat/message.js rename to webroot/js/components/chat/message.js index 78cecfe81..b4e10f53f 100644 --- a/webroot/js/chat/message.js +++ b/webroot/js/components/chat/message.js @@ -1,9 +1,9 @@ import { html, Component } from "https://unpkg.com/htm/preact/index.mjs?module"; -import { messageBubbleColorForString } from '../utils/user-colors.js'; -import { formatMessageText } from '../utils/chat.js'; -import { generateAvatar } from '../utils.js'; -import SOCKET_MESSAGE_TYPES from '../utils/socket-message-types.js'; +import { messageBubbleColorForString } from '../../utils/user-colors.js'; +import { formatMessageText } from '../../utils/chat.js'; +import { generateAvatar } from '../../utils/helpers.js'; +import { SOCKET_MESSAGE_TYPES } from '../../utils/websocket.js'; export default class Message extends Component { render(props) { diff --git a/webroot/js/chat/username.js b/webroot/js/components/chat/username.js similarity index 96% rename from webroot/js/chat/username.js rename to webroot/js/components/chat/username.js index bb67ba260..013b2abe6 100644 --- a/webroot/js/chat/username.js +++ b/webroot/js/components/chat/username.js @@ -3,8 +3,8 @@ import htm from 'https://unpkg.com/htm?module'; // Initialize htm with Preact const html = htm.bind(h); -import { generateAvatar, setLocalStorage } from '../utils.js'; -import { KEY_USERNAME, KEY_AVATAR } from '../utils/chat.js'; +import { generateAvatar, setLocalStorage } from '../../utils/helpers.js'; +import { KEY_USERNAME, KEY_AVATAR } from '../../utils/constants.js'; export default class UsernameForm extends Component { constructor(props, context) { diff --git a/webroot/js/player.js b/webroot/js/components/player.js similarity index 100% rename from webroot/js/player.js rename to webroot/js/components/player.js diff --git a/webroot/js/social.js b/webroot/js/components/social.js similarity index 91% rename from webroot/js/social.js rename to webroot/js/components/social.js index dc46920a2..0bdf94102 100644 --- a/webroot/js/social.js +++ b/webroot/js/components/social.js @@ -1,6 +1,6 @@ import { html } from "https://unpkg.com/htm/preact/index.mjs?module"; -import { SOCIAL_PLATFORMS } from './utils/social.js'; -import { classNames } from './utils.js'; +import { SOCIAL_PLATFORMS } from '../utils/social.js'; +import { classNames } from '../utils/helpers.js'; export default function SocialIcon(props) { const { platform, url } = props; diff --git a/webroot/js/message.js b/webroot/js/message.js deleted file mode 100644 index 65733bd27..000000000 --- a/webroot/js/message.js +++ /dev/null @@ -1,440 +0,0 @@ -// DELETE THIS FILE LATER. - -import SOCKET_MESSAGE_TYPES from './utils/socket-message-types.js'; - -const KEY_USERNAME = 'owncast_username'; -const KEY_AVATAR = 'owncast_avatar'; -const KEY_CHAT_DISPLAYED = 'owncast_chat'; -const KEY_CHAT_FIRST_MESSAGE_SENT = 'owncast_first_message_sent'; -const CHAT_INITIAL_PLACEHOLDER_TEXT = 'Type here to chat, no account necessary.'; -const CHAT_PLACEHOLDER_TEXT = 'Message'; -const CHAT_PLACEHOLDER_OFFLINE = 'Chat is offline.'; - -class Message { - constructor(model) { - this.author = model.author; - this.body = model.body; - this.image = model.image || generateAvatar(model.author); - this.id = model.id; - this.type = model.type; - } - - formatText() { - showdown.setFlavor('github'); - let formattedText = new showdown.Converter({ - emoji: true, - openLinksInNewWindow: true, - tables: false, - simplifiedAutoLink: false, - literalMidWordUnderscores: true, - strikethrough: true, - ghMentions: false, - }).makeHtml(this.body); - - formattedText = this.linkify(formattedText, this.body); - formattedText = this.highlightUsername(formattedText); - - return addNewlines(formattedText); - } - - // TODO: Move this into a util function once we can organize code - // and split things up. - linkify(text, rawText) { - const urls = getURLs(stripTags(rawText)); - if (urls) { - urls.forEach(function (url) { - let linkURL = url; - - // Add http prefix if none exist in the URL so it actually - // will work in an anchor tag. - if (linkURL.indexOf('http') === -1) { - linkURL = 'http://' + linkURL; - } - - // Remove the protocol prefix in the display URLs just to make - // things look a little nicer. - const displayURL = url.replace(/(^\w+:|^)\/\//, ''); - const link = `${displayURL}`; - text = text.replace(url, link); - - if (getYoutubeIdFromURL(url)) { - if (this.isTextJustURLs(text, [url, displayURL])) { - text = ''; - } else { - text += '
'; - } - - const youtubeID = getYoutubeIdFromURL(url); - text += getYoutubeEmbedFromID(youtubeID); - } else if (url.indexOf('instagram.com/p/') > -1) { - if (this.isTextJustURLs(text, [url, displayURL])) { - text = ''; - } else { - text += `
`; - } - text += getInstagramEmbedFromURL(url); - } else if (isImage(url)) { - if (this.isTextJustURLs(text, [url, displayURL])) { - text = ''; - } else { - text += `
`; - } - text += getImageForURL(url); - } - }.bind(this)); - } - return text; - } - - isTextJustURLs(text, urls) { - for (var i = 0; i < urls.length; i++) { - const url = urls[i]; - if (stripTags(text) === url) { - return true; - } - } - - return false; - } - - userColor() { - return messageBubbleColorForString(this.author); - } - - highlightUsername(message) { - const username = document.getElementById('self-message-author').value; - const pattern = new RegExp('@?' + username.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'), 'gi'); - return message.replace(pattern, '$&'); - } -} - - - -class MessagingInterface { - constructor() { - this.chatDisplayed = false; - this.username = ''; - this.messageCharCount = 0; - this.maxMessageLength = 500; - this.maxMessageBuffer = 20; - this.chatUsernames = []; - - this.onReceivedMessages = this.onReceivedMessages.bind(this); - this.disableChat = this.disableChat.bind(this); - this.enableChat = this.enableChat.bind(this); - } - - init() { - this.tagAppContainer = document.getElementById('app-container'); - this.tagChatToggle = document.getElementById('chat-toggle'); - this.tagUserInfoChanger = document.getElementById('user-info-change'); - this.tagUsernameDisplay = document.getElementById('username-display'); - this.tagMessageFormWarning = document.getElementById('message-form-warning'); - - this.inputMessageAuthor = document.getElementById('self-message-author'); - this.inputChangeUserName = document.getElementById('username-change-input'); - - this.btnUpdateUserName = document.getElementById('button-update-username'); - this.btnCancelUpdateUsername = document.getElementById('button-cancel-change'); - this.btnSubmitMessage = document.getElementById('button-submit-message'); - - this.formMessageInput = document.getElementById('message-body-form'); - - this.imgUsernameAvatar = document.getElementById('username-avatar'); - this.textUserInfoDisplay = document.getElementById('user-info-display'); - - this.scrollableMessagesContainer = document.getElementById('messages-container'); - - // add events - this.tagChatToggle.addEventListener('click', this.handleChatToggle.bind(this)); - this.textUserInfoDisplay.addEventListener('click', this.handleShowChangeNameForm.bind(this)); - - this.btnUpdateUserName.addEventListener('click', this.handleUpdateUsername.bind(this)); - this.btnCancelUpdateUsername.addEventListener('click', this.handleHideChangeNameForm.bind(this)); - - this.inputChangeUserName.addEventListener('keydown', this.handleUsernameKeydown.bind(this)); - this.formMessageInput.addEventListener('keydown', this.handleMessageInputKeydown.bind(this)); - this.formMessageInput.addEventListener('keyup', this.handleMessageInputKeyup.bind(this)); - this.formMessageInput.addEventListener('blur', this.handleMessageInputBlur.bind(this)); - this.btnSubmitMessage.addEventListener('click', this.handleSubmitChatButton.bind(this)); - - this.initLocalStates(); - - if (hasTouchScreen()) { - setVHvar(); - window.addEventListener("orientationchange", setVHvar); - this.tagAppContainer.classList.add('touch-screen'); - } - } - - initLocalStates() { - this.username = getLocalStorage(KEY_USERNAME) || generateUsername(); - this.imgUsernameAvatar.src = - getLocalStorage(KEY_AVATAR) || generateAvatar(`${this.username}${Date.now()}`); - this.updateUsernameFields(this.username); - - this.chatDisplayed = getLocalStorage(KEY_CHAT_DISPLAYED) || true; - this.displayChat(); - this.disableChat(); // Disabled by default. - } - - updateUsernameFields(username) { - this.tagUsernameDisplay.innerText = username; - this.inputChangeUserName.value = username; - this.inputMessageAuthor.value = username; - } - - displayChat() { - if (this.chatDisplayed) { - this.tagAppContainer.classList.add('chat'); - this.tagAppContainer.classList.remove('no-chat'); - jumpToBottom(this.scrollableMessagesContainer); - } else { - this.tagAppContainer.classList.add('no-chat'); - this.tagAppContainer.classList.remove('chat'); - } - this.setChatPlaceholderText(); - } - - - handleChatToggle() { - this.chatDisplayed = !this.chatDisplayed; - if (this.chatDisplayed) { - setLocalStorage(KEY_CHAT_DISPLAYED, this.chatDisplayed); - } else { - clearLocalStorage(KEY_CHAT_DISPLAYED); - } - this.displayChat(); - } - - handleShowChangeNameForm() { - this.textUserInfoDisplay.style.display = 'none'; - this.tagUserInfoChanger.style.display = 'flex'; - if (document.body.clientWidth < 640) { - this.tagChatToggle.style.display = 'none'; - } - } - - handleHideChangeNameForm() { - this.textUserInfoDisplay.style.display = 'flex'; - this.tagUserInfoChanger.style.display = 'none'; - if (document.body.clientWidth < 640) { - this.tagChatToggle.style.display = 'inline-block'; - } - } - - handleUpdateUsername() { - const oldName = this.username; - var newValue = this.inputChangeUserName.value; - newValue = newValue.trim(); - // do other string cleanup? - - if (newValue) { - this.username = newValue; - this.updateUsernameFields(newValue); - this.imgUsernameAvatar.src = generateAvatar(`${newValue}${Date.now()}`); - setLocalStorage(KEY_USERNAME, newValue); - setLocalStorage(KEY_AVATAR, this.imgUsernameAvatar.src); - } - this.handleHideChangeNameForm(); - - if (oldName !== newValue) { - this.sendUsernameChange(oldName, newValue, this.imgUsernameAvatar.src); - } - } - - handleUsernameKeydown(event) { - if (event.keyCode === 13) { // enter - this.handleUpdateUsername(); - } else if (event.keyCode === 27) { // esc - this.handleHideChangeNameForm(); - } - } - - sendUsernameChange(oldName, newName, image) { - const nameChange = { - type: SOCKET_MESSAGE_TYPES.NAME_CHANGE, - oldName: oldName, - newName: newName, - image: image, - }; - - this.send(nameChange); - } - - tryToComplete() { - const rawValue = this.formMessageInput.innerHTML; - const position = getCaretPosition(this.formMessageInput); - const at = rawValue.lastIndexOf('@', position - 1); - - if (at === -1) { - return false; - } - - var partial = rawValue.substring(at + 1, position).trim(); - - if (partial === this.suggestion) { - partial = this.partial; - } else { - this.partial = partial; - } - - const possibilities = this.chatUsernames.filter(function (username) { - return username.toLowerCase().startsWith(partial.toLowerCase()); - }); - - if (this.completionIndex === undefined || ++this.completionIndex >= possibilities.length) { - this.completionIndex = 0; - } - - if (possibilities.length > 0) { - this.suggestion = possibilities[this.completionIndex]; - - // TODO: Fix the space not working. I'm guessing because the DOM ignores spaces and it requires a nbsp or something? - this.formMessageInput.innerHTML = rawValue.substring(0, at + 1) + this.suggestion + ' ' + rawValue.substring(position); - setCaretPosition(this.formMessageInput, at + this.suggestion.length + 2); - } - - return true; - } - - handleMessageInputKeydown(event) { - var okCodes = [37,38,39,40,16,91,18,46,8]; - var value = this.formMessageInput.innerHTML.trim(); - var numCharsLeft = this.maxMessageLength - value.length; - if (event.keyCode === 13) { // enter - if (!this.prepNewLine) { - this.submitChat(value); - event.preventDefault(); - this.prepNewLine = false; - - return; - } - } - if (event.keyCode === 16 || event.keyCode === 17) { // ctrl, shift - this.prepNewLine = true; - } - if (event.keyCode === 9) { // tab - if (this.tryToComplete()) { - event.preventDefault(); - - // value could have been changed, update variables - value = this.formMessageInput.innerHTML.trim(); - numCharsLeft = this.maxMessageLength - value.length; - } - } - - if (numCharsLeft <= this.maxMessageBuffer) { - this.tagMessageFormWarning.innerText = `${numCharsLeft} chars left`; - if (numCharsLeft <= 0 && !okCodes.includes(event.keyCode)) { - event.preventDefault(); - return; - } - } else { - this.tagMessageFormWarning.innerText = ''; - } - } - - handleMessageInputKeyup(event) { - if (event.keyCode === 16 || event.keyCode === 17) { // ctrl, shift - this.prepNewLine = false; - } - } - - handleMessageInputBlur(event) { - this.prepNewLine = false; - } - - handleSubmitChatButton(event) { - var value = this.formMessageInput.innerHTML.trim(); - if (value) { - this.submitChat(value); - event.preventDefault(); - return false; - } - event.preventDefault(); - return false; - } - - submitChat(content) { - if (!content) { - return; - } - var message = new Message({ - body: content, - author: this.username, - image: this.imgUsernameAvatar.src, - type: SOCKET_MESSAGE_TYPES.CHAT, - }); - this.send(message); - - // clear out things. - this.formMessageInput.innerHTML = ''; - this.tagMessageFormWarning.innerText = ''; - - const hasSentFirstChatMessage = getLocalStorage(KEY_CHAT_FIRST_MESSAGE_SENT); - if (!hasSentFirstChatMessage) { - setLocalStorage(KEY_CHAT_FIRST_MESSAGE_SENT, true); - this.setChatPlaceholderText(); - } - } - - disableChat() { - if (this.formMessageInput) { - this.formMessageInput.contentEditable = false; - this.formMessageInput.innerHTML = ''; - this.formMessageInput.setAttribute("placeholder", CHAT_PLACEHOLDER_OFFLINE); - } - } - - enableChat() { - if (this.formMessageInput) { - this.formMessageInput.contentEditable = true; - this.setChatPlaceholderText(); - } - } - - setChatPlaceholderText() { - // NOTE: This is a fake placeholder that is being styled via CSS. - // You can't just set the .placeholder property because it's not a form element. - const hasSentFirstChatMessage = getLocalStorage(KEY_CHAT_FIRST_MESSAGE_SENT); - const placeholderText = hasSentFirstChatMessage ? CHAT_PLACEHOLDER_TEXT : CHAT_INITIAL_PLACEHOLDER_TEXT; - this.formMessageInput.setAttribute("placeholder", placeholderText); - } - - // handle Vue.js message display - onReceivedMessages(newMessages, oldMessages) { - // update the list of chat usernames - newMessages.slice(oldMessages.length).forEach(function (message) { - var username; - - switch (message.type) { - case SOCKET_MESSAGE_TYPES.CHAT: - username = message.author; - break; - - case SOCKET_MESSAGE_TYPES.NAME_CHANGE: - username = message.newName; - break; - - default: - return; - } - - if (!this.chatUsernames.includes(username)) { - this.chatUsernames.push(username); - } - }, this); - - if (newMessages.length !== oldMessages.length) { - // jump to bottom - jumpToBottom(this.scrollableMessagesContainer); - } - } - - send(messageJSON) { - console.error('MessagingInterface send() is not linked to the websocket component.'); - } -} - -export { Message, MessagingInterface } diff --git a/webroot/js/chat/standalone.js b/webroot/js/standalone-chat-app.js similarity index 88% rename from webroot/js/chat/standalone.js rename to webroot/js/standalone-chat-app.js index 115982d63..221083466 100644 --- a/webroot/js/chat/standalone.js +++ b/webroot/js/standalone-chat-app.js @@ -2,13 +2,12 @@ import { h, Component, Fragment } from 'https://unpkg.com/preact?module'; import htm from 'https://unpkg.com/htm?module'; const html = htm.bind(h); +import UsernameForm from './components/chat/username.js'; +import Chat from './components/chat.js'; +import Websocket from './utils/websocket.js'; -import UsernameForm from './username.js'; -import Chat from './chat.js'; -import Websocket from '../websocket.js'; - -import { getLocalStorage, generateAvatar, generateUsername } from '../utils.js'; -import { KEY_USERNAME, KEY_AVATAR } from '../utils/chat.js'; +import { getLocalStorage, generateAvatar, generateUsername } from './utils/helpers.js'; +import { KEY_USERNAME, KEY_AVATAR } from '../utils/constants.js'; export default class StandaloneChat extends Component { constructor(props, context) { diff --git a/webroot/js/utils/chat.js b/webroot/js/utils/chat.js index 4ce504f43..b7db2659c 100644 --- a/webroot/js/utils/chat.js +++ b/webroot/js/utils/chat.js @@ -1,12 +1,13 @@ -import { addNewlines } from '../utils.js'; - -export const KEY_USERNAME = 'owncast_username'; -export const KEY_AVATAR = 'owncast_avatar'; -export const KEY_CHAT_DISPLAYED = 'owncast_chat'; -export const KEY_CHAT_FIRST_MESSAGE_SENT = 'owncast_first_message_sent'; -export const CHAT_INITIAL_PLACEHOLDER_TEXT = 'Type here to chat, no account necessary.'; -export const CHAT_PLACEHOLDER_TEXT = 'Message'; -export const CHAT_PLACEHOLDER_OFFLINE = 'Chat is offline.'; +import { addNewlines } from './helpers.js'; +import { + KEY_USERNAME, + KEY_AVATAR, + KEY_CHAT_DISPLAYED, + KEY_CHAT_FIRST_MESSAGE_SENT, + CHAT_INITIAL_PLACEHOLDER_TEXT, + CHAT_PLACEHOLDER_TEXT, + CHAT_PLACEHOLDER_OFFLINE, +} from './constants.js'; export function formatMessageText(message, username) { showdown.setFlavor('github'); diff --git a/webroot/js/utils/constants.js b/webroot/js/utils/constants.js new file mode 100644 index 000000000..a21d32997 --- /dev/null +++ b/webroot/js/utils/constants.js @@ -0,0 +1,29 @@ +// misc constants used throughout the app + +export const URL_STATUS = `/status`; +export const URL_CHAT_HISTORY = `/chat`; +export const URL_CUSTOM_EMOJIS = `/emoji`; +export const URL_CONFIG = `/config`; + +// TODO: This directory is customizable in the config. So we should expose this via the config API. +export const URL_STREAM = `/hls/stream.m3u8`; +export const URL_WEBSOCKET = `${location.protocol === 'https:' ? 'wss' : 'ws'}://${location.host}/entry`; + +export const TIMER_STATUS_UPDATE = 5000; // ms +export const TIMER_DISABLE_CHAT_AFTER_OFFLINE = 5 * 60 * 1000; // 5 mins +export const TIMER_STREAM_DURATION_COUNTER = 1000; +export const TEMP_IMAGE = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'; + +export const MESSAGE_OFFLINE = 'Stream is offline.'; +export const MESSAGE_ONLINE = 'Stream is online'; + +export const URL_OWNCAST = 'https://github.com/gabek/owncast'; // used in footer + + +export const KEY_USERNAME = 'owncast_username'; +export const KEY_AVATAR = 'owncast_avatar'; +export const KEY_CHAT_DISPLAYED = 'owncast_chat'; +export const KEY_CHAT_FIRST_MESSAGE_SENT = 'owncast_first_message_sent'; +export const CHAT_INITIAL_PLACEHOLDER_TEXT = 'Type here to chat, no account necessary.'; +export const CHAT_PLACEHOLDER_TEXT = 'Message'; +export const CHAT_PLACEHOLDER_OFFLINE = 'Chat is offline.'; diff --git a/webroot/js/utils.js b/webroot/js/utils/helpers.js similarity index 79% rename from webroot/js/utils.js rename to webroot/js/utils/helpers.js index 2be01ff7f..6962dfd61 100644 --- a/webroot/js/utils.js +++ b/webroot/js/utils/helpers.js @@ -1,22 +1,3 @@ -export const URL_STATUS = `/status`; -export const URL_CHAT_HISTORY = `/chat`; -export const URL_CUSTOM_EMOJIS = `/emoji`; -export const URL_CONFIG = `/config`; - -// TODO: This directory is customizable in the config. So we should expose this via the config API. -export const URL_STREAM = `/hls/stream.m3u8`; -export const URL_WEBSOCKET = `${location.protocol === 'https:' ? 'wss' : 'ws'}://${location.host}/entry`; - -export const TIMER_STATUS_UPDATE = 5000; // ms -export const TIMER_DISABLE_CHAT_AFTER_OFFLINE = 5 * 60 * 1000; // 5 mins -export const TIMER_STREAM_DURATION_COUNTER = 1000; -export const TEMP_IMAGE = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'; - -export const MESSAGE_OFFLINE = 'Stream is offline.'; -export const MESSAGE_ONLINE = 'Stream is online'; - -export const URL_OWNCAST = 'https://github.com/gabek/owncast'; // used in footer - export function getLocalStorage(key) { try { return localStorage.getItem(key); diff --git a/webroot/js/utils/social.js b/webroot/js/utils/social.js index dad57a546..9f42063e5 100644 --- a/webroot/js/utils/social.js +++ b/webroot/js/utils/social.js @@ -1,4 +1,3 @@ - // x, y pixel psitions of /img/social.gif image. export const SOCIAL_PLATFORMS = { default: { diff --git a/webroot/js/utils/socket-message-types.js b/webroot/js/utils/socket-message-types.js deleted file mode 100644 index f52b57a3e..000000000 --- a/webroot/js/utils/socket-message-types.js +++ /dev/null @@ -1,11 +0,0 @@ -/** - * These are the types of messages that we can handle with the websocket. - * Mostly used by `websocket.js` but if other components need to handle - * different types then it can import this file. - */ -export default { - CHAT: 'CHAT', - PING: 'PING', - NAME_CHANGE: 'NAME_CHANGE', - PONG: 'PONG' -}; diff --git a/webroot/js/websocket.js b/webroot/js/utils/websocket.js similarity index 91% rename from webroot/js/websocket.js rename to webroot/js/utils/websocket.js index 3b558f99f..bc392faa6 100644 --- a/webroot/js/websocket.js +++ b/webroot/js/utils/websocket.js @@ -1,8 +1,14 @@ -import SOCKET_MESSAGE_TYPES from './utils/socket-message-types.js'; - -const URL_WEBSOCKET = `${location.protocol === 'https:' ? 'wss' : 'ws'}://${location.host}/entry`; - -const TIMER_WEBSOCKET_RECONNECT = 5000; // ms +/** + * These are the types of messages that we can handle with the websocket. + * Mostly used by `websocket.js` but if other components need to handle + * different types then it can import this file. + */ +export const SOCKET_MESSAGE_TYPES = { + CHAT: 'CHAT', + PING: 'PING', + NAME_CHANGE: 'NAME_CHANGE', + PONG: 'PONG' +}; export const CALLBACKS = { RAW_WEBSOCKET_MESSAGE_RECEIVED: 'rawWebsocketMessageReceived', @@ -10,8 +16,10 @@ export const CALLBACKS = { WEBSOCKET_DISCONNECTED: 'websocketDisconnected', } -class Websocket { +const URL_WEBSOCKET = `${location.protocol === 'https:' ? 'wss' : 'ws'}://${location.host}/entry`; +const TIMER_WEBSOCKET_RECONNECT = 5000; // ms +export default class Websocket { constructor() { this.websocket = null; this.websocketReconnectTimer = null; @@ -133,7 +141,5 @@ class Websocket { handleNetworkingError(error) { console.error(`Websocket Error: ${error}`) - }; + } } - -export default Websocket; diff --git a/webroot/standalone-chat.html b/webroot/standalone-chat.html index fcb2001ea..ec3899684 100644 --- a/webroot/standalone-chat.html +++ b/webroot/standalone-chat.html @@ -19,7 +19,7 @@