diff --git a/CHANGELOG.md b/CHANGELOG.md
index d459b4e94a..58d23e3413 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,115 @@
+Changes in [3.20.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.20.0) (2021-05-10)
+=====================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.20.0-rc.1...v3.20.0)
+
+ * Upgrade to JS SDK 10.1.0
+ * [Release] Don't use the event's metadata to calc the scale of an image
+ [\#6004](https://github.com/matrix-org/matrix-react-sdk/pull/6004)
+
+Changes in [3.20.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.20.0-rc.1) (2021-05-04)
+===============================================================================================================
+[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.19.0...v3.20.0-rc.1)
+
+ * Upgrade to JS SDK 10.1.0-rc.1
+ * Translations update from Weblate
+ [\#5966](https://github.com/matrix-org/matrix-react-sdk/pull/5966)
+ * Fix more space panel layout and hover behaviour issues
+ [\#5965](https://github.com/matrix-org/matrix-react-sdk/pull/5965)
+ * Fix edge case with space panel alignment with subspaces on ff
+ [\#5964](https://github.com/matrix-org/matrix-react-sdk/pull/5964)
+ * Fix saving room pill part to history
+ [\#5951](https://github.com/matrix-org/matrix-react-sdk/pull/5951)
+ * Generate room preview even when minimized
+ [\#5948](https://github.com/matrix-org/matrix-react-sdk/pull/5948)
+ * Another change from recovery passphrase to Security Phrase
+ [\#5934](https://github.com/matrix-org/matrix-react-sdk/pull/5934)
+ * Sort rooms in the add existing to space dialog based on recency
+ [\#5943](https://github.com/matrix-org/matrix-react-sdk/pull/5943)
+ * Inhibit sending RR when context switching to a room
+ [\#5944](https://github.com/matrix-org/matrix-react-sdk/pull/5944)
+ * Prevent room list keyboard handling from landing focus on hidden nodes
+ [\#5950](https://github.com/matrix-org/matrix-react-sdk/pull/5950)
+ * Make the text filter search all spaces instead of just the selected one
+ [\#5942](https://github.com/matrix-org/matrix-react-sdk/pull/5942)
+ * Enable indent rule and fix indent
+ [\#5931](https://github.com/matrix-org/matrix-react-sdk/pull/5931)
+ * Prevent peeking members from reacting
+ [\#5946](https://github.com/matrix-org/matrix-react-sdk/pull/5946)
+ * Disallow inline display maths
+ [\#5939](https://github.com/matrix-org/matrix-react-sdk/pull/5939)
+ * Space creation prompt user to add existing rooms for "Just Me" spaces
+ [\#5923](https://github.com/matrix-org/matrix-react-sdk/pull/5923)
+ * Add test coverage collection script
+ [\#5937](https://github.com/matrix-org/matrix-react-sdk/pull/5937)
+ * Fix joining room using via servers regression
+ [\#5936](https://github.com/matrix-org/matrix-react-sdk/pull/5936)
+ * Revert "Fixes the two Todays problem in Redaction"
+ [\#5938](https://github.com/matrix-org/matrix-react-sdk/pull/5938)
+ * Handle encoded matrix URLs
+ [\#5903](https://github.com/matrix-org/matrix-react-sdk/pull/5903)
+ * Render ignored users setting regardless of if there are any
+ [\#5860](https://github.com/matrix-org/matrix-react-sdk/pull/5860)
+ * Fix inserting trailing colon after mention/pill
+ [\#5830](https://github.com/matrix-org/matrix-react-sdk/pull/5830)
+ * Fixes the two Todays problem in Redaction
+ [\#5917](https://github.com/matrix-org/matrix-react-sdk/pull/5917)
+ * Fix page up/down scrolling only half a page
+ [\#5920](https://github.com/matrix-org/matrix-react-sdk/pull/5920)
+ * Voice messages: Composer controls
+ [\#5935](https://github.com/matrix-org/matrix-react-sdk/pull/5935)
+ * Support MSC3086 asserted identity
+ [\#5886](https://github.com/matrix-org/matrix-react-sdk/pull/5886)
+ * Handle possible edge case with getting stuck in "unsent messages" bar
+ [\#5930](https://github.com/matrix-org/matrix-react-sdk/pull/5930)
+ * Fix suggested rooms not showing up regression from room list optimisation
+ [\#5932](https://github.com/matrix-org/matrix-react-sdk/pull/5932)
+ * Broadcast language change to ElectronPlatform
+ [\#5913](https://github.com/matrix-org/matrix-react-sdk/pull/5913)
+ * Fix VoIP PIP frame color
+ [\#5701](https://github.com/matrix-org/matrix-react-sdk/pull/5701)
+ * Convert some Flow-typed files to TypeScript
+ [\#5912](https://github.com/matrix-org/matrix-react-sdk/pull/5912)
+ * Initial SpaceStore tests work
+ [\#5906](https://github.com/matrix-org/matrix-react-sdk/pull/5906)
+ * Fix issues with space hierarchy in layout and with incompatible servers
+ [\#5926](https://github.com/matrix-org/matrix-react-sdk/pull/5926)
+ * Scale all mxc thumbs using device pixel ratio for hidpi
+ [\#5928](https://github.com/matrix-org/matrix-react-sdk/pull/5928)
+ * Fix add existing to space dialog no longer showing rooms for public spaces
+ [\#5918](https://github.com/matrix-org/matrix-react-sdk/pull/5918)
+ * Disable spaces context switching for when exploring a space
+ [\#5924](https://github.com/matrix-org/matrix-react-sdk/pull/5924)
+ * Autofocus search box in the add existing to space dialog
+ [\#5921](https://github.com/matrix-org/matrix-react-sdk/pull/5921)
+ * Use label element in add existing to space dialog for easier hit target
+ [\#5922](https://github.com/matrix-org/matrix-react-sdk/pull/5922)
+ * Dynamic max and min zoom in the new ImageView
+ [\#5916](https://github.com/matrix-org/matrix-react-sdk/pull/5916)
+ * Improve message error states
+ [\#5897](https://github.com/matrix-org/matrix-react-sdk/pull/5897)
+ * Check for null room in `VisibilityProvider`
+ [\#5914](https://github.com/matrix-org/matrix-react-sdk/pull/5914)
+ * Add unit tests for various collection-based utility functions
+ [\#5910](https://github.com/matrix-org/matrix-react-sdk/pull/5910)
+ * Spaces visual fixes
+ [\#5909](https://github.com/matrix-org/matrix-react-sdk/pull/5909)
+ * Remove reliance on DOM API to generated message preview
+ [\#5908](https://github.com/matrix-org/matrix-react-sdk/pull/5908)
+ * Expand upon voice message event & include overall waveform
+ [\#5888](https://github.com/matrix-org/matrix-react-sdk/pull/5888)
+ * Use floats for image background opacity
+ [\#5905](https://github.com/matrix-org/matrix-react-sdk/pull/5905)
+ * Show invites to spaces at the top of the space panel
+ [\#5902](https://github.com/matrix-org/matrix-react-sdk/pull/5902)
+ * Improve edge cases with spaces context switching
+ [\#5899](https://github.com/matrix-org/matrix-react-sdk/pull/5899)
+ * Fix spaces notification dots wrongly including upgraded (hidden) rooms
+ [\#5900](https://github.com/matrix-org/matrix-react-sdk/pull/5900)
+ * Iterate the spaces face pile design
+ [\#5898](https://github.com/matrix-org/matrix-react-sdk/pull/5898)
+ * Fix alignment issue with nested spaces being cut off wrong
+ [\#5890](https://github.com/matrix-org/matrix-react-sdk/pull/5890)
+
Changes in [3.19.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v3.19.0) (2021-04-26)
=====================================================================================================
[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v3.19.0-rc.1...v3.19.0)
diff --git a/package.json b/package.json
index e54de8a96c..d9ea440936 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "matrix-react-sdk",
- "version": "3.19.0",
+ "version": "3.20.0",
"description": "SDK for matrix.org using React",
"author": "matrix.org",
"repository": {
@@ -58,7 +58,7 @@
"blueimp-canvas-to-blob": "^3.28.0",
"browser-encrypt-attachment": "^0.3.0",
"browser-request": "^0.3.3",
- "cheerio": "^1.0.0-rc.5",
+ "cheerio": "^1.0.0-rc.9",
"classnames": "^2.2.6",
"commonmark": "^0.29.3",
"counterpart": "^0.18.6",
@@ -97,7 +97,7 @@
"react-transition-group": "^4.4.1",
"resize-observer-polyfill": "^1.5.1",
"rfc4648": "^1.4.0",
- "sanitize-html": "github:apostrophecms/sanitize-html#3c7f93f2058f696f5359e3e58d464161647226db",
+ "sanitize-html": "^2.3.2",
"tar-js": "^0.3.0",
"text-encoding-utf-8": "^1.0.2",
"url": "^0.11.0",
@@ -132,11 +132,12 @@
"@types/modernizr": "^3.5.3",
"@types/node": "^14.14.22",
"@types/pako": "^1.0.1",
+ "@types/parse5": "^6.0.0",
"@types/qrcode": "^1.3.5",
"@types/react": "^16.9",
"@types/react-dom": "^16.9.10",
"@types/react-transition-group": "^4.4.0",
- "@types/sanitize-html": "^1.27.0",
+ "@types/sanitize-html": "^2.3.1",
"@types/zxcvbn": "^4.4.0",
"@typescript-eslint/eslint-plugin": "^4.14.0",
"@typescript-eslint/parser": "^4.14.0",
diff --git a/res/css/structures/_SpacePanel.scss b/res/css/structures/_SpacePanel.scss
index 9264e82ea5..c433ccf275 100644
--- a/res/css/structures/_SpacePanel.scss
+++ b/res/css/structures/_SpacePanel.scss
@@ -237,7 +237,6 @@ $activeBorderColor: $secondary-fg-color;
.mx_SpacePanel_badgeContainer {
position: absolute;
- height: 16px;
// Create a flexbox to make aligning dot badges easier
display: flex;
@@ -249,23 +248,37 @@ $activeBorderColor: $secondary-fg-color;
.mx_NotificationBadge_dot {
// make the smaller dot occupy the same width for centering
- margin-left: 7px;
- margin-right: 7px;
+ margin: 0 7px;
}
}
&.collapsed {
.mx_SpaceButton {
.mx_SpacePanel_badgeContainer {
- right: -3px;
- top: -3px;
+ right: 0;
+ top: 0;
+
+ .mx_NotificationBadge {
+ background-clip: padding-box;
+ }
+
+ .mx_NotificationBadge_dot {
+ margin: 0 -1px 0 0;
+ border: 3px solid $groupFilterPanel-bg-color;
+ }
+
+ .mx_NotificationBadge_2char,
+ .mx_NotificationBadge_3char {
+ margin: -5px -5px 0 0;
+ border: 2px solid $groupFilterPanel-bg-color;
+ }
}
&.mx_SpaceButton_active .mx_SpacePanel_badgeContainer {
// when we draw the selection border we move the relative bounds of our parent
// so update our position within the bounds of the parent to maintain position overall
- right: -6px;
- top: -6px;
+ right: -3px;
+ top: -3px;
}
}
}
diff --git a/res/css/structures/_SpaceRoomView.scss b/res/css/structures/_SpaceRoomView.scss
index e74af46bce..c4b3f9a8d3 100644
--- a/res/css/structures/_SpaceRoomView.scss
+++ b/res/css/structures/_SpaceRoomView.scss
@@ -103,6 +103,10 @@ $SpaceRoomViewInnerWidth: 428px;
padding: 8px 22px;
margin-left: 16px;
}
+
+ input.mx_AccessibleButton {
+ border: none; // override default styles
+ }
}
.mx_Field {
diff --git a/res/css/views/rooms/_VoiceRecordComposerTile.scss b/res/css/views/rooms/_VoiceRecordComposerTile.scss
index b87211a847..a3ee104bd8 100644
--- a/res/css/views/rooms/_VoiceRecordComposerTile.scss
+++ b/res/css/views/rooms/_VoiceRecordComposerTile.scss
@@ -46,11 +46,11 @@ limitations under the License.
mask-image: url('$(res)/img/element-icons/trashcan.svg');
}
-.mx_VoiceRecordComposerTile_recording.mx_VoiceMessagePrimaryContainer {
+.mx_MessageComposer_row .mx_VoiceMessagePrimaryContainer {
// Note: remaining class properties are in the PlayerContainer CSS.
margin: 6px; // force the composer area to put a gutter around us
- margin-right: 12px; // isolate from stop button
+ margin-right: 12px; // isolate from stop/send button
position: relative; // important for the live circle
diff --git a/src/HtmlUtils.tsx b/src/HtmlUtils.tsx
index 6b2568d68c..ef5ac383e3 100644
--- a/src/HtmlUtils.tsx
+++ b/src/HtmlUtils.tsx
@@ -422,8 +422,12 @@ export function bodyToHtml(content: IContent, highlights: string[], opts: IOpts
safeBody = sanitizeHtml(formattedBody, sanitizeParams);
if (SettingsStore.getValue("feature_latex_maths")) {
- const phtml = cheerio.load(safeBody,
- { _useHtmlParser2: true, decodeEntities: false })
+ const phtml = cheerio.load(safeBody, {
+ // @ts-ignore: The `_useHtmlParser2` internal option is the
+ // simplest way to both parse and render using `htmlparser2`.
+ _useHtmlParser2: true,
+ decodeEntities: false,
+ });
// @ts-ignore - The types for `replaceWith` wrongly expect
// Cheerio instance to be returned.
phtml('div, span[data-mx-maths!=""]').replaceWith(function(i, e) {
@@ -431,6 +435,7 @@ export function bodyToHtml(content: IContent, highlights: string[], opts: IOpts
AllHtmlEntities.decode(phtml(e).attr('data-mx-maths')),
{
throwOnError: false,
+ // @ts-ignore - `e` can be an Element, not just a Node
displayMode: e.name == 'div',
output: "htmlAndMathml",
});
diff --git a/src/SlashCommands.tsx b/src/SlashCommands.tsx
index 6ce1439164..4a7b37b5e5 100644
--- a/src/SlashCommands.tsx
+++ b/src/SlashCommands.tsx
@@ -38,7 +38,7 @@ import {isPermalinkHost, parsePermalink} from "./utils/permalinks/Permalinks";
import {inviteUsersToRoom} from "./RoomInvite";
import { WidgetType } from "./widgets/WidgetType";
import { Jitsi } from "./widgets/Jitsi";
-import { parseFragment as parseHtml } from "parse5";
+import { parseFragment as parseHtml, Element as ChildElement } from "parse5";
import BugReportDialog from "./components/views/dialogs/BugReportDialog";
import { ensureDMExists } from "./createRoom";
import { ViewUserPayload } from "./dispatcher/payloads/ViewUserPayload";
@@ -856,7 +856,7 @@ export const Commands = [
// some superfast regex over the text so we don't have to.
const embed = parseHtml(widgetUrl);
if (embed && embed.childNodes && embed.childNodes.length === 1) {
- const iframe = embed.childNodes[0];
+ const iframe = embed.childNodes[0] as ChildElement;
if (iframe.tagName.toLowerCase() === 'iframe' && iframe.attrs) {
const srcAttr = iframe.attrs.find(a => a.name === 'src');
console.log("Pulling URL out of iframe (embed code)");
diff --git a/src/components/structures/MessagePanel.js b/src/components/structures/MessagePanel.js
index c93f07fa0f..e5e0065be8 100644
--- a/src/components/structures/MessagePanel.js
+++ b/src/components/structures/MessagePanel.js
@@ -544,11 +544,13 @@ export default class MessagePanel extends React.Component {
}
if (!grouper) {
const wantTile = this._shouldShowEvent(mxEv);
+ const isGrouped = false;
if (wantTile) {
// make sure we unpack the array returned by _getTilesForEvent,
// otherwise react will auto-generate keys and we will end up
// replacing all of the DOM elements every time we paginate.
- ret.push(...this._getTilesForEvent(prevEvent, mxEv, last, nextEvent, nextTile));
+ ret.push(...this._getTilesForEvent(prevEvent, mxEv, last, isGrouped,
+ nextEvent, nextTile));
prevEvent = mxEv;
}
@@ -564,7 +566,7 @@ export default class MessagePanel extends React.Component {
return ret;
}
- _getTilesForEvent(prevEvent, mxEv, last, nextEvent, nextEventWithTile) {
+ _getTilesForEvent(prevEvent, mxEv, last, isGrouped=false, nextEvent, nextEventWithTile) {
const TileErrorBoundary = sdk.getComponent('messages.TileErrorBoundary');
const EventTile = sdk.getComponent('rooms.EventTile');
const DateSeparator = sdk.getComponent('messages.DateSeparator');
@@ -584,7 +586,7 @@ export default class MessagePanel extends React.Component {
// do we need a date separator since the last event?
const wantsDateSeparator = this._wantsDateSeparator(prevEvent, eventDate);
- if (wantsDateSeparator) {
+ if (wantsDateSeparator && !isGrouped) {
const dateSeparator =
;
ret.push(dateSeparator);
}
@@ -968,9 +970,9 @@ class CreationGrouper {
const DateSeparator = sdk.getComponent('messages.DateSeparator');
const EventListSummary = sdk.getComponent('views.elements.EventListSummary');
-
const panel = this.panel;
const ret = [];
+ const isGrouped = true;
const createEvent = this.createEvent;
const lastShownEvent = this.lastShownEvent;
@@ -984,12 +986,12 @@ class CreationGrouper {
// If this m.room.create event should be shown (room upgrade) then show it before the summary
if (panel._shouldShowEvent(createEvent)) {
// pass in the createEvent as prevEvent as well so no extra DateSeparator is rendered
- ret.push(...panel._getTilesForEvent(createEvent, createEvent, false));
+ ret.push(...panel._getTilesForEvent(createEvent, createEvent));
}
for (const ejected of this.ejectedEvents) {
ret.push(...panel._getTilesForEvent(
- createEvent, ejected, createEvent === lastShownEvent,
+ createEvent, ejected, createEvent === lastShownEvent, isGrouped,
));
}
@@ -998,7 +1000,7 @@ class CreationGrouper {
// of EventListSummary, render each member event as if the previous
// one was itself. This way, the timestamp of the previous event === the
// timestamp of the current event, and no DateSeparator is inserted.
- return panel._getTilesForEvent(e, e, e === lastShownEvent);
+ return panel._getTilesForEvent(e, e, e === lastShownEvent, isGrouped);
}).reduce((a, b) => a.concat(b), []);
// Get sender profile from the latest event in the summary as the m.room.create doesn't contain one
const ev = this.events[this.events.length - 1];
@@ -1083,7 +1085,7 @@ class RedactionGrouper {
const DateSeparator = sdk.getComponent('messages.DateSeparator');
const EventListSummary = sdk.getComponent('views.elements.EventListSummary');
-
+ const isGrouped = true;
const panel = this.panel;
const ret = [];
const lastShownEvent = this.lastShownEvent;
@@ -1103,7 +1105,8 @@ class RedactionGrouper {
let eventTiles = this.events.map((e, i) => {
senders.add(e.sender);
const prevEvent = i === 0 ? this.prevEvent : this.events[i - 1];
- return panel._getTilesForEvent(prevEvent, e, e === lastShownEvent, this.nextEvent, this.nextEventTile);
+ return panel._getTilesForEvent(
+ prevEvent, e, e === lastShownEvent, isGrouped, this.nextEvent, this.nextEventTile);
}).reduce((a, b) => a.concat(b), []);
if (eventTiles.length === 0) {
@@ -1182,7 +1185,7 @@ class MemberGrouper {
const DateSeparator = sdk.getComponent('messages.DateSeparator');
const MemberEventListSummary = sdk.getComponent('views.elements.MemberEventListSummary');
-
+ const isGrouped = true;
const panel = this.panel;
const lastShownEvent = this.lastShownEvent;
const ret = [];
@@ -1215,7 +1218,7 @@ class MemberGrouper {
// of MemberEventListSummary, render each member event as if the previous
// one was itself. This way, the timestamp of the previous event === the
// timestamp of the current event, and no DateSeparator is inserted.
- return panel._getTilesForEvent(e, e, e === lastShownEvent);
+ return panel._getTilesForEvent(e, e, e === lastShownEvent, isGrouped);
}).reduce((a, b) => a.concat(b), []);
if (eventTiles.length === 0) {
diff --git a/src/components/structures/RoomSearch.tsx b/src/components/structures/RoomSearch.tsx
index 34682877e0..bda46aef07 100644
--- a/src/components/structures/RoomSearch.tsx
+++ b/src/components/structures/RoomSearch.tsx
@@ -27,8 +27,8 @@ import { Action } from "../../dispatcher/actions";
import RoomListStore from "../../stores/room-list/RoomListStore";
import { NameFilterCondition } from "../../stores/room-list/filters/NameFilterCondition";
import { getKeyBindingsManager, RoomListAction } from "../../KeyBindingsManager";
-import {replaceableComponent} from "../../utils/replaceableComponent";
-import SpaceStore, {UPDATE_SELECTED_SPACE, UPDATE_TOP_LEVEL_SPACES} from "../../stores/SpaceStore";
+import { replaceableComponent } from "../../utils/replaceableComponent";
+import SpaceStore, { UPDATE_SELECTED_SPACE, UPDATE_TOP_LEVEL_SPACES } from "../../stores/SpaceStore";
interface IProps {
isMinimized: boolean;
diff --git a/src/components/structures/SpaceRoomView.tsx b/src/components/structures/SpaceRoomView.tsx
index 441ca81080..031928f22b 100644
--- a/src/components/structures/SpaceRoomView.tsx
+++ b/src/components/structures/SpaceRoomView.tsx
@@ -430,7 +430,9 @@ const SpaceSetupFirstRooms = ({ space, title, description, onFinished }) => {
/>;
});
- const onNextClick = async () => {
+ const onNextClick = async (ev) => {
+ ev.preventDefault();
+ if (busy) return;
setError("");
setBusy(true);
try {
@@ -455,7 +457,10 @@ const SpaceSetupFirstRooms = ({ space, title, description, onFinished }) => {
setBusy(false);
};
- let onClick = onFinished;
+ let onClick = (ev) => {
+ ev.preventDefault();
+ onFinished();
+ };
let buttonLabel = _t("Skip for now");
if (roomNames.some(name => name.trim())) {
onClick = onNextClick;
@@ -467,16 +472,20 @@ const SpaceSetupFirstRooms = ({ space, title, description, onFinished }) => {
{ description }
{ error && { error }
}
- { fields }
+
- { buttonLabel }
-
+ element="input"
+ type="submit"
+ form="mx_SpaceSetupFirstRooms"
+ value={buttonLabel}
+ />
;
};
@@ -624,7 +633,9 @@ const SpaceSetupPrivateInvite = ({ space, onFinished }) => {
/>;
});
- const onNextClick = async () => {
+ const onNextClick = async (ev) => {
+ ev.preventDefault();
+ if (busy) return;
setError("");
for (let i = 0; i < fieldRefs.length; i++) {
const fieldRef = fieldRefs[i];
@@ -658,7 +669,10 @@ const SpaceSetupPrivateInvite = ({ space, onFinished }) => {
setBusy(false);
};
- let onClick = onFinished;
+ let onClick = (ev) => {
+ ev.preventDefault();
+ onFinished();
+ };
let buttonLabel = _t("Skip for now");
if (emailAddresses.some(name => name.trim())) {
onClick = onNextClick;
@@ -683,7 +697,9 @@ const SpaceSetupPrivateInvite = ({ space, onFinished }) => {
{ error && { error }
}
- { fields }
+
;
};
diff --git a/src/components/views/context_menus/MessageContextMenu.js b/src/components/views/context_menus/MessageContextMenu.js
index 35efd12c9c..365f2ab1de 100644
--- a/src/components/views/context_menus/MessageContextMenu.js
+++ b/src/components/views/context_menus/MessageContextMenu.js
@@ -78,8 +78,10 @@ export default class MessageContextMenu extends React.Component {
// We explicitly decline to show the redact option on ACL events as it has a potential
// to obliterate the room - https://github.com/matrix-org/synapse/issues/4042
+ // Similarly for encryption events, since redacting them "breaks everything"
const canRedact = room.currentState.maySendRedactionForEvent(this.props.mxEvent, cli.credentials.userId)
- && this.props.mxEvent.getType() !== EventType.RoomServerAcl;
+ && this.props.mxEvent.getType() !== EventType.RoomServerAcl
+ && this.props.mxEvent.getType() !== EventType.RoomEncryption;
let canPin = room.currentState.mayClientSendStateEvent('m.room.pinned_events', cli);
// HACK: Intentionally say we can't pin if the user doesn't want to use the functionality
diff --git a/src/components/views/dialogs/UploadConfirmDialog.js b/src/components/views/dialogs/UploadConfirmDialog.tsx
similarity index 72%
rename from src/components/views/dialogs/UploadConfirmDialog.js
rename to src/components/views/dialogs/UploadConfirmDialog.tsx
index 2ff16b9440..7f6bcd27d1 100644
--- a/src/components/views/dialogs/UploadConfirmDialog.js
+++ b/src/components/views/dialogs/UploadConfirmDialog.tsx
@@ -1,5 +1,5 @@
/*
-Copyright 2019 New Vector Ltd
+Copyright 2019, 2021 The Matrix.org Foundation C.I.C.
Copyright 2019 Michael Telatynski <7t3chguy@gmail.com>
Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,20 +16,23 @@ limitations under the License.
*/
import React from 'react';
-import PropTypes from 'prop-types';
import * as sdk from '../../../index';
import { _t } from '../../../languageHandler';
import filesize from "filesize";
-import {replaceableComponent} from "../../../utils/replaceableComponent";
+import { replaceableComponent } from "../../../utils/replaceableComponent";
+import { getBlobSafeMimeType } from '../../../utils/blobs';
+
+interface IProps {
+ file: File;
+ currentIndex: number;
+ totalFiles?: number;
+ onFinished: (uploadConfirmed: boolean, uploadAll?: boolean) => void;
+}
@replaceableComponent("views.dialogs.UploadConfirmDialog")
-export default class UploadConfirmDialog extends React.Component {
- static propTypes = {
- file: PropTypes.object.isRequired,
- currentIndex: PropTypes.number,
- totalFiles: PropTypes.number,
- onFinished: PropTypes.func.isRequired,
- }
+export default class UploadConfirmDialog extends React.Component {
+ private objectUrl: string;
+ private mimeType: string;
static defaultProps = {
totalFiles: 1,
@@ -38,22 +41,28 @@ export default class UploadConfirmDialog extends React.Component {
constructor(props) {
super(props);
- this._objectUrl = URL.createObjectURL(props.file);
+ // Create a fresh `Blob` for previewing (even though `File` already is
+ // one) so we can adjust the MIME type if needed.
+ this.mimeType = getBlobSafeMimeType(props.file.type);
+ const blob = new Blob([props.file], { type:
+ this.mimeType,
+ });
+ this.objectUrl = URL.createObjectURL(blob);
}
componentWillUnmount() {
- if (this._objectUrl) URL.revokeObjectURL(this._objectUrl);
+ if (this.objectUrl) URL.revokeObjectURL(this.objectUrl);
}
- _onCancelClick = () => {
+ private onCancelClick = () => {
this.props.onFinished(false);
}
- _onUploadClick = () => {
+ private onUploadClick = () => {
this.props.onFinished(true);
}
- _onUploadAllClick = () => {
+ private onUploadAllClick = () => {
this.props.onFinished(true, true);
}
@@ -75,10 +84,10 @@ export default class UploadConfirmDialog extends React.Component {
}
let preview;
- if (this.props.file.type.startsWith('image/')) {
+ if (this.mimeType.startsWith('image/')) {
preview =
-
+
{this.props.file.name} ({filesize(this.props.file.size)})
;
@@ -95,7 +104,7 @@ export default class UploadConfirmDialog extends React.Component {
let uploadAllButton;
if (this.props.currentIndex + 1 < this.props.totalFiles) {
- uploadAllButton =