aboutsummaryrefslogtreecommitdiff
path: root/src/components/chat
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/chat')
-rw-r--r--src/components/chat/chat.js63
-rw-r--r--src/components/chat/chat.scss32
-rw-r--r--src/components/chat/chat.vue2
-rw-r--r--src/components/chat/chat_layout.js100
-rw-r--r--src/components/chat/chat_layout_utils.js3
5 files changed, 65 insertions, 135 deletions
diff --git a/src/components/chat/chat.js b/src/components/chat/chat.js
index 6e23c20c..9c4e5b05 100644
--- a/src/components/chat/chat.js
+++ b/src/components/chat/chat.js
@@ -2,29 +2,26 @@ import _ from 'lodash'
import { WSConnectionStatus } from '../../services/api/api.service.js'
import { mapGetters, mapState } from 'vuex'
import ChatMessage from '../chat_message/chat_message.vue'
-import ChatAvatar from '../chat_avatar/chat_avatar.vue'
import PostStatusForm from '../post_status_form/post_status_form.vue'
import ChatTitle from '../chat_title/chat_title.vue'
import chatService from '../../services/chat_service/chat_service.js'
-import ChatLayout from './chat_layout.js'
import { getScrollPosition, getNewTopPosition, isBottomedOut, scrollableContainerHeight } from './chat_layout_utils.js'
const BOTTOMED_OUT_OFFSET = 10
const JUMP_TO_BOTTOM_BUTTON_VISIBILITY_OFFSET = 150
+const SAFE_RESIZE_TIME_OFFSET = 100
const Chat = {
components: {
ChatMessage,
ChatTitle,
- ChatAvatar,
PostStatusForm
},
- mixins: [ChatLayout],
data () {
return {
jumpToBottomButtonVisible: false,
hoveredMessageChainId: undefined,
- scrollPositionBeforeResize: {},
+ lastScrollPosition: {},
scrollableContainerHeight: '100%',
errorLoadingChat: false
}
@@ -119,6 +116,7 @@ const Chat = {
},
onFilesDropped () {
this.$nextTick(() => {
+ this.handleResize()
this.updateScrollableContainerHeight()
})
},
@@ -129,13 +127,30 @@ const Chat = {
}
})
},
- handleLayoutChange () {
- this.updateScrollableContainerHeight()
- if (this.mobileLayout) {
- this.setMobileChatLayout()
- } else {
- this.unsetMobileChatLayout()
+ setChatLayout () {
+ // This is a hacky way to adjust the global layout to the mobile chat (without modifying the rest of the app).
+ // This layout prevents empty spaces from being visible at the bottom
+ // of the chat on iOS Safari (`safe-area-inset`) when
+ // - the on-screen keyboard appears and the user starts typing
+ // - the user selects the text inside the input area
+ // - the user selects and deletes the text that is multiple lines long
+ // TODO: unify the chat layout with the global layout.
+ let html = document.querySelector('html')
+ if (html) {
+ html.classList.add('chat-layout')
}
+
+ this.$nextTick(() => {
+ this.updateScrollableContainerHeight()
+ })
+ },
+ unsetChatLayout () {
+ let html = document.querySelector('html')
+ if (html) {
+ html.classList.remove('chat-layout')
+ }
+ },
+ handleLayoutChange () {
this.$nextTick(() => {
this.updateScrollableContainerHeight()
this.scrollDown()
@@ -149,15 +164,24 @@ const Chat = {
this.scrollableContainerHeight = scrollableContainerHeight(inner, header, footer) + 'px'
},
// Preserves the scroll position when OSK appears or the posting form changes its height.
- handleResize (opts) {
+ handleResize (opts = {}) {
+ const { expand = false, delayed = false } = opts
+
+ if (delayed) {
+ setTimeout(() => {
+ this.handleResize({ ...opts, delayed: false })
+ }, SAFE_RESIZE_TIME_OFFSET)
+ return
+ }
+
this.$nextTick(() => {
this.updateScrollableContainerHeight()
- const { offsetHeight = undefined } = this.scrollPositionBeforeResize
- this.scrollPositionBeforeResize = getScrollPosition(this.$refs.scrollable)
+ const { offsetHeight = undefined } = this.lastScrollPosition
+ this.lastScrollPosition = getScrollPosition(this.$refs.scrollable)
- const diff = this.scrollPositionBeforeResize.offsetHeight - offsetHeight
- if (diff < 0 || (!this.bottomedOut() && opts && opts.expand)) {
+ const diff = this.lastScrollPosition.offsetHeight - offsetHeight
+ if (diff < 0 || (!this.bottomedOut() && expand)) {
this.$nextTick(() => {
this.updateScrollableContainerHeight()
this.$refs.scrollable.scrollTo({
@@ -281,7 +305,12 @@ const Chat = {
.then(data => {
this.$store.dispatch('addChatMessages', { chatId: this.currentChat.id, messages: [data] }).then(() => {
this.$nextTick(() => {
- this.updateScrollableContainerHeight()
+ this.handleResize()
+ // When the posting form size changes because of a media attachment, we need an extra resize
+ // to account for the potential delay in the DOM update.
+ setTimeout(() => {
+ this.updateScrollableContainerHeight()
+ }, SAFE_RESIZE_TIME_OFFSET)
this.scrollDown({ forceRead: true })
})
})
diff --git a/src/components/chat/chat.scss b/src/components/chat/chat.scss
index 13c52ea3..6ae7ebc9 100644
--- a/src/components/chat/chat.scss
+++ b/src/components/chat/chat.scss
@@ -3,14 +3,17 @@
height: calc(100vh - 60px);
width: 100%;
+ .chat-title {
+ // prevents chat header jumping on when the user avatar loads
+ height: 28px;
+ }
+
.chat-view-inner {
height: auto;
width: 100%;
overflow: visible;
display: flex;
- margin-top: 0.5em;
- margin-left: 0.5em;
- margin-right: 0.5em;
+ margin: 0.5em 0.5em 0 0.5em;
}
.chat-view-body {
@@ -19,23 +22,18 @@
flex-direction: column;
width: 100%;
overflow: visible;
- border-radius: none;
min-height: 100%;
- margin-left: 0;
- margin-right: 0;
- margin-bottom: 0em;
- margin-top: 0em;
+ margin: 0 0 0 0;
border-radius: 10px 10px 0 0;
border-radius: var(--panelRadius, 10px) var(--panelRadius, 10px) 0 0 ;
&::after {
- border-radius: none;
- box-shadow: none;
+ border-radius: 0;
}
}
.scrollable-message-list {
- padding: 0 10px;
+ padding: 0 0.8em;
height: 100%;
overflow-y: scroll;
overflow-x: hidden;
@@ -45,7 +43,7 @@
.footer {
position: sticky;
- bottom: 0px;
+ bottom: 0;
}
.chat-view-heading {
@@ -54,15 +52,19 @@
top: 50px;
display: flex;
z-index: 2;
- border-radius: none;
position: sticky;
display: flex;
overflow: hidden;
}
.go-back-button {
- margin-right: 1.2em;
cursor: pointer;
+ margin-right: 1.4em;
+
+ i {
+ display: flex;
+ align-items: center;
+ }
}
.jump-to-bottom-button {
@@ -135,7 +137,7 @@
overflow: hidden;
height: 100%;
margin: 0;
- border-radius: 0 !important;
+ border-radius: 0;
}
.chat-view-heading {
diff --git a/src/components/chat/chat.vue b/src/components/chat/chat.vue
index d8c91dbe..62b72e14 100644
--- a/src/components/chat/chat.vue
+++ b/src/components/chat/chat.vue
@@ -75,7 +75,7 @@
:disable-polls="true"
:disable-sensitivity-checkbox="true"
:disable-submit="errorLoadingChat || !currentChat"
- :request="sendMessage"
+ :post-handler="sendMessage"
:submit-on-enter="!mobileLayout"
:preserve-focus="!mobileLayout"
:auto-focus="!mobileLayout"
diff --git a/src/components/chat/chat_layout.js b/src/components/chat/chat_layout.js
deleted file mode 100644
index 07ae3abf..00000000
--- a/src/components/chat/chat_layout.js
+++ /dev/null
@@ -1,100 +0,0 @@
-const ChatLayout = {
- methods: {
- setChatLayout () {
- if (this.mobileLayout) {
- this.setMobileChatLayout()
- }
- },
- unsetChatLayout () {
- this.unsetMobileChatLayout()
- },
- setMobileChatLayout () {
- // This is a hacky way to adjust the global layout to the mobile chat (without modifying the rest of the app).
- // This layout prevents empty spaces from being visible at the bottom
- // of the chat on iOS Safari (`safe-area-inset`) when
- // - the on-screen keyboard appears and the user starts typing
- // - the user selects the text inside the input area
- // - the user selects and deletes the text that is multiple lines long
- // TODO: unify the chat layout with the global layout.
-
- let html = document.querySelector('html')
- if (html) {
- html.style.overflow = 'hidden'
- html.style.height = '100%'
- }
-
- let body = document.querySelector('body')
- if (body) {
- body.style.height = '100%'
- }
-
- let app = document.getElementById('app')
- if (app) {
- app.style.height = '100%'
- app.style.overflow = 'hidden'
- app.style.minHeight = 'auto'
- }
-
- let appBgWrapper = window.document.getElementById('app_bg_wrapper')
- if (appBgWrapper) {
- appBgWrapper.style.overflow = 'hidden'
- }
-
- let main = document.getElementsByClassName('main')[0]
- if (main) {
- main.style.overflow = 'hidden'
- main.style.height = '100%'
- }
-
- let content = document.getElementById('content')
- if (content) {
- content.style.paddingTop = '0'
- content.style.height = '100%'
- content.style.overflow = 'visible'
- }
-
- this.$nextTick(() => {
- this.updateScrollableContainerHeight()
- })
- },
- unsetMobileChatLayout () {
- let html = document.querySelector('html')
- if (html) {
- html.style.overflow = 'visible'
- html.style.height = 'unset'
- }
-
- let body = document.querySelector('body')
- if (body) {
- body.style.height = 'unset'
- }
-
- let app = document.getElementById('app')
- if (app) {
- app.style.height = '100%'
- app.style.overflow = 'visible'
- app.style.minHeight = '100vh'
- }
-
- let appBgWrapper = document.getElementById('app_bg_wrapper')
- if (appBgWrapper) {
- appBgWrapper.style.overflow = 'visible'
- }
-
- let main = document.getElementsByClassName('main')[0]
- if (main) {
- main.style.overflow = 'visible'
- main.style.height = 'unset'
- }
-
- let content = document.getElementById('content')
- if (content) {
- content.style.paddingTop = '60px'
- content.style.height = 'unset'
- content.style.overflow = 'unset'
- }
- }
- }
-}
-
-export default ChatLayout
diff --git a/src/components/chat/chat_layout_utils.js b/src/components/chat/chat_layout_utils.js
index f07ba2a1..609dc0c9 100644
--- a/src/components/chat/chat_layout_utils.js
+++ b/src/components/chat/chat_layout_utils.js
@@ -22,6 +22,5 @@ export const isBottomedOut = (el, offset = 0) => {
// Height of the scrollable container. The dynamic height is needed to ensure the mobile browser panel doesn't overlap or hide the posting form.
export const scrollableContainerHeight = (inner, header, footer) => {
- const height = parseFloat(getComputedStyle(inner, null).height.replace('px', ''))
- return height - header.clientHeight - footer.clientHeight
+ return inner.offsetHeight - header.clientHeight - footer.clientHeight
}