mirror of
https://github.com/owncast/owncast.git
synced 2024-10-10 19:16:02 +00:00
- fix chrome mobile form focus bug by specifying class. when form focuses media query widths change and may think portrait is in landcape and therefore hide the form.
- cleanup now unused methods - jump to bottom from vue prop listener
This commit is contained in:
parent
594e1c774a
commit
cf27b157e6
@ -87,11 +87,8 @@ GW TODO:
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="user-content" class="user-content">
|
<div id="user-content" class="user-content">
|
||||||
|
|
||||||
<!-- USER CONTENT... -->
|
<!-- USER CONTENT... -->
|
||||||
<div v-html="description"></div>
|
<div v-html="description"></div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -101,13 +98,12 @@ GW TODO:
|
|||||||
|
|
||||||
|
|
||||||
<div id="user-content-touch" class="user-content">
|
<div id="user-content-touch" class="user-content">
|
||||||
|
|
||||||
<!-- USER CONTENT... -->
|
<!-- USER CONTENT... -->
|
||||||
<div v-html="description"></div>
|
<div v-html="description"></div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="chat-container" class="bg-gray-800">
|
<div id="chat-container" class="bg-gray-800">
|
||||||
|
|
||||||
<div id="messages-container">
|
<div id="messages-container">
|
||||||
<div v-for="message in messages">
|
<div v-for="message in messages">
|
||||||
<div class="message flex">
|
<div class="message flex">
|
||||||
|
@ -7,6 +7,7 @@ async function setupApp() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
window.app = new Vue({
|
window.app = new Vue({
|
||||||
el: "#app-container",
|
el: "#app-container",
|
||||||
data: {
|
data: {
|
||||||
@ -18,11 +19,23 @@ async function setupApp() {
|
|||||||
description: "",
|
description: "",
|
||||||
title: "",
|
title: "",
|
||||||
},
|
},
|
||||||
|
watch: {
|
||||||
|
messages: {
|
||||||
|
deep: true,
|
||||||
|
handler: function (newMessages, oldMessages) {
|
||||||
|
if (newMessages.length !== oldMessages.length) {
|
||||||
|
// jump to bottom
|
||||||
|
jumpToBottom(appMessaging.scrollableMessagesContainer);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
// init messaging interactions
|
// init messaging interactions
|
||||||
var appMessagingMisc = new Messaging();
|
var appMessaging = new Messaging();
|
||||||
appMessagingMisc.init();
|
appMessaging.init();
|
||||||
|
|
||||||
const config = await new Config().init();
|
const config = await new Config().init();
|
||||||
app.title = config.title;
|
app.title = config.title;
|
||||||
@ -46,7 +59,7 @@ async function setupApp() {
|
|||||||
|
|
||||||
var websocketReconnectTimer;
|
var websocketReconnectTimer;
|
||||||
function setupWebsocket() {
|
function setupWebsocket() {
|
||||||
clearTimeout(websocketReconnectTimer)
|
clearTimeout(websocketReconnectTimer);
|
||||||
|
|
||||||
// Uncomment to point to somewhere other than goth.land
|
// Uncomment to point to somewhere other than goth.land
|
||||||
const protocol = location.protocol == "https:" ? "wss" : "ws"
|
const protocol = location.protocol == "https:" ? "wss" : "ws"
|
||||||
@ -60,35 +73,34 @@ function setupWebsocket() {
|
|||||||
// Ignore non-chat messages (such as keepalive PINGs)
|
// Ignore non-chat messages (such as keepalive PINGs)
|
||||||
if (model.type !== SocketMessageTypes.CHAT) { return; }
|
if (model.type !== SocketMessageTypes.CHAT) { return; }
|
||||||
|
|
||||||
const message = new Message(model)
|
const message = new Message(model);
|
||||||
|
|
||||||
const existing = this.app.messages.filter(function (item) {
|
const existing = this.app.messages.filter(function (item) {
|
||||||
return item.id === message.id
|
return item.id === message.id;
|
||||||
})
|
})
|
||||||
|
|
||||||
if (existing.length === 0 || !existing) {
|
if (existing.length === 0 || !existing) {
|
||||||
this.app.messages.push(message);
|
this.app.messages = [...this.app.messages, message];
|
||||||
setTimeout(() => { jumpToBottom("#messages-container"); } , 50); // could be better. is there a sort of Vue "componentDidUpdate" we can do this on?
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ws.onclose = (e) => {
|
ws.onclose = (e) => {
|
||||||
// connection closed, discard old websocket and create a new one in 5s
|
// connection closed, discard old websocket and create a new one in 5s
|
||||||
ws = null
|
ws = null;
|
||||||
console.log("Websocket closed.")
|
console.log("Websocket closed.")
|
||||||
websocketReconnectTimer = setTimeout(setupWebsocket, 5000)
|
websocketReconnectTimer = setTimeout(setupWebsocket, 5000);
|
||||||
}
|
}
|
||||||
|
|
||||||
// On ws error just close the socket and let it re-connect again for now.
|
// On ws error just close the socket and let it re-connect again for now.
|
||||||
ws.onerror = (e) => {
|
ws.onerror = (e) => {
|
||||||
console.log("Websocket error: ", e)
|
console.log("Websocket error: ", e);
|
||||||
ws.close()
|
ws.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
window.ws = ws;
|
window.ws = ws;
|
||||||
}
|
}
|
||||||
|
|
||||||
setupApp()
|
setupApp();
|
||||||
|
|
||||||
setupWebsocket()
|
setupWebsocket();
|
||||||
|
|
||||||
|
@ -12,12 +12,9 @@ class Message {
|
|||||||
this.type = model.type;
|
this.type = model.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
addNewlines(str) {
|
|
||||||
return str.replace(/(?:\r\n|\r|\n)/g, '<br />');
|
|
||||||
}
|
|
||||||
formatText() {
|
formatText() {
|
||||||
var linked = autoLink(this.body, { embed: true });
|
var linked = autoLink(this.body, { embed: true });
|
||||||
return this.addNewlines(linked);
|
return addNewlines(linked);
|
||||||
}
|
}
|
||||||
userColor() {
|
userColor() {
|
||||||
return messageBubbleColorForString(this.author);
|
return messageBubbleColorForString(this.author);
|
||||||
@ -25,7 +22,6 @@ class Message {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// convert newlines to <br>s
|
|
||||||
|
|
||||||
class Messaging {
|
class Messaging {
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -41,25 +37,24 @@ class Messaging {
|
|||||||
this.keyChatDisplayed = "owncast_chat";
|
this.keyChatDisplayed = "owncast_chat";
|
||||||
|
|
||||||
this.tagAppContainer = document.querySelector("#app-container");
|
this.tagAppContainer = document.querySelector("#app-container");
|
||||||
|
|
||||||
this.tagChatToggle = document.querySelector("#chat-toggle");
|
this.tagChatToggle = document.querySelector("#chat-toggle");
|
||||||
|
|
||||||
this.textUserInfoDisplay = document.querySelector("#user-info-display");
|
|
||||||
this.tagUserInfoChanger = document.querySelector("#user-info-change");
|
this.tagUserInfoChanger = document.querySelector("#user-info-change");
|
||||||
|
|
||||||
this.tagUsernameDisplay = document.querySelector("#username-display");
|
this.tagUsernameDisplay = document.querySelector("#username-display");
|
||||||
this.imgUsernameAvatar = document.querySelector("#username-avatar");
|
|
||||||
|
|
||||||
this.inputMessageAuthor = document.querySelector("#self-message-author");
|
|
||||||
|
|
||||||
this.tagMessageFormWarning = document.querySelector("#message-form-warning");
|
this.tagMessageFormWarning = document.querySelector("#message-form-warning");
|
||||||
|
|
||||||
|
this.inputMessageAuthor = document.querySelector("#self-message-author");
|
||||||
this.inputChangeUserName = document.querySelector("#username-change-input");
|
this.inputChangeUserName = document.querySelector("#username-change-input");
|
||||||
|
|
||||||
this.btnUpdateUserName = document.querySelector("#button-update-username");
|
this.btnUpdateUserName = document.querySelector("#button-update-username");
|
||||||
this.btnCancelUpdateUsername = document.querySelector("#button-cancel-change");
|
this.btnCancelUpdateUsername = document.querySelector("#button-cancel-change");
|
||||||
this.btnSubmitMessage = document.querySelector("#button-submit-message");
|
this.btnSubmitMessage = document.querySelector("#button-submit-message");
|
||||||
|
|
||||||
this.formMessageInput = document.querySelector("#message-body-form");
|
this.formMessageInput = document.querySelector("#message-body-form");
|
||||||
|
|
||||||
|
this.imgUsernameAvatar = document.querySelector("#username-avatar");
|
||||||
|
this.textUserInfoDisplay = document.querySelector("#user-info-display");
|
||||||
|
|
||||||
|
this.scrollableMessagesContainer = document.querySelector("#messages-container");
|
||||||
}
|
}
|
||||||
init() {
|
init() {
|
||||||
this.tagChatToggle.addEventListener("click", this.handleChatToggle.bind(this));
|
this.tagChatToggle.addEventListener("click", this.handleChatToggle.bind(this));
|
||||||
@ -74,16 +69,13 @@ class Messaging {
|
|||||||
this.initLocalStates();
|
this.initLocalStates();
|
||||||
|
|
||||||
if (hasTouchScreen()) {
|
if (hasTouchScreen()) {
|
||||||
|
this.scrollableMessagesContainer = document.body;
|
||||||
this.tagAppContainer.classList.add("touch-screen");
|
this.tagAppContainer.classList.add("touch-screen");
|
||||||
window.onorientationchange = this.handleOrientationChange.bind(this);
|
window.onorientationchange = this.handleOrientationChange.bind(this);
|
||||||
this.handleOrientationChange();
|
this.handleOrientationChange();
|
||||||
|
|
||||||
// this.formMessageInput.addEventListener("focus", this.handleKeyboardAppear.bind(this));
|
|
||||||
// this.formMessageInput.addEventListener("blur", this.handleKeyboardOut.bind(this));
|
|
||||||
} else {
|
} else {
|
||||||
this.tagAppContainer.classList.add("desktop");
|
this.tagAppContainer.classList.add("desktop");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
initLocalStates() {
|
initLocalStates() {
|
||||||
@ -103,7 +95,7 @@ class Messaging {
|
|||||||
if (this.chatDisplayed) {
|
if (this.chatDisplayed) {
|
||||||
this.tagAppContainer.classList.add("chat");
|
this.tagAppContainer.classList.add("chat");
|
||||||
this.tagAppContainer.classList.remove("no-chat");
|
this.tagAppContainer.classList.remove("no-chat");
|
||||||
setTimeout(() => { jumpToBottom(); } , 50);
|
jumpToBottom(this.scrollableMessagesContainer);
|
||||||
} else {
|
} else {
|
||||||
this.tagAppContainer.classList.add("no-chat");
|
this.tagAppContainer.classList.add("no-chat");
|
||||||
this.tagAppContainer.classList.remove("chat");
|
this.tagAppContainer.classList.remove("chat");
|
||||||
@ -111,10 +103,6 @@ class Messaging {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleOrientationChange() {
|
handleOrientationChange() {
|
||||||
// mobileVHhack();
|
|
||||||
// if small landscape, hide chat
|
|
||||||
// var mql = window.matchMedia("(orientation: landscape)"); // what it _was_
|
|
||||||
|
|
||||||
var isPortrait = Math.abs(window.orientation % 180) === 0;
|
var isPortrait = Math.abs(window.orientation % 180) === 0;
|
||||||
|
|
||||||
if(!isPortrait) {
|
if(!isPortrait) {
|
||||||
@ -128,15 +116,6 @@ class Messaging {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleKeyboardAppear() {
|
|
||||||
// setTimeout(() => {this.tagAppContainer.classList.add("message-input-focus");}, 50);
|
|
||||||
// mobileVHhack();
|
|
||||||
// }
|
|
||||||
// handleKeyboardOut() {
|
|
||||||
// setTimeout(() => {this.tagAppContainer.classList.remove("message-input-focus");}, 50);
|
|
||||||
// mobileVHhack();
|
|
||||||
// }
|
|
||||||
|
|
||||||
handleChatToggle() {
|
handleChatToggle() {
|
||||||
this.chatDisplayed = !this.chatDisplayed;
|
this.chatDisplayed = !this.chatDisplayed;
|
||||||
if (this.chatDisplayed) {
|
if (this.chatDisplayed) {
|
||||||
@ -179,7 +158,6 @@ class Messaging {
|
|||||||
var okCodes = [37,38,39,40,16,91,18,46,8];
|
var okCodes = [37,38,39,40,16,91,18,46,8];
|
||||||
var value = this.formMessageInput.value.trim();
|
var value = this.formMessageInput.value.trim();
|
||||||
var numCharsLeft = this.maxMessageLength - value.length;
|
var numCharsLeft = this.maxMessageLength - value.length;
|
||||||
|
|
||||||
if (event.keyCode === 13) { // enter
|
if (event.keyCode === 13) { // enter
|
||||||
if (!this.prepNewLine) {
|
if (!this.prepNewLine) {
|
||||||
this.submitChat(value);
|
this.submitChat(value);
|
||||||
|
@ -22,13 +22,17 @@ function clearLocalStorage(key) {
|
|||||||
localStorage.removeItem(key);
|
localStorage.removeItem(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
function jumpToBottom(id) {
|
// jump down to the max height of a div, with a slight delay
|
||||||
const div = id ? document.querySelector(id) : document.body;
|
function jumpToBottom(element) {
|
||||||
div.scrollTo({
|
if (!element) return;
|
||||||
top: div.scrollHeight,
|
|
||||||
|
setTimeout(() => {
|
||||||
|
element.scrollTo({
|
||||||
|
top: element.scrollHeight,
|
||||||
left: 0,
|
left: 0,
|
||||||
behavior: 'smooth'
|
behavior: 'smooth'
|
||||||
});
|
});
|
||||||
|
}, 50, element);
|
||||||
}
|
}
|
||||||
|
|
||||||
function uuidv4() {
|
function uuidv4() {
|
||||||
@ -38,17 +42,10 @@ function uuidv4() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function setVHvar() {
|
// convert newlines to <br>s
|
||||||
var vh = window.innerHeight * 0.01;
|
function addNewlines(str) {
|
||||||
// Then we set the value in the --vh custom property to the root of the document
|
return str.replace(/(?:\r\n|\r|\n)/g, '<br />');
|
||||||
document.documentElement.style.setProperty('--vh', `${vh}px`);
|
|
||||||
console.log("== new vh", vh)
|
|
||||||
}
|
}
|
||||||
// delayed
|
|
||||||
function mobileVHhack() {
|
|
||||||
setTimeout(setVHvar, 100);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Trying to determine if browser is mobile/tablet.
|
// Trying to determine if browser is mobile/tablet.
|
||||||
// Source: https://developer.mozilla.org/en-US/docs/Web/HTTP/Browser_detection_using_the_user_agent
|
// Source: https://developer.mozilla.org/en-US/docs/Web/HTTP/Browser_detection_using_the_user_agent
|
||||||
|
@ -9,6 +9,17 @@
|
|||||||
body {
|
body {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Tailwind sets list styles to none. I don't know why. */
|
||||||
|
ol {
|
||||||
|
list-style: decimal;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
list-style: unset;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
::-webkit-scrollbar {
|
::-webkit-scrollbar {
|
||||||
width: 0px;
|
width: 0px;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
@ -378,6 +389,7 @@ header h1 {
|
|||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@media screen and (max-width: 640px ) {
|
@media screen and (max-width: 640px ) {
|
||||||
:root {
|
:root {
|
||||||
--video-container-height: 36vh;
|
--video-container-height: 36vh;
|
||||||
@ -391,28 +403,20 @@ header h1 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media screen and (orientation: landscape) and (max-width: 1024px) {
|
@media screen and (orientation: landscape) and (max-width: 1024px) {
|
||||||
:root {
|
:root .landscape {
|
||||||
--video-container-height: 75vh;
|
--video-container-height: 75vh;
|
||||||
}
|
}
|
||||||
#main-mobile-container {
|
.touch-screen.landscape #chat-container-wrap {
|
||||||
margin-top: calc(var(--header-height) + var(--video-container-height));
|
margin-top: calc(var(--header-height) + var(--video-container-height));
|
||||||
}
|
}
|
||||||
.touch-screen .user-content {
|
.touch-screen.landscape .user-content {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
.touch-screen #chat-container {
|
.touch-screen.landscape #chat-container {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
.touch-screen #chat-toggle {
|
.touch-screen.landscape #chat-toggle {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Tailwind sets list styles to none. I don't know why. */
|
|
||||||
ol {
|
|
||||||
list-style: decimal;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul {
|
|
||||||
list-style: unset;
|
|
||||||
}
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user