mirror of
https://github.com/danbulant/Nertivia-Client
synced 2026-06-15 12:31:15 +00:00
358 lines
11 KiB
Vue
358 lines
11 KiB
Vue
<template>
|
|
|
|
<div ref="msg-logs" class="message-logs" @scroll.passive="scrollEvent" @resize="onResize">
|
|
<div class="load-more-button" v-if="loadMoreTop.show && selectedChannelMessages.length >= 50">
|
|
<spinner :size="30" v-if="loadMoreTop.loading" />
|
|
<div class="text" v-if="!loadMoreTop.loading" @click="loadMoreMessages">Load more</div>
|
|
</div>
|
|
<message
|
|
class="message-container"
|
|
v-for="(msg, index) in selectedChannelMessages"
|
|
:class="{'show-message-animation': index === selectedChannelMessages.length - 1}"
|
|
:key="msg.tempID || msg.messageID"
|
|
:date="msg.created"
|
|
:admin="msg.creator.admin"
|
|
:username="msg.creator.username"
|
|
:uniqueID="msg.creator.uniqueID"
|
|
:avatar="msg.creator.avatar"
|
|
:message="msg.message"
|
|
:embed="msg.embed"
|
|
:files="msg.files"
|
|
:status="msg.status"
|
|
:messageID="msg.messageID"
|
|
:channelID="msg.channelID"
|
|
:type="msg.type"
|
|
:timeEdited="msg.timeEdited"
|
|
/>
|
|
<uploadsQueue v-if="uploadQueue !== undefined" :queue="uploadQueue"/>
|
|
<div class="load-more-button" v-if="loadMoreBottom.show && selectedChannelMessages.length >= 50">
|
|
<spinner :size="30" v-if="loadMoreBottom.loading" />
|
|
<div class="text" v-if="!loadMoreBottom.loading" @click="loadBottomMessages">Load more</div>
|
|
</div>
|
|
</div>
|
|
|
|
</template>
|
|
|
|
<script>
|
|
import messagesService from "@/services/messagesService";
|
|
import { bus } from "../../main";
|
|
import Message from "../../components/app/MessageTemplate.vue";
|
|
import Spinner from "@/components/Spinner.vue";
|
|
import uploadsQueue from "@/components/app/uploadsQueue.vue";
|
|
import debounce from "lodash/debounce";
|
|
|
|
import windowProperties from '@/utils/windowProperties';
|
|
|
|
|
|
export default {
|
|
components: {
|
|
Message,
|
|
Spinner,
|
|
uploadsQueue,
|
|
},
|
|
data() {
|
|
return {
|
|
scrolledDown: true,
|
|
scrolledTop: false,
|
|
|
|
loadMoreTop: {
|
|
show: true,
|
|
loading: false
|
|
},
|
|
loadMoreBottom: {
|
|
show: false,
|
|
loading: false,
|
|
},
|
|
selectedChannelID: null,
|
|
currentScrollTopPos: null,
|
|
backToBottomLoading: false,
|
|
};
|
|
},
|
|
methods: {
|
|
scrollEvent: debounce(function(event) {
|
|
const { target: { scrollTop, clientHeight, scrollHeight} } = event;
|
|
this.scrolledDown = Math.abs(scrollHeight - scrollTop - clientHeight) <= 3.0;
|
|
this.scrolledTop = scrollTop === 0;
|
|
this.currentScrollTopPos = scrollTop;
|
|
}, 20),
|
|
scrollDown(data) {
|
|
const element = this.$refs['msg-logs']
|
|
const force = data && data.force ? data.force : false;
|
|
const pos = data && data.pos ? data.pos : undefined;
|
|
if (!force && !this.scrolledDown) return;
|
|
if (!element) return;
|
|
element.scrollTop = pos || element.scrollHeight;
|
|
},
|
|
unloadTopMessages(){
|
|
if (this.selectedChannelMessages && this.selectedChannelMessages.length >= 100)
|
|
this.$store.dispatch('unloadTopMessages', {channelID: this.selectedChannelID});
|
|
},
|
|
unloadBottomMessages(){
|
|
if (this.selectedChannelMessages && this.selectedChannelMessages.length >= 100){
|
|
this.$store.dispatch('setBottomUnloadStatus', {channelID: this.selectedChannelID, status: true})
|
|
this.$store.dispatch('unloadBottomMessages', {channelID: this.selectedChannelID});
|
|
}
|
|
},
|
|
onResize(dimentions) {
|
|
this.scrollDown();
|
|
},
|
|
async loadMoreMessages() {
|
|
if (this.loadMoreTop.loading) return;
|
|
const msgLogs = this.$refs['msg-logs'];
|
|
const scrollTop = msgLogs.scrollTop;
|
|
const scrollHeight = msgLogs.scrollHeight;
|
|
|
|
const continueMessageID = this.selectedChannelMessages[0].messageID;
|
|
this.$set(this.loadMoreTop, 'loading', true);
|
|
const {ok, result, error} = await messagesService.get(this.selectedChannelID, continueMessageID)
|
|
if (ok) {
|
|
if (!result.data.messages.length) {
|
|
this.$set(this.loadMoreTop, 'loading', false);
|
|
this.$set(this.loadMoreTop, 'show', false);
|
|
return;
|
|
}
|
|
this.$store.dispatch('addMessages', result.data.messages)
|
|
this.$nextTick(_ => {
|
|
this.$set(this.loadMoreTop, 'loading', false);
|
|
msgLogs.scrollTop = msgLogs.scrollHeight - scrollHeight;
|
|
})
|
|
}
|
|
},
|
|
async loadBottomMessages() {
|
|
if (this.loadMoreBottom.loading) return;
|
|
const msgLogs = this.$refs['msg-logs'];
|
|
const scrollTop = msgLogs.scrollTop;
|
|
const scrollHeight = msgLogs.scrollHeight;
|
|
const channelID = this.selectedChannelID;
|
|
|
|
|
|
const beforeMessageID = this.selectedChannelMessages[this.selectedChannelMessages.length - 1].messageID;
|
|
this.$set(this.loadMoreBottom, 'loading', true);
|
|
const {ok, result, error} = await messagesService.get(channelID, null, beforeMessageID)
|
|
if (ok) {
|
|
if (!result.data.messages.length) {
|
|
this.$store.dispatch('setBottomUnloadStatus', {channelID, status: false})
|
|
this.$set(this.loadMoreBottom, 'loading', false);
|
|
this.$set(this.loadMoreBottom, 'show', false);
|
|
return;
|
|
}
|
|
this.$store.dispatch('addMessagesBefore', result.data.messages)
|
|
|
|
this.$nextTick(_ => {
|
|
|
|
this.$set(this.loadMoreBottom, 'loading', false);
|
|
this.scrolledDown = false;
|
|
msgLogs.scrollTop = scrollTop
|
|
this.$set(this.loadMoreBottom, 'show', true);
|
|
})
|
|
}
|
|
},
|
|
scrolledUpEvent() {
|
|
this.unloadBottomMessages();
|
|
const msgLogs = this.$refs['msg-logs'];
|
|
const scrollTop = msgLogs.scrollTop;
|
|
const scrollHeight = msgLogs.scrollHeight;
|
|
|
|
this.$set(this.loadMoreBottom, 'show', true);
|
|
|
|
this.$nextTick(_ => {
|
|
msgLogs.scrollTop = 0;
|
|
if (this.loadMoreTop.show)
|
|
this.loadMoreMessages();
|
|
})
|
|
},
|
|
scrolledDownEvent(){
|
|
this.unloadTopMessages()
|
|
this.$set(this.loadMoreTop, 'show', true);
|
|
this.$nextTick(_ => {
|
|
if (this.loadMoreBottom.show)
|
|
this.loadBottomMessages();
|
|
})
|
|
},
|
|
async backToBottomEvent() {
|
|
if (this.backToBottomLoading) return;
|
|
const channelID = this.selectedChannelID;
|
|
const bottomUnloaded = this.bottomUnloaded;
|
|
if (!bottomUnloaded) {
|
|
this.scrollDown({force: true});
|
|
this.unloadTopMessages();
|
|
return;
|
|
}
|
|
this.backToBottomLoading = true;
|
|
const {ok, result, error} = await messagesService.get(this.selectedChannelID)
|
|
if (ok) {
|
|
this.$store.dispatch('messages', {messages: result.data.messages.reverse(), channelID});
|
|
this.$set(this.loadMoreBottom, 'show', false);
|
|
this.$store.dispatch('setBottomUnloadStatus', {channelID, status: false})
|
|
this.$nextTick(_ => {this.scrollDown({force: true});})
|
|
|
|
}
|
|
this.backToBottomLoading = false;
|
|
},
|
|
|
|
},
|
|
|
|
mounted() {
|
|
|
|
this.selectedChannelID = this.$store.getters.selectedChannelID;
|
|
const pos = this.$store.getters.scrollPosition[this.selectedChannelID];
|
|
bus.$on('backToBottom', this.backToBottomEvent)
|
|
bus.$on('scrollDown', this.scrollDown)
|
|
bus.$emit('scrolledDown',this.scrolledDown);
|
|
|
|
if (this.bottomUnloaded) {
|
|
this.$set(this.loadMoreBottom, 'show', true);
|
|
}
|
|
this.$nextTick( _ => {
|
|
this.scrollDown({force: pos, pos: pos});
|
|
})
|
|
|
|
|
|
},
|
|
|
|
beforeDestroy() {
|
|
this.$store.dispatch("setEditMessage", null);
|
|
this.$store.dispatch('changeScrollPosition',{
|
|
channelID: this.selectedChannelID,
|
|
pos: !this.scrolledDown ? this.currentScrollTopPos : null
|
|
});
|
|
bus.$off('backToBottom', this.backToBottomEvent);
|
|
bus.$off('scrollDown', this.scrollDown)
|
|
},
|
|
|
|
watch: {
|
|
selectedChannelMessages(newMessages, oldMessages){
|
|
this.$set(this.loadMoreTop, 'show', true);
|
|
const msgLogs = this.$refs['msg-logs'];
|
|
this.$nextTick(function () {
|
|
this.scrollDown();
|
|
})
|
|
},
|
|
uploadQueue() {
|
|
this.$nextTick(function () {
|
|
this.scrollDown({force: true});
|
|
})
|
|
},
|
|
getWindowWidth(dimentions) {
|
|
this.onResize();
|
|
},
|
|
scrolledTop(scrolledTop) {
|
|
if (scrolledTop)
|
|
this.scrolledUpEvent();
|
|
},
|
|
scrolledDown(scrolledDown) {
|
|
bus.$emit('scrolledDown',scrolledDown);
|
|
if (scrolledDown)
|
|
this.scrolledDownEvent();
|
|
}
|
|
},
|
|
computed: {
|
|
uploadQueue() {
|
|
const allUploads = this.$store.getters.getAllUploads;
|
|
const selectedChannelID = this.$store.getters.selectedChannelID;
|
|
|
|
const filteredArray = [];
|
|
|
|
for (let upload in allUploads) {
|
|
if (allUploads[upload].channelID === selectedChannelID) {
|
|
filteredArray.push(allUploads[upload]);
|
|
}
|
|
}
|
|
if (!filteredArray.length) return undefined;
|
|
return filteredArray;
|
|
},
|
|
user() {
|
|
return this.$store.getters.user;
|
|
},
|
|
channel() {
|
|
return this.$store.getters.channels[this.selectedChannelID];
|
|
},
|
|
selectedChannelMessages() {
|
|
const selectedChannel = this.$store.getters.selectedChannelID;
|
|
return this.$store.getters.messages[selectedChannel];
|
|
},
|
|
editMessage() {
|
|
let editMessage = this.$store.getters.popouts.editMessage;
|
|
if (!editMessage) return null;
|
|
return editMessage;
|
|
},
|
|
getWindowWidth() {
|
|
return {width: windowProperties.resizeWidth, height: windowProperties.resizeHeight};
|
|
},
|
|
scrollPosition() {
|
|
return this.$store.getters.scrollPosition;
|
|
},
|
|
bottomUnloaded() {
|
|
return this.$store.getters.bottomUnloaded[this.selectedChannelID] || false;
|
|
}
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
.message-logs {
|
|
overflow: auto;
|
|
flex: 1;
|
|
margin-right: 2px;
|
|
position: relative;
|
|
}
|
|
|
|
.load-more-button {
|
|
background: rgba(0, 0, 0, 0.46);
|
|
padding: 5px;
|
|
user-select: none;
|
|
border-radius: 5px;
|
|
margin: 5px;
|
|
height: 30px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
justify-content: center;
|
|
.text {
|
|
text-align: center;
|
|
color: white;
|
|
cursor: pointer;
|
|
align-self: center;
|
|
}
|
|
}
|
|
.back-to-bottom-button {
|
|
&:hover {
|
|
background: rgb(23, 124, 255);
|
|
box-shadow: 0px 0px 15px 0px #0000008a;
|
|
}
|
|
transition: 0.2s;
|
|
background: rgba(23, 124, 255, 0.818);
|
|
color: white;
|
|
position: absolute;
|
|
bottom: 15px;
|
|
right: 25px;
|
|
border-radius: 10px;
|
|
height: 50px;
|
|
z-index: 2;
|
|
display: flex;
|
|
justify-content: center;
|
|
flex-shrink: 0;
|
|
box-shadow: 0px 0px 7px 0px #0000008a;
|
|
align-content: center;
|
|
align-items: center;
|
|
padding-left: 10px;
|
|
user-select: none;
|
|
cursor: pointer;
|
|
.material-icons {
|
|
align-self: center;
|
|
flex-shrink: 0;
|
|
font-size: 35px;
|
|
}
|
|
}
|
|
|
|
|
|
.show-message-animation {
|
|
animation: showMessage 0.3s ease-in-out;
|
|
}
|
|
@keyframes showMessage {
|
|
from {
|
|
transform: translate(-50px, 0);
|
|
opacity: 0;
|
|
}
|
|
}
|
|
</style>
|