This commit is contained in:
Jaiwanth 2021-06-03 13:21:56 +05:30
parent 183166c460
commit 4c22d1f2a1
3 changed files with 55 additions and 52 deletions

View file

@ -1,7 +1,36 @@
import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { MatrixEvent } from "matrix-js-sdk/src/models/event";
import { Room } from "matrix-js-sdk/src/models/room"; import { Room } from "matrix-js-sdk/src/models/room";
import { MatrixClientPeg } from "../../MatrixClientPeg";
import { TimelineWindow } from "matrix-js-sdk/src/timeline-window";
import { arrayFastClone } from "../arrays";
export abstract class Exporter { export abstract class Exporter {
constructor(protected res: MatrixEvent[], protected room: Room) {} constructor(protected room: Room) {}
protected getTimelineConversation = () : MatrixEvent => {
if (!this.room) return;
const cli = MatrixClientPeg.get();
const timelineSet = this.room.getUnfilteredTimelineSet();
const timelineWindow = new TimelineWindow(
cli, timelineSet,
{windowLimit: Number.MAX_VALUE});
timelineWindow.load(null, 30);
const events = timelineWindow.getEvents();
// Clone and reverse the events so that we preserve the order
arrayFastClone(events)
.reverse()
.forEach(event => {
cli.decryptEventIfNeeded(event);
});
return events;
};
abstract export(): Promise<Blob>; abstract export(): Promise<Blob>;
} }

View file

