mirror of https://github.com/vector-im/riot-web
Better file names
parent
a0a604618c
commit
80c0ad82fc
|
@ -136,3 +136,19 @@ export function wantsDateSeparator(prevEventDate: Date, nextEventDate: Date): bo
|
||||||
// Compare weekdays
|
// Compare weekdays
|
||||||
return prevEventDate.getDay() !== nextEventDate.getDay();
|
return prevEventDate.getDay() !== nextEventDate.getDay();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function formatFullDateNoDayNoTime(date: Date) {
|
||||||
|
const dateTime = date.getFullYear() +
|
||||||
|
"-" +
|
||||||
|
pad(date.getMonth()) +
|
||||||
|
"-" +
|
||||||
|
pad(date.getDate()) +
|
||||||
|
_t(" at ") +
|
||||||
|
pad(date.getHours()) +
|
||||||
|
"." +
|
||||||
|
pad(date.getMinutes()) +
|
||||||
|
"." +
|
||||||
|
pad(date.getSeconds());
|
||||||
|
return dateTime;
|
||||||
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ import BaseAvatar from "./BaseAvatar";
|
||||||
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
import { mediaFromMxc } from "../../../customisations/Media";
|
import { mediaFromMxc } from "../../../customisations/Media";
|
||||||
import { ResizeMethod } from "../../../Avatar";
|
import { ResizeMethod } from "../../../Avatar";
|
||||||
|
import { omit } from "lodash";
|
||||||
|
|
||||||
interface IProps extends Omit<React.ComponentProps<typeof BaseAvatar>, "name" | "idName" | "url"> {
|
interface IProps extends Omit<React.ComponentProps<typeof BaseAvatar>, "name" | "idName" | "url"> {
|
||||||
member: RoomMember;
|
member: RoomMember;
|
||||||
|
@ -94,6 +95,8 @@ export default class MemberAvatar extends React.Component<IProps, IState> {
|
||||||
let {member, fallbackUserId, onClick, viewUserOnClick, ...otherProps} = this.props;
|
let {member, fallbackUserId, onClick, viewUserOnClick, ...otherProps} = this.props;
|
||||||
const userId = member ? member.userId : fallbackUserId;
|
const userId = member ? member.userId : fallbackUserId;
|
||||||
|
|
||||||
|
otherProps = omit(otherProps, "avatarSrc");
|
||||||
|
|
||||||
if (viewUserOnClick) {
|
if (viewUserOnClick) {
|
||||||
onClick = () => {
|
onClick = () => {
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
|
|
|
@ -103,6 +103,7 @@
|
||||||
"%(weekDayName)s, %(monthName)s %(day)s %(time)s": "%(weekDayName)s, %(monthName)s %(day)s %(time)s",
|
"%(weekDayName)s, %(monthName)s %(day)s %(time)s": "%(weekDayName)s, %(monthName)s %(day)s %(time)s",
|
||||||
"%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s": "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s",
|
"%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s": "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s",
|
||||||
"%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s %(time)s": "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s %(time)s",
|
"%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s %(time)s": "%(weekDayName)s, %(monthName)s %(day)s %(fullYear)s %(time)s",
|
||||||
|
" at ": " at ",
|
||||||
"Who would you like to add to this community?": "Who would you like to add to this community?",
|
"Who would you like to add to this community?": "Who would you like to add to this community?",
|
||||||
"Warning: any person you add to a community will be publicly visible to anyone who knows the community ID": "Warning: any person you add to a community will be publicly visible to anyone who knows the community ID",
|
"Warning: any person you add to a community will be publicly visible to anyone who knows the community ID": "Warning: any person you add to a community will be publicly visible to anyone who knows the community ID",
|
||||||
"Invite new community members": "Invite new community members",
|
"Invite new community members": "Invite new community members",
|
||||||
|
|
|
@ -9,7 +9,7 @@ import { Exporter } from "./Exporter";
|
||||||
import { renderToStaticMarkup } from 'react-dom/server'
|
import { renderToStaticMarkup } from 'react-dom/server'
|
||||||
import { Layout } from "../../settings/Layout";
|
import { Layout } from "../../settings/Layout";
|
||||||
import { shouldFormContinuation } from "../../components/structures/MessagePanel";
|
import { shouldFormContinuation } from "../../components/structures/MessagePanel";
|
||||||
import { wantsDateSeparator } from "../../DateUtils";
|
import { formatFullDateNoDayNoTime, wantsDateSeparator } from "../../DateUtils";
|
||||||
import { RoomPermalinkCreator } from "../permalinks/Permalinks";
|
import { RoomPermalinkCreator } from "../permalinks/Permalinks";
|
||||||
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";
|
||||||
|
@ -18,6 +18,7 @@ import DateSeparator from "../../components/views/messages/DateSeparator";
|
||||||
import exportCSS from "./exportCSS";
|
import exportCSS from "./exportCSS";
|
||||||
import exportJS from "./exportJS";
|
import exportJS from "./exportJS";
|
||||||
import BaseAvatar from "../../components/views/avatars/BaseAvatar";
|
import BaseAvatar from "../../components/views/avatars/BaseAvatar";
|
||||||
|
import exportIcons from "./exportIcons";
|
||||||
|
|
||||||
export default class HTMLExporter extends Exporter {
|
export default class HTMLExporter extends Exporter {
|
||||||
protected zip: JSZip;
|
protected zip: JSZip;
|
||||||
|
@ -179,6 +180,37 @@ export default class HTMLExporter extends Exporter {
|
||||||
return wantsDateSeparator(prevEvent.getDate(), event.getDate());
|
return wantsDateSeparator(prevEvent.getDate(), event.getDate());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected splitFileName(file: string) {
|
||||||
|
const lastDot = file.lastIndexOf('.');
|
||||||
|
if (lastDot === -1) return [file, ""];
|
||||||
|
const fileName = file.slice(0, lastDot);
|
||||||
|
const ext = file.slice(lastDot + 1);
|
||||||
|
return [fileName, ext];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getFilePath(event: MatrixEvent) {
|
||||||
|
const mediaType = event.getContent().msgtype;
|
||||||
|
let fileDirectory: string;
|
||||||
|
switch (mediaType) {
|
||||||
|
case "m.image":
|
||||||
|
fileDirectory = "images";
|
||||||
|
break;
|
||||||
|
case "m.video":
|
||||||
|
fileDirectory = "videos";
|
||||||
|
break;
|
||||||
|
case "m.audio":
|
||||||
|
fileDirectory = "audio";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fileDirectory = "files";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const fileDate = formatFullDateNoDayNoTime(new Date(event.getTs()));
|
||||||
|
const [fileName, fileExt] = this.splitFileName(event.getContent().body);
|
||||||
|
const filePath = fileDirectory + "/" + fileName + '-' + fileDate + '.' + fileExt;
|
||||||
|
return filePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
protected getEventTile(mxEv: MatrixEvent, continuation: boolean, mediaSrc?: string) {
|
protected getEventTile(mxEv: MatrixEvent, continuation: boolean, mediaSrc?: string) {
|
||||||
const hasAvatar = this.hasAvatar(mxEv);
|
const hasAvatar = this.hasAvatar(mxEv);
|
||||||
|
@ -215,31 +247,12 @@ export default class HTMLExporter extends Exporter {
|
||||||
protected async createMessageBody(mxEv: MatrixEvent, joined = false) {
|
protected async createMessageBody(mxEv: MatrixEvent, joined = false) {
|
||||||
let eventTile: JSX.Element;
|
let eventTile: JSX.Element;
|
||||||
switch (mxEv.getContent().msgtype) {
|
switch (mxEv.getContent().msgtype) {
|
||||||
case "m.image": {
|
case "m.image":
|
||||||
const blob = await this.getMediaBlob(mxEv);
|
case "m.file":
|
||||||
const filePath = `images/${mxEv.getId()}.${blob.type.replace("image/", "")}`;
|
case "m.video":
|
||||||
eventTile = this.getEventTile(mxEv, joined, filePath);
|
|
||||||
this.zip.file(filePath, blob);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "m.video": {
|
|
||||||
const blob = await this.getMediaBlob(mxEv);
|
|
||||||
const filePath = `videos/${mxEv.getId()}.${blob.type.replace("video/", "")}`;
|
|
||||||
eventTile = this.getEventTile(mxEv, joined, filePath);
|
|
||||||
this.zip.file(filePath, blob);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "m.audio": {
|
case "m.audio": {
|
||||||
const blob = await this.getMediaBlob(mxEv);
|
const blob = await this.getMediaBlob(mxEv);
|
||||||
const filePath = `audio/${mxEv.getId()}.${blob.type.replace("audio/", "")}`;
|
const filePath = this.getFilePath(mxEv);
|
||||||
eventTile = this.getEventTile(mxEv, joined, filePath);
|
|
||||||
this.zip.file(filePath, blob);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case "m.file": {
|
|
||||||
const blob = await this.getMediaBlob(mxEv);
|
|
||||||
const fileName = mxEv.getContent().body;
|
|
||||||
const filePath = `files/${fileName}`;
|
|
||||||
eventTile = this.getEventTile(mxEv, joined, filePath);
|
eventTile = this.getEventTile(mxEv, joined, filePath);
|
||||||
this.zip.file(filePath, blob);
|
this.zip.file(filePath, blob);
|
||||||
break;
|
break;
|
||||||
|
@ -273,8 +286,10 @@ export default class HTMLExporter extends Exporter {
|
||||||
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) {
|
||||||
const filename = `matrix-export-${new Date().toISOString()}.zip`;
|
this.zip.file(`icons/${iconName}`, exportIcons[iconName]);
|
||||||
|
}
|
||||||
|
const filename = `matrix-export-${formatFullDateNoDayNoTime(new Date())}.zip`;
|
||||||
|
|
||||||
//Generate the zip file asynchronously
|
//Generate the zip file asynchronously
|
||||||
const blob = await this.zip.generateAsync({ type: "blob" });
|
const blob = await this.zip.generateAsync({ type: "blob" });
|
||||||
|
|
Loading…
Reference in New Issue