- 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:
Ginger Wong 2020-06-18 00:06:10 -07:00
parent 594e1c774a
commit cf27b157e6
5 changed files with 69 additions and 82 deletions

View File

@ -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">

View File

@ -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();

View File

@ -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);

View File

@ -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

View File

@ -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;
}