thelounge/client/components/Chat.vue

178 lines
3.8 KiB
Vue
Raw Normal View History

<template>
2018-07-08 13:42:54 +00:00
<div
id="chat-container"
class="window">
<div
id="chat"
2018-07-09 10:44:12 +00:00
:data-id="channel.id"
:class="{
'hide-motd': !settings.motd,
'hide-status-messages': settings.statusMessages === 'hidden',
'condensed-status-messages': settings.statusMessages === 'condensed',
'colored-nicks': settings.coloredNicks,
2018-07-08 17:28:52 +00:00
'show-seconds': settings.showSeconds,
}"
>
<div
:id="'chan-' + channel.id"
:class="[channel.type, 'chan', 'active']"
:data-id="channel.id"
:data-type="channel.type"
:aria-label="channel.name"
role="tabpanel"
>
<div class="header">
<button
class="lt"
aria-label="Toggle channel list"/>
<span class="title">{{ channel.name }}</span>
<span
:title="channel.topic"
class="topic"
v-html="$options.filters.parse(channel.topic)"/>
<button
class="menu"
aria-label="Open the context menu"
/>
<span
v-if="channel.type === 'channel'"
class="rt-tooltip tooltipped tooltipped-w"
aria-label="Toggle user list">
<button
class="rt"
aria-label="Toggle user list"/>
</span>
</div>
2018-07-10 09:16:24 +00:00
<div
v-if="channel.type === 'special'"
class="chat-content">
<component
:is="specialComponent"
:channel="channel"/>
</div>
<div
v-else
class="chat-content">
2018-07-09 17:16:19 +00:00
<div
ref="chat"
class="chat"
>
2018-07-08 17:53:23 +00:00
<div class="show-more">
2018-07-08 13:42:54 +00:00
<button
2018-07-08 17:53:23 +00:00
ref="loadMoreButton"
:disabled="channel.historyLoading || !$root.connected"
class="btn"
@click="onShowMoreClick"
>
<span v-if="channel.historyLoading">Loading</span>
<span v-else>Show older messages</span>
</button>
</div>
<MessageList :channel="channel"/>
</div>
<ChatUserList
v-if="channel.type === 'channel'"
:channel="channel"/>
</div>
</div>
</div>
<div id="connection-error"/>
2018-07-08 13:42:54 +00:00
<ChatInput
:network="network"
:channel="channel"/>
</div>
</template>
<script>
2018-07-08 13:42:54 +00:00
require("intersection-observer");
const socket = require("../js/socket");
import MessageList from "./MessageList.vue";
2018-07-08 13:42:54 +00:00
import ChatInput from "./ChatInput.vue";
import ChatUserList from "./ChatUserList.vue";
2018-07-10 09:16:24 +00:00
import ListBans from "./Special/ListBans.vue";
2018-07-10 09:37:48 +00:00
import ListChannels from "./Special/ListChannels.vue";
export default {
name: "Chat",
components: {
MessageList,
2018-07-08 13:42:54 +00:00
ChatInput,
ChatUserList,
},
props: {
settings: Object,
network: Object,
channel: Object,
},
2018-07-10 09:16:24 +00:00
computed: {
specialComponent() {
2018-07-10 09:37:48 +00:00
switch (this.channel.special) {
case "list_bans": return ListBans;
case "list_channels": return ListChannels;
2018-07-10 09:16:24 +00:00
}
},
},
2018-07-10 07:45:54 +00:00
watch: {
"channel.messages"() {
const el = this.$refs.chat;
2018-07-10 09:20:52 +00:00
if (!el || el.scrollHeight - el.scrollTop - el.offsetHeight > 30) {
2018-07-10 07:45:54 +00:00
return;
}
this.$nextTick(() => {
el.scrollTop = el.scrollHeight;
});
},
},
2018-07-08 13:42:54 +00:00
created() {
2018-07-10 09:16:24 +00:00
if (!this.$refs.chat) {
return;
}
2018-07-08 13:42:54 +00:00
if (window.IntersectionObserver) {
this.historyObserver = new window.IntersectionObserver(loadMoreHistory, {
root: this.$refs.chat,
});
}
2018-07-09 17:16:19 +00:00
this.$nextTick(() => {
this.$refs.chat.scrollTop = this.$refs.chat.scrollHeight;
});
2018-07-08 13:42:54 +00:00
},
mounted() {
if (this.historyObserver) {
this.historyObserver.observe(this.$refs.loadMoreButton);
}
},
destroyed() {
if (this.historyObserver) {
2018-07-08 14:57:02 +00:00
this.historyObserver.disconnect();
2018-07-08 13:42:54 +00:00
}
},
methods: {
2018-07-08 13:42:54 +00:00
onShowMoreClick() {
let lastMessage = this.channel.messages[0];
lastMessage = lastMessage ? lastMessage.id : -1;
this.$set(this.channel, "historyLoading", true);
socket.emit("more", {
target: this.channel.id,
lastId: lastMessage,
});
},
},
};
2018-07-08 13:42:54 +00:00
function loadMoreHistory(entries) {
entries.forEach((entry) => {
if (!entry.isIntersecting) {
return;
}
entry.target.click();
});
}
</script>