mirror of
https://github.com/vector-im/element-web.git
synced 2024-11-15 20:54:59 +08:00
Apply review suggestions
This commit is contained in:
parent
c62210b07c
commit
7207329c15
@ -35,7 +35,7 @@ limitations under the License.
|
||||
}
|
||||
|
||||
.mx_RadioButton input[type="radio"]:checked + div > div {
|
||||
background: gray;
|
||||
background: $greyed-fg-color;
|
||||
}
|
||||
|
||||
.mx_RadioButton input[type=radio]:checked + div {
|
||||
@ -52,8 +52,8 @@ limitations under the License.
|
||||
}
|
||||
|
||||
.mx_Checkbox input[type="checkbox"]:checked + label > .mx_Checkbox_background {
|
||||
background: gray;
|
||||
border-color: gray;
|
||||
background: $greyed-fg-color;
|
||||
border-color: $greyed-fg-color;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -312,7 +312,10 @@ function textForMessageEvent(ev: MatrixEvent): () => string | null {
|
||||
message = _t('%(senderDisplayName)s sent an image.', { senderDisplayName });
|
||||
} else if (ev.getType() == "m.sticker") {
|
||||
message = _t('%(senderDisplayName)s sent a sticker.', { senderDisplayName });
|
||||
} else message = senderDisplayName + ': ' + message;
|
||||
} else {
|
||||
// in this case, parse it as a plain text message
|
||||
message = senderDisplayName + ': ' + message;
|
||||
}
|
||||
return message;
|
||||
};
|
||||
}
|
||||
|
@ -36,7 +36,6 @@ interface IProps extends Omit<React.ComponentProps<typeof BaseAvatar>, "name" |
|
||||
// Whether the onClick of the avatar should be overridden to dispatch `Action.ViewUser`
|
||||
viewUserOnClick?: boolean;
|
||||
title?: string;
|
||||
forExport?: boolean;
|
||||
}
|
||||
|
||||
interface IState {
|
||||
@ -90,8 +89,7 @@ export default class MemberAvatar extends React.Component<IProps, IState> {
|
||||
}
|
||||
|
||||
render() {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
let { member, fallbackUserId, onClick, viewUserOnClick, forExport, ...otherProps } = this.props;
|
||||
let { member, fallbackUserId, onClick, viewUserOnClick, ...otherProps } = this.props;
|
||||
const userId = member ? member.userId : fallbackUserId;
|
||||
|
||||
if (viewUserOnClick) {
|
||||
|
@ -29,13 +29,15 @@ import {
|
||||
textForFormat,
|
||||
textForType,
|
||||
} from "../../../utils/exportUtils/exportUtils";
|
||||
import { IFieldState, IValidationResult } from "../elements/Validation";
|
||||
import withValidation, { IFieldState, IValidationResult } from "../elements/Validation";
|
||||
import HTMLExporter from "../../../utils/exportUtils/HtmlExport";
|
||||
import JSONExporter from "../../../utils/exportUtils/JSONExport";
|
||||
import PlainTextExporter from "../../../utils/exportUtils/PlainTextExport";
|
||||
import { useStateCallback } from "../../../hooks/useStateCallback";
|
||||
import Exporter from "../../../utils/exportUtils/Exporter";
|
||||
import Spinner from "../elements/Spinner";
|
||||
import Modal from "../../../Modal";
|
||||
import InfoDialog from "./InfoDialog";
|
||||
|
||||
interface IProps extends IDialogProps {
|
||||
room: Room;
|
||||
@ -126,67 +128,85 @@ const ExportDialog: React.FC<IProps> = ({ room, onFinished }) => {
|
||||
await startExport();
|
||||
};
|
||||
|
||||
const onValidateSize = async ({
|
||||
value,
|
||||
}: Pick<IFieldState, "value">): Promise<IValidationResult> => {
|
||||
const parsedSize = parseFloat(value);
|
||||
const min = 1;
|
||||
const max = 2000;
|
||||
const validateSize = withValidation({
|
||||
rules: [
|
||||
{
|
||||
key: "required",
|
||||
test({ value, allowEmpty }) {
|
||||
return allowEmpty || !!value;
|
||||
},
|
||||
invalid: () => {
|
||||
const min = 1;
|
||||
const max = 10 ** 8;
|
||||
return _t("Enter a number between %(min)s and %(max)s", {
|
||||
min,
|
||||
max,
|
||||
});
|
||||
},
|
||||
}, {
|
||||
key: "number",
|
||||
test: ({ value }) => {
|
||||
const parsedSize = parseFloat(value);
|
||||
const min = 1;
|
||||
const max = 2000;
|
||||
return !(isNaN(parsedSize) || min > parsedSize || parsedSize > max);
|
||||
},
|
||||
invalid: () => {
|
||||
const min = 1;
|
||||
const max = 2000;
|
||||
return _t(
|
||||
"Size can only be a number between %(min)s MB and %(max)s MB",
|
||||
{ min, max },
|
||||
);
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
if (isNaN(parsedSize)) {
|
||||
return { valid: false, feedback: _t("Size must be a number") };
|
||||
}
|
||||
|
||||
if (min > parsedSize || parsedSize > max) {
|
||||
return {
|
||||
valid: false,
|
||||
feedback: _t(
|
||||
"Size can only be between %(min)s MB and %(max)s MB",
|
||||
{ min, max },
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
valid: true,
|
||||
feedback: _t("Enter size between %(min)s MB and %(max)s MB", {
|
||||
min,
|
||||
max,
|
||||
}),
|
||||
};
|
||||
const onValidateSize = async (fieldState: IFieldState): Promise<IValidationResult> => {
|
||||
const result = await validateSize(fieldState);
|
||||
return result;
|
||||
};
|
||||
|
||||
const onValidateNumberOfMessages = async ({
|
||||
value,
|
||||
}: Pick<IFieldState, "value">): Promise<IValidationResult> => {
|
||||
const parsedSize = parseFloat(value);
|
||||
const min = 1;
|
||||
const max = 10 ** 8;
|
||||
const validateNumberOfMessages = withValidation({
|
||||
rules: [
|
||||
{
|
||||
key: "required",
|
||||
test({ value, allowEmpty }) {
|
||||
return allowEmpty || !!value;
|
||||
},
|
||||
invalid: () => {
|
||||
const min = 1;
|
||||
const max = 10 ** 8;
|
||||
return _t("Enter a number between %(min)s and %(max)s", {
|
||||
min,
|
||||
max,
|
||||
});
|
||||
},
|
||||
}, {
|
||||
key: "number",
|
||||
test: ({ value }) => {
|
||||
const parsedSize = parseFloat(value);
|
||||
const min = 1;
|
||||
const max = 10 ** 8;
|
||||
if (isNaN(parsedSize)) return false;
|
||||
return !(min > parsedSize || parsedSize > max);
|
||||
},
|
||||
invalid: () => {
|
||||
const min = 1;
|
||||
const max = 10 ** 8;
|
||||
return _t(
|
||||
"Number of messages can only be a number between %(min)s and %(max)s",
|
||||
{ min, max },
|
||||
);
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
if (isNaN(parsedSize)) {
|
||||
return {
|
||||
valid: false,
|
||||
feedback: _t("Number of messages must be a number"),
|
||||
};
|
||||
}
|
||||
|
||||
if (min > parsedSize || parsedSize > max) {
|
||||
return {
|
||||
valid: false,
|
||||
feedback: _t(
|
||||
"Number of messages can only be between %(min)s and %(max)s",
|
||||
{ min, max },
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
valid: true,
|
||||
feedback: _t("Enter a number between %(min)s and %(max)s", {
|
||||
min,
|
||||
max,
|
||||
}),
|
||||
};
|
||||
const onValidateNumberOfMessages = async (fieldState: IFieldState): Promise<IValidationResult> => {
|
||||
const result = await validateNumberOfMessages(fieldState);
|
||||
return result;
|
||||
};
|
||||
|
||||
const onCancel = async () => {
|
||||
@ -236,42 +256,20 @@ const ExportDialog: React.FC<IProps> = ({ room, onFinished }) => {
|
||||
|
||||
if (exportCancelled) {
|
||||
// Display successful cancellation message
|
||||
return (
|
||||
<BaseDialog
|
||||
title={_t("Export Cancelled")}
|
||||
className="mx_ExportDialog"
|
||||
contentId="mx_Dialog_content"
|
||||
onFinished={onFinished}
|
||||
fixedWidth={true}
|
||||
>
|
||||
<p>{ _t("The export was cancelled successfully") }</p>
|
||||
|
||||
<DialogButtons
|
||||
primaryButton={_t("Okay")}
|
||||
hasCancel={false}
|
||||
onPrimaryButtonClick={onFinished}
|
||||
/>
|
||||
</BaseDialog>
|
||||
);
|
||||
Modal.createTrackedDialog("Export Cancelled", "", InfoDialog, {
|
||||
title: _t("Export Cancelled"),
|
||||
description: <p>{ _t("The export was cancelled successfully") }</p>,
|
||||
hasCloseButton: true,
|
||||
});
|
||||
return null;
|
||||
} else if (exportSuccessful) {
|
||||
// Display successful export message
|
||||
return (
|
||||
<BaseDialog
|
||||
title={_t("Export Successful")}
|
||||
className="mx_ExportDialog"
|
||||
contentId="mx_Dialog_content"
|
||||
onFinished={onFinished}
|
||||
fixedWidth={true}
|
||||
>
|
||||
<p>{ _t("Your messages were successfully exported") }</p>
|
||||
|
||||
<DialogButtons
|
||||
primaryButton={_t("Okay")}
|
||||
hasCancel={false}
|
||||
onPrimaryButtonClick={onFinished}
|
||||
/>
|
||||
</BaseDialog>
|
||||
);
|
||||
Modal.createTrackedDialog("Export Successful", "", InfoDialog, {
|
||||
title: _t("Export Successful"),
|
||||
description: <p>{ _t("Your messages were successfully exported") }</p>,
|
||||
hasCloseButton: true,
|
||||
});
|
||||
return null;
|
||||
} else if (displayCancel) {
|
||||
// Display cancel warning
|
||||
return (
|
||||
|
@ -355,10 +355,10 @@ export default class ReplyThread extends React.Component<IProps, IState> {
|
||||
} else if (this.props.forExport) {
|
||||
const eventId = ReplyThread.getParentEventId(this.props.parentEv);
|
||||
header = <p className="mx_ReplyThread_Export">
|
||||
{ _t("In reply to <messageLink/>",
|
||||
{ _t("In reply to <a>this message</a>",
|
||||
{},
|
||||
{ messageLink: () => (
|
||||
<a className="mx_reply_anchor" href={`#${eventId}`} scroll-to={eventId}> { _t("this message") } </a>
|
||||
{ a: (sub) => (
|
||||
<a className="mx_reply_anchor" href={`#${eventId}`} scroll-to={eventId}> { sub } </a>
|
||||
),
|
||||
})
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ export default class CallEvent extends React.Component<IProps, IState> {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
callState: this.props.callEventGrouper?.state,
|
||||
callState: this.props.callEventGrouper.state,
|
||||
silenced: false,
|
||||
};
|
||||
}
|
||||
@ -210,7 +210,7 @@ export default class CallEvent extends React.Component<IProps, IState> {
|
||||
render() {
|
||||
const event = this.props.mxEvent;
|
||||
const sender = event.sender ? event.sender.name : event.getSender();
|
||||
const isVoice = this.props.callEventGrouper?.isVoice;
|
||||
const isVoice = this.props.callEventGrouper.isVoice;
|
||||
const callType = isVoice ? _t("Voice call") : _t("Video call");
|
||||
const callState = this.state.callState;
|
||||
const hangupReason = this.props.callEventGrouper.hangupReason;
|
||||
|
@ -201,11 +201,7 @@ export default class MFileBody extends React.Component<IProps, IState> {
|
||||
if (this.props.showGenericPlaceholder) {
|
||||
placeholder = (
|
||||
<AccessibleButton className="mx_MediaBody mx_MFileBody_info" onClick={this.onPlaceholderClick}>
|
||||
<span className="mx_MFileBody_info_icon">
|
||||
{ this.props.forExport ?
|
||||
<img alt="Attachment" className="mx_export_attach_icon" src="icons/attach.svg" />
|
||||
: null }
|
||||
</span>
|
||||
<span className="mx_MFileBody_info_icon" />
|
||||
<TextWithTooltip tooltip={presentableTextForFile(this.content, _t("Attachment"), true)}>
|
||||
<span className="mx_MFileBody_info_filename">
|
||||
{ presentableTextForFile(this.content, _t("Attachment"), true, true) }
|
||||
|
@ -39,7 +39,6 @@ const RedactedBody = React.forwardRef<any, IBodyProps>(({ mxEvent, forExport },
|
||||
|
||||
return (
|
||||
<span className="mx_RedactedBody" ref={ref} title={titleText}>
|
||||
{ forExport ? <img alt={_t("Redacted")} className="mx_export_trash_icon" src="icons/trash.svg" /> : null }
|
||||
{ text }
|
||||
</span>
|
||||
);
|
||||
|
@ -725,6 +725,7 @@
|
||||
"Invite to %(spaceName)s": "Invite to %(spaceName)s",
|
||||
"Share your public space": "Share your public space",
|
||||
"Unknown App": "Unknown App",
|
||||
"Are you sure you want to exit during this export?": "Are you sure you want to exit during this export?",
|
||||
"HTML": "HTML",
|
||||
"JSON": "JSON",
|
||||
"Plain Text": "Plain Text",
|
||||
@ -1972,7 +1973,6 @@
|
||||
"<reactors/><reactedWith> reacted with %(content)s</reactedWith>": "<reactors/><reactedWith> reacted with %(content)s</reactedWith>",
|
||||
"<reactors/><reactedWith>reacted with %(shortName)s</reactedWith>": "<reactors/><reactedWith>reacted with %(shortName)s</reactedWith>",
|
||||
"Message deleted on %(date)s": "Message deleted on %(date)s",
|
||||
"Redacted": "Redacted",
|
||||
"%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s changed the avatar for %(roomName)s",
|
||||
"%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s removed the room avatar.",
|
||||
"%(senderDisplayName)s changed the room avatar to <img/>": "%(senderDisplayName)s changed the room avatar to <img/>",
|
||||
@ -2122,8 +2122,7 @@
|
||||
"QR Code": "QR Code",
|
||||
"Unable to load event that was replied to, it either does not exist or you do not have permission to view it.": "Unable to load event that was replied to, it either does not exist or you do not have permission to view it.",
|
||||
"<a>In reply to</a> <pill>": "<a>In reply to</a> <pill>",
|
||||
"In reply to <messageLink/>": "In reply to <messageLink/>",
|
||||
"this message": "this message",
|
||||
"In reply to <a>this message</a>": "In reply to <a>this message</a>",
|
||||
"Room address": "Room address",
|
||||
"e.g. my-room": "e.g. my-room",
|
||||
"Some characters not allowed": "Some characters not allowed",
|
||||
@ -2329,16 +2328,13 @@
|
||||
"There was an error updating your community. The server is unable to process your request.": "There was an error updating your community. The server is unable to process your request.",
|
||||
"Update community": "Update community",
|
||||
"An error has occurred.": "An error has occurred.",
|
||||
"Size can only be between %(min)s MB and %(max)s MB": "Size can only be between %(min)s MB and %(max)s MB",
|
||||
"Enter size between %(min)s MB and %(max)s MB": "Enter size between %(min)s MB and %(max)s MB",
|
||||
"Number of messages must be a number": "Number of messages must be a number",
|
||||
"Number of messages can only be between %(min)s and %(max)s": "Number of messages can only be between %(min)s and %(max)s",
|
||||
"Enter a number between %(min)s and %(max)s": "Enter a number between %(min)s and %(max)s",
|
||||
"Size can only be a number between %(min)s MB and %(max)s MB": "Size can only be a number between %(min)s MB and %(max)s MB",
|
||||
"Number of messages can only be a number between %(min)s and %(max)s": "Number of messages can only be a number between %(min)s and %(max)s",
|
||||
"Number of messages": "Number of messages",
|
||||
"MB": "MB",
|
||||
"Export Cancelled": "Export Cancelled",
|
||||
"The export was cancelled successfully": "The export was cancelled successfully",
|
||||
"Okay": "Okay",
|
||||
"Export Successful": "Export Successful",
|
||||
"Your messages were successfully exported": "Your messages were successfully exported",
|
||||
"Are you sure you want to stop exporting your data? If you do, you'll need to start over.": "Are you sure you want to stop exporting your data? If you do, you'll need to start over.",
|
||||
|
@ -25,6 +25,7 @@ import { Direction, MatrixClient } from "matrix-js-sdk";
|
||||
import { MutableRefObject } from "react";
|
||||
import JSZip from "jszip";
|
||||
import { saveAs } from "file-saver";
|
||||
import { _t } from "../../languageHandler";
|
||||
|
||||
type BlobFile = {
|
||||
name: string;
|
||||
@ -54,7 +55,7 @@ export default abstract class Exporter {
|
||||
|
||||
protected onBeforeUnload(e: BeforeUnloadEvent): string {
|
||||
e.preventDefault();
|
||||
return e.returnValue = "Are you sure you want to exit during this export?";
|
||||
return e.returnValue = _t("Are you sure you want to exit during this export?");
|
||||
}
|
||||
|
||||
protected updateProgress(progress: string, log = true, show = true): void {
|
||||
@ -70,7 +71,7 @@ export default abstract class Exporter {
|
||||
this.files.push(file);
|
||||
}
|
||||
|
||||
protected async downloadZIP(): Promise<string | null> {
|
||||
protected async downloadZIP(): Promise<string | void> {
|
||||
const filename = `matrix-export-${formatFullDateNoDay(new Date())}.zip`;
|
||||
|
||||
const zip = new JSZip();
|
||||
|
@ -31,7 +31,6 @@ import EventTile, { haveTileForEvent } from "../../components/views/rooms/EventT
|
||||
import DateSeparator from "../../components/views/messages/DateSeparator";
|
||||
import BaseAvatar from "../../components/views/avatars/BaseAvatar";
|
||||
import exportJS from "!!raw-loader!./exportJS";
|
||||
import exportIcons from "./exportIcons";
|
||||
import { ExportType } from "./exportUtils";
|
||||
import { IExportOptions } from "./exportUtils";
|
||||
import MatrixClientContext from "../../contexts/MatrixClientContext";
|
||||
@ -294,6 +293,7 @@ export default class HTMLExporter extends Exporter {
|
||||
const mxc = mxEv.getContent().url || mxEv.getContent().file?.url;
|
||||
eventTileMarkup = eventTileMarkup.split(mxc).join(filePath);
|
||||
}
|
||||
eventTileMarkup = eventTileMarkup.replace(/<span class="mx_MFileBody_info_icon".*?>.*?<\/span>/, '');
|
||||
if (hasAvatar) {
|
||||
eventTileMarkup = eventTileMarkup.replace(
|
||||
encodeURI(this.getAvatarURL(mxEv)).replace(/&/g, '&'),
|
||||
@ -406,10 +406,6 @@ export default class HTMLExporter extends Exporter {
|
||||
this.addFile("css/style.css", new Blob([exportCSS]));
|
||||
this.addFile("js/script.js", new Blob([exportJS]));
|
||||
|
||||
for (const iconName in exportIcons) {
|
||||
this.addFile(`icons/${iconName}`, new Blob([exportIcons[iconName]]));
|
||||
}
|
||||
|
||||
await this.downloadZIP();
|
||||
|
||||
const exportEnd = performance.now();
|
||||
|
@ -16,33 +16,31 @@ limitations under the License.
|
||||
|
||||
/* eslint-disable max-len, camelcase */
|
||||
|
||||
declare const __webpack_hash__: string;
|
||||
|
||||
import ThemeWatcher from "../../settings/watchers/ThemeWatcher";
|
||||
|
||||
const getExportCSS = async (): Promise<string> => {
|
||||
const theme = new ThemeWatcher().getEffectiveTheme();
|
||||
const hash = __webpack_hash__;
|
||||
|
||||
const bundle = await fetch(`bundles/${hash}/bundle.css`);
|
||||
const bundleCSS = await bundle.text();
|
||||
let themeCSS: string;
|
||||
if (theme === 'light') {
|
||||
const res = await fetch(`bundles/${hash}/theme-light.css`);
|
||||
themeCSS = await res.text();
|
||||
} else {
|
||||
const res = await fetch(`bundles/${hash}/theme-dark.css`);
|
||||
themeCSS = await res.text();
|
||||
const stylesheets: string[] = [];
|
||||
document.querySelectorAll('link[rel="stylesheet"]').forEach((e: any) => {
|
||||
if (e.href.endsWith("bundle.css") || e.href.endsWith(`theme-${theme}.css`)) {
|
||||
stylesheets.push(e.href);
|
||||
}
|
||||
});
|
||||
let CSS: string;
|
||||
for (const stylesheet of stylesheets) {
|
||||
const res = await fetch(stylesheet);
|
||||
const innerText = await res.text();
|
||||
CSS += innerText;
|
||||
}
|
||||
const fontFaceRegex = /@font-face {.*?}/sg;
|
||||
|
||||
themeCSS = themeCSS.replace(fontFaceRegex, '');
|
||||
themeCSS = themeCSS.replace(
|
||||
CSS = CSS.replace(fontFaceRegex, '');
|
||||
CSS = CSS.replace(
|
||||
/font-family: Inter/g,
|
||||
`font-family: -apple-system, BlinkMacSystemFont, avenir next,
|
||||
avenir, segoe ui, helvetica neue, helvetica, Ubuntu, roboto, noto, arial, sans-serif`,
|
||||
);
|
||||
themeCSS = themeCSS.replace(
|
||||
CSS = CSS.replace(
|
||||
/font-family: Inconsolata/g,
|
||||
"font-family: Menlo, Consolas, Monaco, Liberation Mono, Lucida Console, monospace",
|
||||
);
|
||||
@ -148,6 +146,10 @@ const getExportCSS = async (): Promise<string> => {
|
||||
top: 1px;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.mx_RedactedBody {
|
||||
padding-left: unset;
|
||||
}
|
||||
|
||||
img {
|
||||
white-space: nowrap;
|
||||
@ -155,7 +157,7 @@ const getExportCSS = async (): Promise<string> => {
|
||||
}
|
||||
`;
|
||||
|
||||
return themeCSS + bundleCSS + customCSS;
|
||||
return CSS + customCSS;
|
||||
};
|
||||
|
||||
export default getExportCSS;
|
||||
|
@ -1,23 +0,0 @@
|
||||
/*
|
||||
Copyright 2021 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import trashSVG from "!!raw-loader!../../../res/img/element-icons/trashcan.svg";
|
||||
import attachSVG from "!!raw-loader!../../../res/img/element-icons/room/composer/attach.svg";
|
||||
|
||||
export default {
|
||||
"trash.svg": trashSVG,
|
||||
"attach.svg": attachSVG,
|
||||
};
|
@ -16,7 +16,7 @@ limitations under the License.
|
||||
|
||||
import { IContent, MatrixClient, MatrixEvent, Room } from "matrix-js-sdk";
|
||||
import { MatrixClientPeg } from "../../src/MatrixClientPeg";
|
||||
import { textForFormat, IExportOptions, ExportType } from "../../src/utils/exportUtils/exportUtils";
|
||||
import { IExportOptions, ExportType, ExportFormat } from "../../src/utils/exportUtils/exportUtils";
|
||||
import '../skinned-sdk';
|
||||
import PlainTextExporter from "../../src/utils/exportUtils/PlainTextExport";
|
||||
import HTMLExporter from "../../src/utils/exportUtils/HtmlExport";
|
||||
@ -73,9 +73,60 @@ describe('export', function() {
|
||||
}
|
||||
const mockRoom = createRoom();
|
||||
|
||||
const ts0 = Date.now();
|
||||
|
||||
function mkRedactedEvent(i = 0) {
|
||||
return new MatrixEvent({
|
||||
type: "m.room.message",
|
||||
sender: MY_USER_ID,
|
||||
content: {},
|
||||
unsigned: {
|
||||
"age": 72,
|
||||
"transaction_id": "m1212121212.23",
|
||||
"redacted_because": {
|
||||
"content": {},
|
||||
"origin_server_ts": ts0 + i*1000,
|
||||
"redacts": "$9999999999999999999999999999999999999999998",
|
||||
"sender": "@me:here",
|
||||
"type": "m.room.redaction",
|
||||
"unsigned": {
|
||||
"age": 94,
|
||||
"transaction_id": "m1111111111.1",
|
||||
},
|
||||
"event_id": "$9999999999999999999999999999999999999999998",
|
||||
"room_id": mockRoom.roomId,
|
||||
},
|
||||
},
|
||||
event_id: "$9999999999999999999999999999999999999999999",
|
||||
room_id: mockRoom.roomId,
|
||||
});
|
||||
}
|
||||
|
||||
function mkFileEvent() {
|
||||
return new MatrixEvent({
|
||||
"content": {
|
||||
"body": "index.html",
|
||||
"info": {
|
||||
"mimetype": "text/html",
|
||||
"size": 31613,
|
||||
},
|
||||
"msgtype": "m.file",
|
||||
"url": "mxc://test.org",
|
||||
},
|
||||
"origin_server_ts": 1628872988364,
|
||||
"sender": MY_USER_ID,
|
||||
"type": "m.room.message",
|
||||
"unsigned": {
|
||||
"age": 266,
|
||||
"transaction_id": "m99999999.2",
|
||||
},
|
||||
"event_id": "$99999999999999999999",
|
||||
"room_id": mockRoom.roomId,
|
||||
});
|
||||
}
|
||||
|
||||
function mkEvents() {
|
||||
const matrixEvents = [];
|
||||
const ts0 = Date.now();
|
||||
let i: number;
|
||||
// plain text
|
||||
for (i = 0; i < 10; i++) {
|
||||
@ -134,30 +185,7 @@ describe('export', function() {
|
||||
}));
|
||||
// redacted events
|
||||
for (i = 0; i < 10; i++) {
|
||||
matrixEvents.push(new MatrixEvent({
|
||||
type: "m.room.message",
|
||||
sender: MY_USER_ID,
|
||||
content: {},
|
||||
unsigned: {
|
||||
"age": 72,
|
||||
"transaction_id": "m1212121212.23",
|
||||
"redacted_because": {
|
||||
"content": {},
|
||||
"origin_server_ts": ts0 + i*1000,
|
||||
"redacts": "$9999999999999999999999999999999999999999998",
|
||||
"sender": "@me:here",
|
||||
"type": "m.room.redaction",
|
||||
"unsigned": {
|
||||
"age": 94,
|
||||
"transaction_id": "m1111111111.1",
|
||||
},
|
||||
"event_id": "$9999999999999999999999999999999999999999998",
|
||||
"room_id": mockRoom.roomId,
|
||||
},
|
||||
},
|
||||
event_id: "$9999999999999999999999999999999999999999999",
|
||||
room_id: mockRoom.roomId,
|
||||
}));
|
||||
matrixEvents.push(mkRedactedEvent(i));
|
||||
}
|
||||
return matrixEvents;
|
||||
}
|
||||
@ -165,10 +193,22 @@ describe('export', function() {
|
||||
const events: MatrixEvent[] = mkEvents();
|
||||
|
||||
it('checks if the export format is valid', function() {
|
||||
expect(textForFormat('HTML')).toBeTruthy();
|
||||
expect(textForFormat('JSON')).toBeTruthy();
|
||||
expect(textForFormat('PLAIN_TEXT')).toBeTruthy();
|
||||
expect(() => textForFormat('PDF')).toThrowError("Unknown format");
|
||||
function isValidFormat(format: string): boolean {
|
||||
const options: string[] = Object.values(ExportFormat);
|
||||
return options.includes(format);
|
||||
}
|
||||
expect(isValidFormat("Html")).toBeTruthy();
|
||||
expect(isValidFormat("Json")).toBeTruthy();
|
||||
expect(isValidFormat("PlainText")).toBeTruthy();
|
||||
expect(isValidFormat("Pdf")).toBeFalsy();
|
||||
});
|
||||
|
||||
it("checks if the icons' html corresponds to export regex", function() {
|
||||
const exporter = new HTMLExporter(mockRoom, ExportType.Beginning, mockExportOptions, null);
|
||||
const fileRegex = /<span class="mx_MFileBody_info_icon">.*?<\/span>/;
|
||||
expect(fileRegex.test(
|
||||
renderToString(exporter.getEventTile(mkFileEvent(), true))),
|
||||
).toBeTruthy();
|
||||
});
|
||||
|
||||
it('checks if the export options are valid', function() {
|
||||
|
Loading…
Reference in New Issue
Block a user