@ -11,25 +11,25 @@ import { Layout } from "../../settings/Layout";
import { shouldFormContinuation } from "../../components/structures/MessagePanel"; import { shouldFormContinuation } from "../../components/structures/MessagePanel";
import { formatFullDateNoDay, formatFullDateNoDayNoTime, wantsDateSeparator } from "../../DateUtils"; import { formatFullDateNoDay, formatFullDateNoDayNoTime, wantsDateSeparator } from "../../DateUtils";
import { RoomPermalinkCreator } from "../permalinks/Permalinks"; import { RoomPermalinkCreator } from "../permalinks/Permalinks";
import { _t } from "../../languageHandler";
import { MatrixClientPeg } from "../../MatrixClientPeg";
import { EventType } from "matrix-js-sdk/src/@types/event";
import * as ponyfill from "web-streams-polyfill/ponyfill" import * as ponyfill from "web-streams-polyfill/ponyfill"
import * as Avatar from "../../Avatar"; import * as Avatar from "../../Avatar";
import EventTile, { haveTileForEvent } from "../../components/views/rooms/EventTile"; import EventTile, { haveTileForEvent } from "../../components/views/rooms/EventTile";
import DateSeparator from "../../components/views/messages/DateSeparator"; import DateSeparator from "../../components/views/messages/DateSeparator";
import BaseAvatar from "../../components/views/avatars/BaseAvatar";
import exportCSS from "./exportCSS"; import exportCSS from "./exportCSS";
import exportJS from "./exportJS"; import exportJS from "./exportJS";
import BaseAvatar from "../../components/views/avatars/BaseAvatar";
import exportIcons from "./exportIcons"; import exportIcons from "./exportIcons";
import { _t } from "../../languageHandler";
import { MatrixClientPeg } from "../../MatrixClientPeg";
import { EventType } from "matrix-js-sdk/src/@types/event";
export default class HTMLExporter extends Exporter { export default class HTMLExporter extends Exporter {
protected zip: JSZip; protected zip: JSZip;
protected avatars: Map<string, boolean>; protected avatars: Map<string, boolean>;
protected permalinkCreator: RoomPermalinkCreator; protected permalinkCreator: RoomPermalinkCreator;
constructor(res: MatrixEvent[], room: Room) { constructor(room: Room) {
super(res, room); super(room);
this.zip = new JSZip(); this.zip = new JSZip();
this.avatars = new Map<string, boolean>(); this.avatars = new Map<string, boolean>();
this.permalinkCreator = new RoomPermalinkCreator(this.room); this.permalinkCreator = new RoomPermalinkCreator(this.room);
@ -57,16 +57,16 @@ export default class HTMLExporter extends Exporter {
return renderToStaticMarkup(avatar); return renderToStaticMarkup(avatar);
} }
protected async wrapHTML(content: string, room: Room) { protected async wrapHTML(content: string) {
const roomAvatar32 = await this.getRoomAvatar(32); const roomAvatar32 = await this.getRoomAvatar(32);
const exportDate = formatFullDateNoDayNoTime(new Date()); const exportDate = formatFullDateNoDayNoTime(new Date());
const cli = MatrixClientPeg.get(); const cli = MatrixClientPeg.get();
const creator = room.currentState.getStateEvents(EventType.RoomCreate, "")?.getSender(); const creator = this.room.currentState.getStateEvents(EventType.RoomCreate, "")?.getSender();
const creatorName = room?.getMember(creator)?.rawDisplayName || creator; const creatorName = this.room?.getMember(creator)?.rawDisplayName || creator;
const exporter = cli.getUserId(); const exporter = cli.getUserId();
const exporterName = room?.getMember(exporter)?.rawDisplayName; const exporterName = this.room?.getMember(exporter)?.rawDisplayName;
const topic = room.currentState.getStateEvents(EventType.RoomTopic, "")?.getContent()?.topic const topic = this.room.currentState.getStateEvents(EventType.RoomTopic, "")?.getContent()?.topic
|| room.topic || ""; || this.room.topic || "";
const createdText = _t("%(creatorName)s created this room.", { const createdText = _t("%(creatorName)s created this room.", {
creatorName, creatorName,
}); });
@ -74,7 +74,7 @@ export default class HTMLExporter extends Exporter {
const exportedText = _t(`This is the start of export of <b>%(roomName)s</b>. const exportedText = _t(`This is the start of export of <b>%(roomName)s</b>.
Exported by %(exporterDetails)s at %(exportDate)s. `, { Exported by %(exporterDetails)s at %(exportDate)s. `, {
exportDate, exportDate,
roomName: room.name, roomName: this.room.name,
exporterDetails: `<a href="https://matrix.to/#/${exporter}" target="_blank" rel="noopener noreferrer"> exporterDetails: `<a href="https://matrix.to/#/${exporter}" target="_blank" rel="noopener noreferrer">
${exporterName ? `<b>${ exporterName }</b>(${ exporter })` : `<b>${ exporter }</b>`} ${exporterName ? `<b>${ exporterName }</b>(${ exporter })` : `<b>${ exporter }</b>`}
</a>`, </a>`,
@ -115,9 +115,9 @@ export default class HTMLExporter extends Exporter {
<div <div
dir="auto" dir="auto"
class="mx_RoomHeader_nametext" class="mx_RoomHeader_nametext"
title="${room.name}" title="${this.room.name}"
> >
${room.name} ${this.room.name}
</div> </div>
</div> </div>
<div class="mx_RoomHeader_topic" dir="auto"> ${topic} </div> <div class="mx_RoomHeader_topic" dir="auto"> ${topic} </div>
@ -144,7 +144,7 @@ export default class HTMLExporter extends Exporter {
> >
<div class="mx_NewRoomIntro"> <div class="mx_NewRoomIntro">
${roomAvatar52} ${roomAvatar52}
<h2> ${room.name} </h2> <h2> ${this.room.name} </h2>
<p> ${createdText} <br/><br/> ${exportedText} </p> <p> ${createdText} <br/><br/> ${exportedText} </p>
<p> ${topicText} </p> <p> ${topicText} </p>
</div> </div>
@ -294,7 +294,7 @@ export default class HTMLExporter extends Exporter {
return renderToStaticMarkup(eventTile); return renderToStaticMarkup(eventTile);
} }
protected async createHTML(events: MatrixEvent[], room: Room) { protected async createHTML(events: MatrixEvent[]) {
let content = ""; let content = "";
let prevEvent = null; let prevEvent = null;
for (const event of events) { for (const event of events) {
@ -308,17 +308,21 @@ export default class HTMLExporter extends Exporter {
content += body; content += body;
prevEvent = event; prevEvent = event;
} }
return await this.wrapHTML(content, room); return await this.wrapHTML(content);
} }
public async export() { public async export() {
const html = await this.createHTML(this.res, this.room); const res = this.getTimelineConversation();
const html = await this.createHTML(res);
this.zip.file("index.html", html); this.zip.file("index.html", html);
this.zip.file("css/style.css", exportCSS); this.zip.file("css/style.css", exportCSS);
this.zip.file("js/script.js", exportJS); this.zip.file("js/script.js", exportJS);
for (const iconName in exportIcons) { for (const iconName in exportIcons) {
this.zip.file(`icons/${iconName}`, exportIcons[iconName]); this.zip.file(`icons/${iconName}`, exportIcons[iconName]);
} }
const filename = `matrix-export-${formatFullDateNoDay(new Date())}.zip`; const filename = `matrix-export-${formatFullDateNoDay(new Date())}.zip`;
//Generate the zip file asynchronously //Generate the zip file asynchronously

View file

@ -1,7 +1,4 @@
import { MatrixClientPeg } from "../../MatrixClientPeg"; import { Room } from 'matrix-js-sdk/src/models/room';
import { arrayFastClone } from "../arrays";
import { TimelineWindow } from "matrix-js-sdk/src/timeline-window";
import Room from 'matrix-js-sdk/src/models/room';
import HTMLExporter from "./HtmlExport"; import HTMLExporter from "./HtmlExport";
export enum exportFormats { export enum exportFormats {
@ -14,37 +11,10 @@ export enum exportOptions {
TIMELINE = "TIMELINE", TIMELINE = "TIMELINE",
} }
const getTimelineConversation = (room: Room) => {
if (!room) return;
const cli = MatrixClientPeg.get();
const timelineSet = room.getUnfilteredTimelineSet();
const timelineWindow = new TimelineWindow(
cli, timelineSet,
{windowLimit: Number.MAX_VALUE});
timelineWindow.load(null, 30);
const events = timelineWindow.getEvents();
// Clone and reverse the events so that we preserve the order
arrayFastClone(events)
.reverse()
.forEach(event => {
cli.decryptEventIfNeeded(event);
});
return events;
};
const exportConversationalHistory = async (room: Room, format: string, options) => { const exportConversationalHistory = async (room: Room, format: string, options) => {
const res = getTimelineConversation(room);
switch (format) { switch (format) {
case exportFormats.HTML: case exportFormats.HTML:
await new HTMLExporter(res, room).export(); await new HTMLExporter(room).export();
break; break;
case exportFormats.JSON: case exportFormats.JSON:
break; break;