2018-07-08 10:50:11 +00:00
|
|
|
<template>
|
2020-08-28 21:21:54 +00:00
|
|
|
<div id="chat-container" class="window" :data-current-channel="channel.name" lang="">
|
2018-07-08 13:42:54 +00:00
|
|
|
<div
|
|
|
|
id="chat"
|
2018-07-08 17:26:26 +00:00
|
|
|
:class="{
|
2023-04-24 22:49:57 +00:00
|
|
|
'hide-motd': !store.state.settings.motd,
|
2022-06-19 00:25:21 +00:00
|
|
|
'time-seconds': store.state.settings.showSeconds,
|
|
|
|
'time-12h': store.state.settings.use12hClock,
|
2023-04-16 23:11:35 +00:00
|
|
|
'colored-nicks': true, // TODO temporarily fixes themes, to be removed in next major version
|
2019-02-25 05:38:13 +00:00
|
|
|
}"
|
|
|
|
>
|
2018-07-08 12:18:17 +00:00
|
|
|
<div
|
|
|
|
:id="'chan-' + channel.id"
|
2019-12-04 06:58:23 +00:00
|
|
|
class="chat-view"
|
|
|
|
:data-type="channel.type"
|
2018-07-08 12:18:17 +00:00
|
|
|
:aria-label="channel.name"
|
2019-02-25 05:38:13 +00:00
|
|
|
role="tabpanel"
|
|
|
|
>
|
2018-07-08 12:18:17 +00:00
|
|
|
<div class="header">
|
2019-04-13 20:44:04 +00:00
|
|
|
<SidebarToggle />
|
2021-04-21 01:04:31 +00:00
|
|
|
<span class="title" :aria-label="'Currently open ' + channel.type">{{
|
|
|
|
channel.name
|
|
|
|
}}</span>
|
2019-08-11 13:59:06 +00:00
|
|
|
<div v-if="channel.editTopic === true" class="topic-container">
|
|
|
|
<input
|
2019-12-19 13:06:33 +00:00
|
|
|
ref="topicInput"
|
2019-08-11 13:59:06 +00:00
|
|
|
:value="channel.topic"
|
|
|
|
class="topic-input"
|
|
|
|
placeholder="Set channel topic"
|
2020-08-29 08:46:11 +00:00
|
|
|
enterkeyhint="done"
|
2019-08-11 13:59:06 +00:00
|
|
|
@keyup.enter="saveTopic"
|
|
|
|
@keyup.esc="channel.editTopic = false"
|
|
|
|
/>
|
|
|
|
<span aria-label="Save topic" class="save-topic" @click="saveTopic">
|
|
|
|
<span type="button" aria-label="Save topic"></span>
|
|
|
|
</span>
|
|
|
|
</div>
|
2021-10-22 20:52:51 +00:00
|
|
|
<span
|
|
|
|
v-else
|
|
|
|
:title="channel.topic"
|
|
|
|
:class="{topic: true, empty: !channel.topic}"
|
|
|
|
@dblclick="editTopic"
|
2019-07-17 09:33:59 +00:00
|
|
|
><ParsedMessage
|
|
|
|
v-if="channel.topic"
|
|
|
|
:network="network"
|
|
|
|
:text="channel.topic"
|
2019-02-25 05:38:13 +00:00
|
|
|
/></span>
|
2019-12-31 16:21:34 +00:00
|
|
|
<MessageSearchForm
|
2021-04-12 21:09:55 +00:00
|
|
|
v-if="
|
2022-06-19 00:25:21 +00:00
|
|
|
store.state.settings.searchEnabled &&
|
2021-04-12 21:09:55 +00:00
|
|
|
['channel', 'query'].includes(channel.type)
|
|
|
|
"
|
2019-12-31 16:21:34 +00:00
|
|
|
:network="network"
|
|
|
|
:channel="channel"
|
|
|
|
/>
|
2019-11-04 09:21:05 +00:00
|
|
|
<button
|
|
|
|
class="mentions"
|
|
|
|
aria-label="Open your mentions"
|
|
|
|
@click="openMentions"
|
|
|
|
/>
|
2019-11-09 22:21:34 +00:00
|
|
|
<button
|
|
|
|
class="menu"
|
|
|
|
aria-label="Open the context menu"
|
|
|
|
@click="openContextMenu"
|
|
|
|
/>
|
2018-07-08 12:18:17 +00:00
|
|
|
<span
|
|
|
|
v-if="channel.type === 'channel'"
|
|
|
|
class="rt-tooltip tooltipped tooltipped-w"
|
2019-02-25 05:38:13 +00:00
|
|
|
aria-label="Toggle user list"
|
|
|
|
>
|
2019-04-13 20:44:04 +00:00
|
|
|
<button
|
|
|
|
class="rt"
|
|
|
|
aria-label="Toggle user list"
|
2022-06-19 00:25:21 +00:00
|
|
|
@click="store.commit('toggleUserlist')"
|
2019-04-13 20:44:04 +00:00
|
|
|
/>
|
2018-07-08 12:18:17 +00:00
|
|
|
</span>
|
2018-07-08 10:50:11 +00:00
|
|
|
</div>
|
2019-07-17 09:33:59 +00:00
|
|
|
<div v-if="channel.type === 'special'" class="chat-content">
|
2018-07-19 10:01:52 +00:00
|
|
|
<div class="chat">
|
|
|
|
<div class="messages">
|
|
|
|
<div class="msg">
|
2020-04-28 14:17:55 +00:00
|
|
|
<component
|
2018-07-19 10:01:52 +00:00
|
|
|
:is="specialComponent"
|
2018-07-19 17:44:24 +00:00
|
|
|
:network="network"
|
2019-02-25 05:38:13 +00:00
|
|
|
:channel="channel"
|
|
|
|
/>
|
2018-07-19 10:01:52 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
2018-07-10 09:16:24 +00:00
|
|
|
</div>
|
2019-07-17 09:33:59 +00:00
|
|
|
<div v-else class="chat-content">
|
2018-09-24 12:47:39 +00:00
|
|
|
<div
|
2019-07-17 09:33:59 +00:00
|
|
|
:class="[
|
|
|
|
'scroll-down tooltipped tooltipped-w tooltipped-no-touch',
|
|
|
|
{'scroll-down-shown': !channel.scrolledToBottom},
|
|
|
|
]"
|
2019-02-18 06:27:35 +00:00
|
|
|
aria-label="Jump to recent messages"
|
2022-06-19 00:25:21 +00:00
|
|
|
@click="messageList?.jumpToBottom()"
|
2019-02-25 05:38:13 +00:00
|
|
|
>
|
2018-09-24 12:47:39 +00:00
|
|
|
<div class="scroll-down-arrow" />
|
|
|
|
</div>
|
2021-06-22 04:55:54 +00:00
|
|
|
<ChatUserList v-if="channel.type === 'channel'" :channel="channel" />
|
2021-01-26 22:51:22 +00:00
|
|
|
<MessageList
|
|
|
|
ref="messageList"
|
|
|
|
:network="network"
|
|
|
|
:channel="channel"
|
|
|
|
:focused="focused"
|
|
|
|
/>
|
2018-07-08 10:50:11 +00:00
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
</div>
|
2018-08-31 10:43:21 +00:00
|
|
|
<div
|
2022-06-19 00:25:21 +00:00
|
|
|
v-if="store.state.currentUserVisibleError"
|
2018-10-16 10:21:16 +00:00
|
|
|
id="user-visible-error"
|
2019-02-25 05:38:13 +00:00
|
|
|
@click="hideUserVisibleError"
|
2019-07-17 09:33:59 +00:00
|
|
|
>
|
2022-06-19 00:25:21 +00:00
|
|
|
{{ store.state.currentUserVisibleError }}
|
2019-07-17 09:33:59 +00:00
|
|
|
</div>
|
|
|
|
<ChatInput :network="network" :channel="channel" />
|
2018-07-08 10:50:11 +00:00
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
2022-06-19 00:25:21 +00:00
|
|
|
<script lang="ts">
|
2019-11-09 22:21:34 +00:00
|
|
|
import socket from "../js/socket";
|
2020-03-16 17:58:40 +00:00
|
|
|
import eventbus from "../js/eventbus";
|
2018-07-12 08:41:40 +00:00
|
|
|
import ParsedMessage from "./ParsedMessage.vue";
|
2018-07-08 17:22:01 +00:00
|
|
|
import MessageList from "./MessageList.vue";
|
2018-07-08 13:42:54 +00:00
|
|
|
import ChatInput from "./ChatInput.vue";
|
2018-07-08 17:22:01 +00:00
|
|
|
import ChatUserList from "./ChatUserList.vue";
|
2019-04-13 20:44:04 +00:00
|
|
|
import SidebarToggle from "./SidebarToggle.vue";
|
2019-12-31 16:21:34 +00:00
|
|
|
import MessageSearchForm from "./MessageSearchForm.vue";
|
2018-07-10 09:16:24 +00:00
|
|
|
import ListBans from "./Special/ListBans.vue";
|
2019-04-14 11:44:44 +00:00
|
|
|
import ListInvites from "./Special/ListInvites.vue";
|
2018-07-10 09:37:48 +00:00
|
|
|
import ListChannels from "./Special/ListChannels.vue";
|
2018-07-11 07:54:32 +00:00
|
|
|
import ListIgnored from "./Special/ListIgnored.vue";
|
2022-06-19 00:25:21 +00:00
|
|
|
import {defineComponent, PropType, ref, computed, watch, nextTick, onMounted, Component} from "vue";
|
|
|
|
import type {ClientNetwork, ClientChan} from "../js/types";
|
|
|
|
import {useStore} from "../js/store";
|
2024-05-02 06:21:51 +00:00
|
|
|
import {SpecialChanType, ChanType} from "../../shared/types/chan";
|
2018-07-08 10:50:11 +00:00
|
|
|
|
2022-06-19 00:25:21 +00:00
|
|
|
export default defineComponent({
|
2018-07-08 10:50:11 +00:00
|
|
|
name: "Chat",
|
|
|
|
components: {
|
2018-07-12 08:41:40 +00:00
|
|
|
ParsedMessage,
|
2018-07-08 17:22:01 +00:00
|
|
|
MessageList,
|
2018-07-08 13:42:54 +00:00
|
|
|
ChatInput,
|
2018-07-08 17:22:01 +00:00
|
|
|
ChatUserList,
|
2019-04-13 20:44:04 +00:00
|
|
|
SidebarToggle,
|
2019-12-31 16:21:34 +00:00
|
|
|
MessageSearchForm,
|
2018-07-08 10:50:11 +00:00
|
|
|
},
|
|
|
|
props: {
|
2022-06-19 00:25:21 +00:00
|
|
|
network: {type: Object as PropType<ClientNetwork>, required: true},
|
|
|
|
channel: {type: Object as PropType<ClientChan>, required: true},
|
|
|
|
focused: Number,
|
2018-07-08 10:50:11 +00:00
|
|
|
},
|
2022-06-19 00:25:21 +00:00
|
|
|
emits: ["channel-changed"],
|
|
|
|
setup(props, {emit}) {
|
|
|
|
const store = useStore();
|
|
|
|
|
|
|
|
const messageList = ref<typeof MessageList>();
|
|
|
|
const topicInput = ref<HTMLInputElement | null>(null);
|
|
|
|
|
|
|
|
const specialComponent = computed(() => {
|
|
|
|
switch (props.channel.special) {
|
2024-05-02 06:21:51 +00:00
|
|
|
case SpecialChanType.BANLIST:
|
2022-06-19 00:25:21 +00:00
|
|
|
return ListBans as Component;
|
2024-05-02 06:21:51 +00:00
|
|
|
case SpecialChanType.INVITELIST:
|
2022-06-19 00:25:21 +00:00
|
|
|
return ListInvites as Component;
|
2024-05-02 06:21:51 +00:00
|
|
|
case SpecialChanType.CHANNELLIST:
|
2022-06-19 00:25:21 +00:00
|
|
|
return ListChannels as Component;
|
2024-05-02 06:21:51 +00:00
|
|
|
case SpecialChanType.IGNORELIST:
|
2022-06-19 00:25:21 +00:00
|
|
|
return ListIgnored as Component;
|
2018-07-10 09:16:24 +00:00
|
|
|
}
|
2018-12-17 10:29:49 +00:00
|
|
|
|
|
|
|
return undefined;
|
2022-06-19 00:25:21 +00:00
|
|
|
});
|
2019-12-19 13:06:33 +00:00
|
|
|
|
2022-06-19 00:25:21 +00:00
|
|
|
const channelChanged = () => {
|
2019-10-17 16:56:44 +00:00
|
|
|
// Triggered when active channel is set or changed
|
2022-06-19 00:25:21 +00:00
|
|
|
emit("channel-changed", props.channel);
|
2019-10-17 16:56:44 +00:00
|
|
|
|
2022-06-19 00:25:21 +00:00
|
|
|
socket.emit("open", props.channel.id);
|
2019-10-17 16:56:44 +00:00
|
|
|
|
2022-06-19 00:25:21 +00:00
|
|
|
if (props.channel.usersOutdated) {
|
|
|
|
props.channel.usersOutdated = false;
|
2019-10-17 16:56:44 +00:00
|
|
|
|
|
|
|
socket.emit("names", {
|
2022-06-19 00:25:21 +00:00
|
|
|
target: props.channel.id,
|
2019-10-17 16:56:44 +00:00
|
|
|
});
|
|
|
|
}
|
2022-06-19 00:25:21 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
const hideUserVisibleError = () => {
|
|
|
|
store.commit("currentUserVisibleError", null);
|
|
|
|
};
|
|
|
|
|
|
|
|
const editTopic = () => {
|
2024-05-02 06:21:51 +00:00
|
|
|
if (props.channel.type === ChanType.CHANNEL) {
|
2022-06-19 00:25:21 +00:00
|
|
|
props.channel.editTopic = true;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const saveTopic = () => {
|
|
|
|
props.channel.editTopic = false;
|
|
|
|
|
|
|
|
if (!topicInput.value) {
|
|
|
|
return;
|
2019-08-03 10:09:55 +00:00
|
|
|
}
|
2022-06-19 00:25:21 +00:00
|
|
|
|
|
|
|
const newTopic = topicInput.value.value;
|
|
|
|
|
|
|
|
if (props.channel.topic !== newTopic) {
|
|
|
|
const target = props.channel.id;
|
|
|
|
const text = `/raw TOPIC ${props.channel.name} :${newTopic}`;
|
2019-08-03 10:09:55 +00:00
|
|
|
socket.emit("input", {target, text});
|
|
|
|
}
|
2022-06-19 00:25:21 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
const openContextMenu = (event: any) => {
|
2020-03-16 17:58:40 +00:00
|
|
|
eventbus.emit("contextmenu:channel", {
|
2019-11-23 14:26:20 +00:00
|
|
|
event: event,
|
2022-06-19 00:25:21 +00:00
|
|
|
channel: props.channel,
|
|
|
|
network: props.network,
|
2019-11-23 14:26:20 +00:00
|
|
|
});
|
2022-06-19 00:25:21 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
const openMentions = (event: any) => {
|
2020-03-16 17:58:40 +00:00
|
|
|
eventbus.emit("mentions:toggle", {
|
2019-11-04 09:21:05 +00:00
|
|
|
event: event,
|
|
|
|
});
|
2022-06-19 00:25:21 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
watch(
|
|
|
|
() => props.channel,
|
|
|
|
() => {
|
|
|
|
channelChanged();
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
watch(
|
|
|
|
() => props.channel.editTopic,
|
|
|
|
(newTopic) => {
|
|
|
|
if (newTopic) {
|
|
|
|
void nextTick(() => {
|
|
|
|
topicInput.value?.focus();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
);
|
|
|
|
|
|
|
|
onMounted(() => {
|
|
|
|
channelChanged();
|
|
|
|
|
|
|
|
if (props.channel.editTopic) {
|
|
|
|
void nextTick(() => {
|
|
|
|
topicInput.value?.focus();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return {
|
|
|
|
store,
|
|
|
|
messageList,
|
|
|
|
topicInput,
|
|
|
|
specialComponent,
|
|
|
|
hideUserVisibleError,
|
|
|
|
editTopic,
|
|
|
|
saveTopic,
|
|
|
|
openContextMenu,
|
|
|
|
openMentions,
|
|
|
|
};
|
2018-09-14 13:28:39 +00:00
|
|
|
},
|
2022-06-19 00:25:21 +00:00
|
|
|
});
|
2018-07-08 10:50:11 +00:00
|
|
|
</script>
|