162 lines
No EOL
5.7 KiB
Vue
162 lines
No EOL
5.7 KiB
Vue
<template>
|
|
<message-incoming v-bind="{ ...$props, ...$attrs }" v-on="$listeners" v-if="items.length > 1 || event.isRedacted() || forceMultiview">
|
|
<div class="bubble">
|
|
<div class="original-message" v-if="inReplyToText">
|
|
<div class="original-message-sender">{{ inReplyToSender }}</div>
|
|
<div
|
|
class="original-message-text"
|
|
v-html="linkify($sanitize(inReplyToText))"
|
|
/>
|
|
</div>
|
|
|
|
<div class="message">
|
|
<SwipeableThumbnailsView :items="items" v-if="!event.isRedacted() && room.displayType == ROOM_TYPE_CHANNEL" v-on="$listeners" />
|
|
<v-container v-else-if="!event.isRedacted()" fluid class="imageCollection">
|
|
<v-row wrap>
|
|
<v-col v-for="({ size, item }) in layoutedItems()" :key="item.event.getId()" :cols="size">
|
|
<ThumbnailView :item="item" :previewOnly="true" v-on:itemclick="onItemClick($event)" />
|
|
</v-col>
|
|
</v-row>
|
|
</v-container>
|
|
<i v-if="event.isRedacted()" class="deleted-text">
|
|
<v-icon :color="this.senderIsAdminOrModerator(this.event) ? 'white' : ''" size="small">block</v-icon>
|
|
{{ redactedBySomeoneElse(event) ? $t('message.incoming_message_deleted_text') : $t('message.outgoing_message_deleted_text')}}
|
|
</i>
|
|
<span v-html="linkify($sanitize(messageText))" v-else-if="messageText" />
|
|
<span class="edit-marker" v-if="event.replacingEventId() && !event.isRedacted()">
|
|
{{ $t('message.edited') }}
|
|
</span>
|
|
</div>
|
|
</div>
|
|
<GalleryItemsView :originalEvent="originalEvent" :items="items" :initialItem="showItem" v-if="!!showItem" v-on:close="showItem = null" />
|
|
</message-incoming>
|
|
<component v-else-if="items.length == 1" :is="componentFn(items[0].event)"
|
|
:originalEvent="items[0].event"
|
|
v-bind="{...$props, ...$attrs}" v-on="$listeners"
|
|
/>
|
|
</template>
|
|
|
|
<script>
|
|
import MessageIncoming from "./MessageIncoming.vue";
|
|
import messageMixin from "./messageMixin";
|
|
import util, { ROOM_TYPE_CHANNEL, ROOM_TYPE_FILE_MODE } from "../../plugins/utils";
|
|
import GalleryItemsView from '../file_mode/GalleryItemsView.vue';
|
|
import ThumbnailView from '../file_mode/ThumbnailView.vue';
|
|
import SwipeableThumbnailsView from "./channel/SwipeableThumbnailsView.vue";
|
|
|
|
export default {
|
|
extends: MessageIncoming,
|
|
components: { MessageIncoming, GalleryItemsView, ThumbnailView, SwipeableThumbnailsView },
|
|
mixins: [messageMixin],
|
|
data() {
|
|
return {
|
|
ROOM_TYPE_CHANNEL: ROOM_TYPE_CHANNEL,
|
|
items: [],
|
|
showItem: null,
|
|
}
|
|
},
|
|
mounted() {
|
|
this.thread = this.timelineSet.relations.getChildEventsForEvent(this.event.getId(), util.threadMessageType(), "m.room.message");
|
|
if (!this.thread) {
|
|
this.event.on("Event.relationsCreated", this.onRelationsCreated);
|
|
}
|
|
},
|
|
beforeDestroy() {
|
|
this.event.off("Event.relationsCreated", this.onRelationsCreated);
|
|
},
|
|
computed: {
|
|
forceMultiview() {
|
|
return this.room.displayType == ROOM_TYPE_FILE_MODE || (this.room.displayType == ROOM_TYPE_CHANNEL && this.items.length == 1 && util.isFileTypePDF(this.items[0].event));
|
|
}
|
|
},
|
|
methods: {
|
|
onRelationsCreated() {
|
|
this.thread = this.timelineSet.relations.getChildEventsForEvent(this.event.getId(), util.threadMessageType(), "m.room.message");
|
|
this.event.off("Event.relationsCreated", this.onRelationsCreated);
|
|
},
|
|
onItemClick(event) {
|
|
this.showItem = event.item;
|
|
},
|
|
processThread() {
|
|
this.$emit('layout-change', () => {
|
|
this.items = this.timelineSet.relations.getAllChildEventsForEvent(this.event.getId())
|
|
.filter(e => !e.isRedacted() && util.downloadableTypes().includes(e.getContent().msgtype))
|
|
.map(e => {
|
|
let ret = {
|
|
event: e,
|
|
src: null,
|
|
};
|
|
ret.promise =
|
|
util
|
|
.getThumbnail(this.$matrix.matrixClient, e, this.$config, 100, 100)
|
|
.then((url) => {
|
|
ret.src = url;
|
|
})
|
|
.catch((err) => {
|
|
console.log("Failed to fetch thumbnail: ", err);
|
|
});
|
|
return ret;
|
|
});
|
|
}, this.$el);
|
|
},
|
|
layoutedItems() {
|
|
if (!this.items || this.items.length == 0) { return [] }
|
|
let array = this.items.slice(0);
|
|
let rows = []
|
|
while (array.length > 0) {
|
|
if (array.length >= 7) {
|
|
rows.push({ size: 6, item: array[0] });
|
|
rows.push({ size: 6, item: array[1] });
|
|
rows.push({ size: 12, item: array[2] });
|
|
rows.push({ size: 3, item: array[3] });
|
|
rows.push({ size: 3, item: array[4] });
|
|
rows.push({ size: 3, item: array[5] });
|
|
rows.push({ size: 3, item: array[6] });
|
|
array = array.slice(7);
|
|
} else if (array.length >= 3) {
|
|
rows.push({ size: 6, item: array[0] });
|
|
rows.push({ size: 6, item: array[1] });
|
|
rows.push({ size: 12, item: array[2] });
|
|
array = array.slice(3);
|
|
} else if (array.length >= 2) {
|
|
rows.push({ size: 6, item: array[0] });
|
|
rows.push({ size: 6, item: array[1] });
|
|
array = array.slice(2);
|
|
} else {
|
|
rows.push({ size: 12, item: array[0] });
|
|
array = array.slice(1);
|
|
}
|
|
}
|
|
return rows
|
|
},
|
|
downloadAll() {
|
|
this.items.forEach(item => util.download(this.$matrix.matrixClient, item.event));
|
|
}
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<style lang="scss">
|
|
@import "@/assets/css/chat.scss";
|
|
</style>
|
|
|
|
<style lang="scss" scoped>
|
|
.bubble {
|
|
width: 100%;
|
|
}
|
|
|
|
.imageCollection {
|
|
border-radius: 15px;
|
|
padding: 0;
|
|
overflow: hidden;
|
|
|
|
.row {
|
|
margin: -4px; // Compensate for column padding, so the border-radius above looks round!
|
|
padding: 0;
|
|
}
|
|
|
|
.col {
|
|
padding: 2px;
|
|
}
|
|
}
|
|
</style> |