Work on export and moving to Vue composition API
This commit is contained in:
parent
b0fae3396d
commit
9a124c5ab9
22 changed files with 660 additions and 906 deletions
|
|
@ -26,9 +26,16 @@
|
|||
|
||||
<div v-if="!event.isRelation() && !event.isRedacted() && !event.isRedaction()" :ref="event.getId()">
|
||||
<div class="message-wrapper">
|
||||
<component :is="componentForEvent(event, true)" :room="room" :originalEvent="event"
|
||||
:nextEvent="events[index + 1]" :timelineSet="timelineSet" :componentFn="componentForEventForExport"
|
||||
ref="exportedEvent" v-on:layout-change="onLayoutChange" />
|
||||
<component
|
||||
:is="componentForEvent(event, true)"
|
||||
:room="room"
|
||||
:originalEvent="event"
|
||||
:nextEvent="events[index + 1]"
|
||||
:timelineSet="timelineSet"
|
||||
:componentFn="componentForEvent"
|
||||
ref="exportedEvent"
|
||||
v-on:layout-change="onLayoutChange"
|
||||
/>
|
||||
<!-- <div v-if="debugging" style="user-select:text">EventID: {{ event.getId() }}</div> -->
|
||||
<!-- <div v-if="debugging" style="user-select:text">Event: {{ JSON.stringify(event) }}</div> -->
|
||||
</div>
|
||||
|
|
@ -54,16 +61,12 @@
|
|||
|
||||
<script>
|
||||
import MessageIncomingText from "./messages/MessageIncomingText.vue";
|
||||
import MessageIncomingFile from "./messages/MessageIncomingFile.vue";
|
||||
import MessageIncomingImage from "./messages/MessageIncomingImage.vue";
|
||||
import MessageFile from "./messages/composition/MessageFile.vue";
|
||||
import MessageImage from "./messages/composition/MessageImage.vue";
|
||||
import MessageIncomingAudio from "./messages/MessageIncomingAudio.vue";
|
||||
import MessageIncomingVideo from "./messages/MessageIncomingVideo.vue";
|
||||
import MessageIncomingSticker from "./messages/MessageIncomingSticker.vue";
|
||||
import MessageOutgoingText from "./messages/MessageOutgoingText.vue";
|
||||
import MessageOutgoingFile from "./messages/MessageOutgoingFile.vue";
|
||||
import MessageOutgoingImage from "./messages/MessageOutgoingImage.vue";
|
||||
import MessageOutgoingAudio from "./messages/MessageOutgoingAudio.vue";
|
||||
import MessageOutgoingVideo from "./messages/MessageOutgoingVideo.vue";
|
||||
import MessageOutgoingSticker from "./messages/MessageOutgoingSticker.vue";
|
||||
import MessageOutgoingPoll from "./messages/MessageOutgoingPoll.vue";
|
||||
import ContactJoin from "./messages/ContactJoin.vue";
|
||||
|
|
@ -94,7 +97,7 @@ import CreatePollDialog from "./CreatePollDialog.vue";
|
|||
import chatMixin from "./chatMixin";
|
||||
import util from "../plugins/utils";
|
||||
import { EventTimelineSet } from "matrix-js-sdk";
|
||||
import axios from 'axios';
|
||||
import axios from "axios";
|
||||
import "../services/jszip.min";
|
||||
import "../services/filesaver.cjs";
|
||||
|
||||
|
|
@ -105,16 +108,12 @@ export default {
|
|||
components: {
|
||||
ChatHeader,
|
||||
MessageIncomingText,
|
||||
MessageIncomingFile,
|
||||
MessageIncomingImage,
|
||||
MessageFile,
|
||||
MessageImage,
|
||||
MessageIncomingAudio,
|
||||
MessageIncomingVideo,
|
||||
MessageIncomingSticker,
|
||||
MessageOutgoingText,
|
||||
MessageOutgoingFile,
|
||||
MessageOutgoingImage,
|
||||
MessageOutgoingAudio,
|
||||
MessageOutgoingVideo,
|
||||
MessageOutgoingSticker,
|
||||
MessageOutgoingPoll,
|
||||
ContactJoin,
|
||||
|
|
@ -180,9 +179,6 @@ export default {
|
|||
},
|
||||
},
|
||||
methods: {
|
||||
componentForEventForExport(event) {
|
||||
return this.componentForEvent(event, true);
|
||||
},
|
||||
cancelExport() {
|
||||
this.cancelled = true;
|
||||
},
|
||||
|
|
@ -258,19 +254,25 @@ export default {
|
|||
this.events = events;
|
||||
|
||||
// Need to set thread root events and replyEvents so stuff is rendered correctly.
|
||||
this.events.filter(event => (event.threadRootId && !event.parentThread)).forEach(event => {
|
||||
const parentEvent = this.timelineSet.findEventById(event.threadRootId) || this.room.findEventById(event.threadRootId);
|
||||
if (parentEvent) {
|
||||
parentEvent["isMxThread"] = true;
|
||||
event["parentThread"] = parentEvent;
|
||||
}
|
||||
});
|
||||
this.events.filter(event => (event.replyEventId && !event.replyEvent)).forEach(event => {
|
||||
const parentEvent = this.timelineSet.findEventById(event.replyEventId) || this.room.findEventById(event.replyEventId);
|
||||
if (parentEvent) {
|
||||
event["replyEvent"] = parentEvent;
|
||||
}
|
||||
});
|
||||
this.events
|
||||
.filter((event) => event.threadRootId && !event.parentThread)
|
||||
.forEach((event) => {
|
||||
const parentEvent =
|
||||
this.timelineSet.findEventById(event.threadRootId) || this.room.findEventById(event.threadRootId);
|
||||
if (parentEvent) {
|
||||
parentEvent["isMxThread"] = true;
|
||||
event["parentThread"] = parentEvent;
|
||||
}
|
||||
});
|
||||
this.events
|
||||
.filter((event) => event.replyEventId && !event.replyEvent)
|
||||
.forEach((event) => {
|
||||
const parentEvent =
|
||||
this.timelineSet.findEventById(event.replyEventId) || this.room.findEventById(event.replyEventId);
|
||||
if (parentEvent) {
|
||||
event["replyEvent"] = parentEvent;
|
||||
}
|
||||
});
|
||||
|
||||
// Wait a tick so UI is updated.
|
||||
return new Promise((resolve, ignoredReject) => {
|
||||
|
|
@ -304,8 +306,7 @@ export default {
|
|||
childComponents.push(parentComp.$refs.exportedEvent);
|
||||
}
|
||||
}
|
||||
for (const comp of childComponents) {
|
||||
|
||||
for (const comp of childComponents.filter((c) => c.event != undefined)) {
|
||||
// Avatars need downloading?
|
||||
if (comp.$el && comp.$el.nodeType == 1) {
|
||||
const avatars = comp.$el.getElementsByClassName("v-avatar");
|
||||
|
|
@ -322,29 +323,44 @@ export default {
|
|||
const img = images[imageIndex];
|
||||
img.onerror = undefined;
|
||||
img.removeAttribute("src");
|
||||
img.setAttribute("data-exported-src", './avatars/' + fileName);
|
||||
img.setAttribute("data-exported-src", "./avatars/" + fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (!avatarFolder.file(fileName)) {
|
||||
const url = member.getAvatarUrl(this.$matrix.matrixClient.getHomeserverUrl(), 40, 40, "scale", true, false, this.$matrix.useAuthedMedia);
|
||||
const url = member.getAvatarUrl(
|
||||
this.$matrix.matrixClient.getHomeserverUrl(),
|
||||
40,
|
||||
40,
|
||||
"scale",
|
||||
true,
|
||||
false,
|
||||
this.$matrix.useAuthedMedia
|
||||
);
|
||||
if (url) {
|
||||
avatarFolder.file(fileName, "empty");
|
||||
downloadPromises.push(
|
||||
axios.get(url, {
|
||||
responseType: 'blob'
|
||||
})
|
||||
.then(result => {
|
||||
axios
|
||||
.get(url, {
|
||||
responseType: "blob",
|
||||
headers: this.$matrix.useAuthedMedia
|
||||
? {
|
||||
Authorization: `Bearer ${this.$matrix.matrixClient.getAccessToken()}`,
|
||||
}
|
||||
: undefined,
|
||||
})
|
||||
.then((result) => {
|
||||
if (result.data) {
|
||||
avatarFolder.file(fileName, result.data);
|
||||
setSource(fileName);
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
.catch((err) => {
|
||||
console.error("Download error: ", err);
|
||||
avatarFolder.remove(fileName);
|
||||
}));
|
||||
})
|
||||
);
|
||||
}
|
||||
} else {
|
||||
setSource(fileName);
|
||||
|
|
@ -353,139 +369,107 @@ export default {
|
|||
}
|
||||
}
|
||||
|
||||
let componentClass = comp.$options ? comp.$options.__file.split("/").reverse()[0].split(".")[0] : "invalid_component";
|
||||
switch (componentClass) {
|
||||
case "MessageIncomingImageExport":
|
||||
case "MessageOutgoingImageExport":
|
||||
// TODO - maybe consider what media to download based on the file size we already have?
|
||||
// info = comp.event.getContent().info;
|
||||
// if (info && info.size && currentMediaSize + info.size > maxMediaSize) {
|
||||
// // No need to even download.
|
||||
// console.log("Dont download!");
|
||||
// continue;
|
||||
// }
|
||||
let componentClass = comp.$options
|
||||
? comp.$options.__file.split("/").reverse()[0].split(".")[0]
|
||||
: "invalid_component";
|
||||
let attachment =
|
||||
comp.event && comp.event.getId
|
||||
? this.$matrix.attachmentManager.getEventAttachment(comp.event)
|
||||
: undefined;
|
||||
|
||||
downloadPromises.push(
|
||||
util
|
||||
.getAttachment(this.$matrix.matrixClient, this.$matrix.useAuthedMedia, comp.event, null, true)
|
||||
.then((blob) => {
|
||||
return new Promise((resolve, ignoredReject) => {
|
||||
let mime = blob.type;
|
||||
var extension = ".png";
|
||||
switch (mime) {
|
||||
case "image/jpeg":
|
||||
case "image/jpg":
|
||||
extension = ".jpg";
|
||||
break;
|
||||
case "image/gif":
|
||||
extension = ".gif";
|
||||
}
|
||||
if (currentMediaSize + blob.size <= maxMediaSize) {
|
||||
currentMediaSize += blob.size;
|
||||
if (attachment && (attachment.srcSize = 0 || currentMediaSize + attachment.srcSize <= maxMediaSize)) {
|
||||
downloadPromises.push(
|
||||
attachment
|
||||
.loadSrc({ asBlob: true })
|
||||
.then((res) => {
|
||||
const blob = res.data;
|
||||
if (currentMediaSize + blob.size <= maxMediaSize) {
|
||||
currentMediaSize += blob.size;
|
||||
|
||||
let fileName = comp.event.getId() + extension;
|
||||
imageFolder.file(fileName, blob); // TODO calc bytes
|
||||
switch (componentClass) {
|
||||
case "MessageIncomingImageExport":
|
||||
case "MessageOutgoingImageExport":
|
||||
{
|
||||
let mime = blob.type;
|
||||
var extension = ".png";
|
||||
switch (mime) {
|
||||
case "image/jpeg":
|
||||
case "image/jpg":
|
||||
extension = ".jpg";
|
||||
break;
|
||||
case "image/gif":
|
||||
extension = ".gif";
|
||||
}
|
||||
|
||||
// Update source
|
||||
const images = comp.$el.getElementsByTagName("img");
|
||||
for (let imageIndex = 0; imageIndex < images.length; imageIndex++) {
|
||||
const img = images[imageIndex];
|
||||
img.removeAttribute("src");
|
||||
img.setAttribute("data-exported-src", './images/' + fileName);
|
||||
let fileName = comp.event.getId() + extension;
|
||||
imageFolder.file(fileName, blob); // TODO calc bytes
|
||||
|
||||
// Update source
|
||||
const images = comp.$el.getElementsByTagName("img");
|
||||
for (let imageIndex = 0; imageIndex < images.length; imageIndex++) {
|
||||
const img = images[imageIndex];
|
||||
img.removeAttribute("src");
|
||||
img.setAttribute("data-exported-src", "./images/" + fileName);
|
||||
}
|
||||
this.processedEvents += 1;
|
||||
}
|
||||
this.processedEvents += 1;
|
||||
resolve(true);
|
||||
}
|
||||
});
|
||||
})
|
||||
.catch((ignoredErr) => {
|
||||
this.processedEvents += 1;
|
||||
})
|
||||
);
|
||||
break;
|
||||
case "MessageIncomingAudioExport":
|
||||
case "MessageOutgoingAudioExport":
|
||||
downloadPromises.push(
|
||||
util
|
||||
.getAttachment(this.$matrix.matrixClient, this.$matrix.useAuthedMedia, comp.event, null, true)
|
||||
.then((blob) => {
|
||||
if (currentMediaSize + blob.size <= maxMediaSize) {
|
||||
currentMediaSize += blob.size;
|
||||
return new Promise((resolve, ignoredReject) => {
|
||||
//let mime = blob.type;
|
||||
var extension = ".webm";
|
||||
let fileName = comp.event.getId() + extension;
|
||||
audioFolder.file(fileName, blob); // TODO calc bytes
|
||||
let elements = comp.$el.getElementsByTagName("audio");
|
||||
let element = elements && elements[0];
|
||||
if (element) {
|
||||
element.setAttribute("data-exported-src", "./audio/" + fileName);
|
||||
break;
|
||||
|
||||
case "MessageIncomingAudioExport":
|
||||
case "MessageOutgoingAudioExport":
|
||||
{
|
||||
var extension = ".webm";
|
||||
let fileName = comp.event.getId() + extension;
|
||||
audioFolder.file(fileName, blob); // TODO calc bytes
|
||||
let elements = comp.$el.getElementsByTagName("audio");
|
||||
let element = elements && elements[0];
|
||||
if (element) {
|
||||
element.setAttribute("data-exported-src", "./audio/" + fileName);
|
||||
}
|
||||
this.processedEvents += 1;
|
||||
}
|
||||
this.processedEvents += 1;
|
||||
resolve(true);
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((ignoredErr) => {
|
||||
this.processedEvents += 1;
|
||||
})
|
||||
);
|
||||
break;
|
||||
case "MessageIncomingVideoExport":
|
||||
case "MessageOutgoingVideoExport":
|
||||
downloadPromises.push(
|
||||
util
|
||||
.getAttachment(this.$matrix.matrixClient, this.$matrix.useAuthedMedia, comp.event, null, true)
|
||||
.then((blob) => {
|
||||
if (currentMediaSize + blob.size <= maxMediaSize) {
|
||||
currentMediaSize += blob.size;
|
||||
return new Promise((resolve, ignoredReject) => {
|
||||
//let mime = blob.type;
|
||||
var extension = ".mp4";
|
||||
let fileName = comp.event.getId() + extension;
|
||||
videoFolder.file(fileName, blob); // TODO calc bytes
|
||||
// comp.src = "./video/" + fileName;
|
||||
let elements = comp.$el.getElementsByTagName("video");
|
||||
let element = elements && elements[0];
|
||||
if (element) {
|
||||
element.setAttribute("data-exported-src", "./video/" + fileName);
|
||||
break;
|
||||
|
||||
case "MessageIncomingVideoExport":
|
||||
case "MessageOutgoingVideoExport":
|
||||
{
|
||||
var extension = ".mp4";
|
||||
let fileName = comp.event.getId() + extension;
|
||||
videoFolder.file(fileName, blob); // TODO calc bytes
|
||||
// comp.src = "./video/" + fileName;
|
||||
let elements = comp.$el.getElementsByTagName("video");
|
||||
let element = elements && elements[0];
|
||||
if (element) {
|
||||
element.setAttribute("data-exported-src", "./video/" + fileName);
|
||||
}
|
||||
this.processedEvents += 1;
|
||||
}
|
||||
this.processedEvents += 1;
|
||||
resolve(true);
|
||||
});
|
||||
break;
|
||||
|
||||
case "MessageIncomingFileExport":
|
||||
case "MessageOutgoingFileExport":
|
||||
{
|
||||
var extension = util.getFileExtension(comp.event);
|
||||
let fileName = comp.event.getId() + extension;
|
||||
filesFolder.file(fileName, blob);
|
||||
comp.href = "./files/" + fileName;
|
||||
this.processedEvents += 1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
})
|
||||
.catch((ignoredErr) => {
|
||||
this.processedEvents += 1;
|
||||
})
|
||||
);
|
||||
break;
|
||||
case "MessageIncomingFileExport":
|
||||
case "MessageOutgoingFileExport":
|
||||
downloadPromises.push(
|
||||
util
|
||||
.getAttachment(this.$matrix.matrixClient, this.$matrix.useAuthedMedia, comp.event, null, true)
|
||||
.then((blob) => {
|
||||
if (currentMediaSize + blob.size <= maxMediaSize) {
|
||||
currentMediaSize += blob.size;
|
||||
return new Promise((resolve, ignoredReject) => {
|
||||
var extension = util.getFileExtension(comp.event);
|
||||
let fileName = comp.event.getId() + extension;
|
||||
filesFolder.file(fileName, blob);
|
||||
comp.href="./files/" + fileName;
|
||||
this.processedEvents += 1;
|
||||
resolve(true);
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((ignoredErr) => {
|
||||
return true;
|
||||
} else {
|
||||
this.processedEvents += 1;
|
||||
})
|
||||
);
|
||||
break;
|
||||
default:
|
||||
this.processedEvents += 1;
|
||||
break;
|
||||
return false;
|
||||
}
|
||||
})
|
||||
.catch((ignoredErr) => {
|
||||
this.processedEvents += 1;
|
||||
})
|
||||
);
|
||||
} else {
|
||||
this.processedEvents += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -496,7 +480,7 @@ export default {
|
|||
|
||||
let root = this.$refs.exportRoot;
|
||||
|
||||
var doc = "<!DOCTYPE html>\n<html><head>\n<meta charset=\"utf-8\"/>\n";
|
||||
var doc = '<!DOCTYPE html>\n<html><head>\n<meta charset="utf-8"/>\n';
|
||||
|
||||
for (const sheet of document.styleSheets) {
|
||||
doc += "<style type='text/css'>\n";
|
||||
|
|
@ -542,7 +526,8 @@ export default {
|
|||
this.$emit("close");
|
||||
});
|
||||
},
|
||||
onLayoutChange(action, ignoredelement) {
|
||||
onLayoutChange(event) {
|
||||
const { action, element } = event;
|
||||
action();
|
||||
},
|
||||
},
|
||||
|
|
@ -551,7 +536,8 @@ export default {
|
|||
|
||||
<style lang="scss">
|
||||
.chat-root.export {
|
||||
.messageIn-thread, .messageOut-thread {
|
||||
.messageIn-thread,
|
||||
.messageOut-thread {
|
||||
/** For media threads, hide all duplicated metadata, like
|
||||
sender, sender avatar, time, quick reactions etc. They are
|
||||
shown for the root thread event */
|
||||
|
|
@ -561,11 +547,14 @@ export default {
|
|||
.messageOut {
|
||||
margin-right: 50px !important;
|
||||
}
|
||||
.messageIn, .messageOut {
|
||||
.quick-reaction-container, .senderAndTime, .avatar {
|
||||
.messageIn,
|
||||
.messageOut {
|
||||
.quick-reaction-container,
|
||||
.senderAndTime,
|
||||
.avatar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</style>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue