From 41b995df3c9b54abfc740e71e71b9ad1874ea7ee Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 13 Jun 2019 22:56:32 +0100 Subject: [PATCH 01/31] If oldContent matches newContent, skip sending the edit Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/views/elements/MessageEditor.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/components/views/elements/MessageEditor.js b/src/components/views/elements/MessageEditor.js index 0aff6781ee..72091f2e1c 100644 --- a/src/components/views/elements/MessageEditor.js +++ b/src/components/views/elements/MessageEditor.js @@ -166,6 +166,17 @@ export default class MessageEditor extends React.Component { contentBody.format = newContent.format; contentBody.formatted_body = ` * ${newContent.formatted_body}`; } + + // if nothing has changed then bail + const oldContent = this.props.editState.getEvent().getContent(); + if (oldContent["msgtype"] === newContent["msgtype"] && oldContent["body"] === newContent["body"] && + oldContent["format"] === newContent["format"] && + oldContent["formatted_body"] === newContent["formatted_body"]) { + console.log("skipping"); + this._cancelEdit(); + return; + } + const content = Object.assign({ "m.new_content": newContent, "m.relates_to": { From e591d3ef76828179bac3db5d13fcb73ecb90d34a Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Sat, 29 Jun 2019 06:52:19 +0100 Subject: [PATCH 02/31] take dirty-flag into account for editing Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/views/elements/MessageEditor.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/views/elements/MessageEditor.js b/src/components/views/elements/MessageEditor.js index ce22bf2fc6..4f1bcea971 100644 --- a/src/components/views/elements/MessageEditor.js +++ b/src/components/views/elements/MessageEditor.js @@ -189,10 +189,10 @@ export default class MessageEditor extends React.Component { // if nothing has changed then bail const oldContent = this.props.editState.getEvent().getContent(); - if (oldContent["msgtype"] === newContent["msgtype"] && oldContent["body"] === newContent["body"] && + if (!this._hasModifications || + (oldContent["msgtype"] === newContent["msgtype"] && oldContent["body"] === newContent["body"] && oldContent["format"] === newContent["format"] && - oldContent["formatted_body"] === newContent["formatted_body"]) { - console.log("skipping"); + oldContent["formatted_body"] === newContent["formatted_body"])) { this._cancelEdit(); return; } From d774d96290e954ad126f27e688cbb6693cf38d3f Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Sun, 30 Jun 2019 10:41:39 +0100 Subject: [PATCH 03/31] Fix some React errors Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/views/elements/EditableItemList.js | 8 ++++---- .../settings/tabs/user/PreferencesUserSettingsTab.js | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/components/views/elements/EditableItemList.js b/src/components/views/elements/EditableItemList.js index c6eeb1b93c..ab0fe6e96a 100644 --- a/src/components/views/elements/EditableItemList.js +++ b/src/components/views/elements/EditableItemList.js @@ -121,8 +121,8 @@ export default class EditableItemList extends React.Component { return (
- @@ -135,11 +135,11 @@ export default class EditableItemList extends React.Component { render() { const editableItems = this.props.items.map((item, index) => { if (!this.props.canRemove) { - return
  • {item}
  • ; + return
  • {item}
  • ; } return From 137c531d518112c84ab7255e5348c5d073f9674e Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Wed, 3 Jul 2019 16:45:05 +0100 Subject: [PATCH 04/31] Upgrade to JS SDK 2.1.0-rc.1 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 14d833df96..6e870d3f16 100644 --- a/package.json +++ b/package.json @@ -81,7 +81,7 @@ "linkifyjs": "^2.1.6", "lodash": "^4.13.1", "lolex": "2.3.2", - "matrix-js-sdk": "2.0.1", + "matrix-js-sdk": "2.1.0-rc.1", "optimist": "^0.6.1", "pako": "^1.0.5", "png-chunks-extract": "^1.0.0", diff --git a/yarn.lock b/yarn.lock index 7b949781d7..2d6c8169bc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4877,10 +4877,10 @@ mathml-tag-names@^2.0.1: resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.0.tgz#490b70e062ee24636536e3d9481e333733d00f2c" integrity sha512-3Zs9P/0zzwTob2pdgT0CHZuMbnSUSp8MB1bddfm+HDmnFWHGT4jvEZRf+2RuPoa+cjdn/z25SEt5gFTqdhvJAg== -matrix-js-sdk@2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-2.0.1.tgz#e9691c7fc142793aa8cd79e92d45698bcc5da8c4" - integrity sha512-+yj9fBdIE65v1+46TL/eLQGohtNZGBEtOD1n3nTAVBMogyVb2bpUWnqTli0ghiOCG9MKq7tWi+G4bDBTABxuxA== +matrix-js-sdk@2.1.0-rc.1: + version "2.1.0-rc.1" + resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-2.1.0-rc.1.tgz#0eff1224c6877538df2ccdd8e5b65892473f646f" + integrity sha512-YXybCKTdY8aHKJnr/zl8TR1iEIL890RLrD3Wc3YNWdbIt0ldnrdedreZYMmDhuSVFWbLwx1q8QDHwLZJvUGCdQ== dependencies: another-json "^0.2.0" babel-runtime "^6.26.0" From d3c993543f5a8ee5e9ad6539533aecfccf951b1d Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Wed, 3 Jul 2019 16:56:10 +0100 Subject: [PATCH 05/31] Prepare changelog for v1.3.0-rc.1 --- CHANGELOG.md | 111 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a2ea1d48b..47e7c75d18 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,114 @@ +Changes in [1.3.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v1.3.0-rc.1) (2019-07-03) +============================================================================================================= +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v1.2.2...v1.3.0-rc.1) + + * MELS handle m.room.third_party_invite + [\#3173](https://github.com/matrix-org/matrix-react-sdk/pull/3173) + * Fix logic around MemberList invites section, specifically regarding 3pid + [\#3172](https://github.com/matrix-org/matrix-react-sdk/pull/3172) + * Update from Weblate + [\#3176](https://github.com/matrix-org/matrix-react-sdk/pull/3176) + * Track the user's own typing state external to the composer + [\#3150](https://github.com/matrix-org/matrix-react-sdk/pull/3150) + * Handle associated event send failures + [\#3170](https://github.com/matrix-org/matrix-react-sdk/pull/3170) + * Improve interactive tooltip hover behaviour + [\#3169](https://github.com/matrix-org/matrix-react-sdk/pull/3169) + * Fix login type selector border + [\#3171](https://github.com/matrix-org/matrix-react-sdk/pull/3171) + * Use the event sender instead of event ID for viaServers off a tombstone + [\#3159](https://github.com/matrix-org/matrix-react-sdk/pull/3159) + * Append keyshare request dialogs instead of replacing the current dialog + [\#3160](https://github.com/matrix-org/matrix-react-sdk/pull/3160) + * Add AccessibleTooltipButton and use it for RoomSubList buttons + [\#3165](https://github.com/matrix-org/matrix-react-sdk/pull/3165) + * MemberInfo wrap Device Name/ID + [\#3166](https://github.com/matrix-org/matrix-react-sdk/pull/3166) + * Correctly populate the dispatch for joining a room via servers + [\#3161](https://github.com/matrix-org/matrix-react-sdk/pull/3161) + * Clean up legacy breadcrumbs persistence fallback + [\#3162](https://github.com/matrix-org/matrix-react-sdk/pull/3162) + * Update from Weblate + [\#3168](https://github.com/matrix-org/matrix-react-sdk/pull/3168) + * Add ability to render null-rejoins in Timeline and MELS + [\#3135](https://github.com/matrix-org/matrix-react-sdk/pull/3135) + * Add /myavatar command + [\#3155](https://github.com/matrix-org/matrix-react-sdk/pull/3155) + * Update config.json docs location + [\#3158](https://github.com/matrix-org/matrix-react-sdk/pull/3158) + * If on trackpad, don't mess with horizontal scrolling. + [\#3148](https://github.com/matrix-org/matrix-react-sdk/pull/3148) + * Limit reactions row on initial display + [\#3152](https://github.com/matrix-org/matrix-react-sdk/pull/3152) + * Unpin highlight.js + [\#3156](https://github.com/matrix-org/matrix-react-sdk/pull/3156) + * Flexboxify generic error page + [\#3154](https://github.com/matrix-org/matrix-react-sdk/pull/3154) + * Fix weird scrollbar when devtools is in a narrow browser + [\#3153](https://github.com/matrix-org/matrix-react-sdk/pull/3153) + * Show a loading state for slow peeks + [\#3142](https://github.com/matrix-org/matrix-react-sdk/pull/3142) + * Don't show error dialog when user has no webcam + [\#3146](https://github.com/matrix-org/matrix-react-sdk/pull/3146) + * Make edit history work in encrypted rooms. + [\#3151](https://github.com/matrix-org/matrix-react-sdk/pull/3151) + * Change interactive tooltip to only flip when required + [\#3147](https://github.com/matrix-org/matrix-react-sdk/pull/3147) + * Edit history dialog + [\#3144](https://github.com/matrix-org/matrix-react-sdk/pull/3144) + * Fix the scrollbar in the community bar + [\#3143](https://github.com/matrix-org/matrix-react-sdk/pull/3143) + * Add focus border to edit composer + [\#3145](https://github.com/matrix-org/matrix-react-sdk/pull/3145) + * Supply oobData to RoomPreviewBar + [\#3141](https://github.com/matrix-org/matrix-react-sdk/pull/3141) + * Don't boost trackpad users in breadcrumbs + [\#3140](https://github.com/matrix-org/matrix-react-sdk/pull/3140) + * Fix room upgrade warning being chopped off and a spelling mistake + [\#3139](https://github.com/matrix-org/matrix-react-sdk/pull/3139) + * Add quick reaction buttons in tooltip + [\#3138](https://github.com/matrix-org/matrix-react-sdk/pull/3138) + * When joining from room directory, use auto_join + [\#3136](https://github.com/matrix-org/matrix-react-sdk/pull/3136) + * Improve API and interactivity of new tooltip + [\#3137](https://github.com/matrix-org/matrix-react-sdk/pull/3137) + * Use feature flag for displaying edits as well + [\#3132](https://github.com/matrix-org/matrix-react-sdk/pull/3132) + * Add interactive tooltip style + [\#3131](https://github.com/matrix-org/matrix-react-sdk/pull/3131) + * Remove redundant extra chevrons from ContextualMenu + [\#3129](https://github.com/matrix-org/matrix-react-sdk/pull/3129) + * Editor caret improvements + [\#3126](https://github.com/matrix-org/matrix-react-sdk/pull/3126) + * Disable left/right arrow navigating completions for now + [\#3130](https://github.com/matrix-org/matrix-react-sdk/pull/3130) + * Take list nesting into account for indenting + [\#3128](https://github.com/matrix-org/matrix-react-sdk/pull/3128) + * Add file size to UploadConfirmDialog + [\#3127](https://github.com/matrix-org/matrix-react-sdk/pull/3127) + * Consider cancelled verifications when mounting IncomingSasDialog + [\#3123](https://github.com/matrix-org/matrix-react-sdk/pull/3123) + * Make the verification cancelled dialog say OK instead of Cancel + [\#3124](https://github.com/matrix-org/matrix-react-sdk/pull/3124) + * Update from Weblate + [\#3125](https://github.com/matrix-org/matrix-react-sdk/pull/3125) + * Remove unused ContextualMenu features + [\#3122](https://github.com/matrix-org/matrix-react-sdk/pull/3122) + * Fix casing of TooltipButton + [\#3119](https://github.com/matrix-org/matrix-react-sdk/pull/3119) + * De-duplicate notif badge code + [\#3120](https://github.com/matrix-org/matrix-react-sdk/pull/3120) + * Fix favicon/title badge count + [\#3121](https://github.com/matrix-org/matrix-react-sdk/pull/3121) + * Switch ugly password boxes to Field or styled input + [\#3071](https://github.com/matrix-org/matrix-react-sdk/pull/3071) + * Restore warning for if you're already logged in + [\#3118](https://github.com/matrix-org/matrix-react-sdk/pull/3118) + * Provide default name if device label is missing + [\#3113](https://github.com/matrix-org/matrix-react-sdk/pull/3113) + * Support @room pills while editing + [\#3108](https://github.com/matrix-org/matrix-react-sdk/pull/3108) + Changes in [1.2.2](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v1.2.2) (2019-06-19) =================================================================================================== [Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v1.2.2-rc.2...v1.2.2) From a36c520362461c51406629d0e430d68a31ac54d8 Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Wed, 3 Jul 2019 16:56:10 +0100 Subject: [PATCH 06/31] v1.3.0-rc.1 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 6e870d3f16..74ce948653 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-react-sdk", - "version": "1.2.2", + "version": "1.3.0-rc.1", "description": "SDK for matrix.org using React", "author": "matrix.org", "repository": { From 375976575bd0c94b03a6da60ab95785f43211fb6 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 4 Jul 2019 11:07:22 +0200 Subject: [PATCH 07/31] add redact button --- .../views/dialogs/_MessageEditHistoryDialog.scss | 5 +++++ res/css/views/messages/_MessageActionBar.scss | 7 ++++++- src/components/views/messages/EditHistoryMessage.js | 13 +++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/res/css/views/dialogs/_MessageEditHistoryDialog.scss b/res/css/views/dialogs/_MessageEditHistoryDialog.scss index 951b863e6a..38188974ac 100644 --- a/res/css/views/dialogs/_MessageEditHistoryDialog.scss +++ b/res/css/views/dialogs/_MessageEditHistoryDialog.scss @@ -42,5 +42,10 @@ limitations under the License. .mx_EventTile_line, .mx_EventTile_content { margin-right: 0px; } + + .mx_MessageActionBar .mx_AccessibleButton { + font-size: 10px; + padding: 0 8px; + } } diff --git a/res/css/views/messages/_MessageActionBar.scss b/res/css/views/messages/_MessageActionBar.scss index 7ac0e95e81..b7ba2ef27d 100644 --- a/res/css/views/messages/_MessageActionBar.scss +++ b/res/css/views/messages/_MessageActionBar.scss @@ -30,9 +30,9 @@ limitations under the License. z-index: 1; > * { + white-space: nowrap; display: inline-block; position: relative; - width: 27px; border: 1px solid $message-action-bar-border-color; margin-left: -1px; @@ -55,6 +55,11 @@ limitations under the License. } } + +.mx_MessageActionBar_maskButton { + width: 27px; +} + .mx_MessageActionBar_maskButton::after { content: ''; position: absolute; diff --git a/src/components/views/messages/EditHistoryMessage.js b/src/components/views/messages/EditHistoryMessage.js index fef9c362c6..5b00257e87 100644 --- a/src/components/views/messages/EditHistoryMessage.js +++ b/src/components/views/messages/EditHistoryMessage.js @@ -20,6 +20,8 @@ import * as HtmlUtils from '../../../HtmlUtils'; import {formatTime} from '../../../DateUtils'; import {MatrixEvent} from 'matrix-js-sdk'; import {pillifyLinks} from '../../../utils/pillify'; +import { _t } from '../../../languageHandler'; +import sdk from '../../../index'; export default class EditHistoryMessage extends React.PureComponent { static propTypes = { @@ -27,6 +29,9 @@ export default class EditHistoryMessage extends React.PureComponent { mxEvent: PropTypes.instanceOf(MatrixEvent).isRequired, }; + _onRedactClick = async () => { + }; + componentDidMount() { pillifyLinks(this.refs.content.children, this.props.mxEvent); } @@ -35,6 +40,13 @@ export default class EditHistoryMessage extends React.PureComponent { pillifyLinks(this.refs.content.children, this.props.mxEvent); } + _renderActionBar() { + const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); + return (
    + {_t("Remove")} +
    ); + } + render() { const {mxEvent} = this.props; const originalContent = mxEvent.getOriginalContent(); @@ -55,6 +67,7 @@ export default class EditHistoryMessage extends React.PureComponent {
    {timestamp} { contentContainer } + { this._renderActionBar() }
    ; } From 8468f7cdc39e5f970ae6978849d2e3e7d6afe70c Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Thu, 4 Jul 2019 15:39:36 +0200 Subject: [PATCH 08/31] support redactions in edit history dialog --- .../dialogs/ConfirmAndWaitRedactDialog.js | 87 +++++++++++++++++++ .../views/messages/EditHistoryMessage.js | 50 ++++++++++- src/i18n/strings/en_EN.json | 3 +- 3 files changed, 135 insertions(+), 5 deletions(-) create mode 100644 src/components/views/dialogs/ConfirmAndWaitRedactDialog.js diff --git a/src/components/views/dialogs/ConfirmAndWaitRedactDialog.js b/src/components/views/dialogs/ConfirmAndWaitRedactDialog.js new file mode 100644 index 0000000000..5fd5129550 --- /dev/null +++ b/src/components/views/dialogs/ConfirmAndWaitRedactDialog.js @@ -0,0 +1,87 @@ +/* +Copyright 2019 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 React from 'react'; +import sdk from '../../../index'; +import { _t } from '../../../languageHandler'; + +/* + * A dialog for confirming a redaction. + * Also shows a spinner (and possible error) while the redaction is ongoing, + * and only closes the dialog when the redaction is done or failed. + * + * This is done to prevent the edit history dialog racing with the redaction: + * if this dialog closes and the MessageEditHistoryDialog is shown again, + * it will fetch the relations again, which will race with the ongoing /redact request. + * which will cause the edit to appear unredacted. + * + * To avoid this, we keep the dialog open as long as /redact is in progress. + */ +export default class ConfirmAndWaitRedactDialog extends React.PureComponent { + constructor(props) { + super(props); + this.state = { + isRedacting: false, + redactionErrorCode: null, + }; + } + + onParentFinished = async (proceed) => { + if (proceed) { + this.setState({isRedacting: true}); + try { + await this.props.redact(); + this.props.onFinished(true); + } catch (error) { + const code = error.errcode || error.statusCode; + if (typeof code !== "undefined") { + this.setState({redactionErrorCode: code}); + } else { + this.props.onFinished(true); + } + } + } else { + this.props.onFinished(false); + } + }; + + render() { + if (this.state.isRedacting) { + if (this.state.redactionErrorCode) { + const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); + const code = this.state.redactionErrorCode; + return ( + + ); + } else { + const BaseDialog = sdk.getComponent("dialogs.BaseDialog"); + const Spinner = sdk.getComponent('elements.Spinner'); + return ( + ); + } + } else { + const ConfirmRedactDialog = sdk.getComponent("dialogs.ConfirmRedactDialog"); + return (); + } + } +} diff --git a/src/components/views/messages/EditHistoryMessage.js b/src/components/views/messages/EditHistoryMessage.js index 5b00257e87..67ab2f0e2c 100644 --- a/src/components/views/messages/EditHistoryMessage.js +++ b/src/components/views/messages/EditHistoryMessage.js @@ -22,6 +22,9 @@ import {MatrixEvent} from 'matrix-js-sdk'; import {pillifyLinks} from '../../../utils/pillify'; import { _t } from '../../../languageHandler'; import sdk from '../../../index'; +import MatrixClientPeg from '../../../MatrixClientPeg'; +import Modal from '../../../Modal'; +import classNames from 'classnames'; export default class EditHistoryMessage extends React.PureComponent { static propTypes = { @@ -29,19 +32,46 @@ export default class EditHistoryMessage extends React.PureComponent { mxEvent: PropTypes.instanceOf(MatrixEvent).isRequired, }; + constructor(props) { + super(props); + const cli = MatrixClientPeg.get(); + const {userId} = cli.credentials; + const event = this.props.mxEvent; + const room = cli.getRoom(event.getRoomId()); + const canRedact = room.currentState.maySendRedactionForEvent(event, userId); + this.state = {canRedact}; + } + _onRedactClick = async () => { + const event = this.props.mxEvent; + const cli = MatrixClientPeg.get(); + const ConfirmAndWaitRedactDialog = sdk.getComponent("dialogs.ConfirmAndWaitRedactDialog"); + + Modal.createTrackedDialog('Confirm Redact Dialog from edit history', '', ConfirmAndWaitRedactDialog, { + redact: () => cli.redactEvent(event.getRoomId(), event.getId()), + }, 'mx_Dialog_confirmredact'); }; + pillifyLinks() { + // not present for redacted events + if (this.refs.content) { + pillifyLinks(this.refs.content.children, this.props.mxEvent); + } + } + componentDidMount() { - pillifyLinks(this.refs.content.children, this.props.mxEvent); + this.pillifyLinks(); } componentDidUpdate() { - pillifyLinks(this.refs.content.children, this.props.mxEvent); + this.pillifyLinks(); } _renderActionBar() { const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); + if (this.props.mxEvent.isRedacted()) { + return null; + } return (
    {_t("Remove")}
    ); @@ -52,8 +82,12 @@ export default class EditHistoryMessage extends React.PureComponent { const originalContent = mxEvent.getOriginalContent(); const content = originalContent["m.new_content"] || originalContent; const contentElements = HtmlUtils.bodyToHtml(content); + const isRedacted = this.props.mxEvent.isRedacted(); let contentContainer; - if (mxEvent.getContent().msgtype === "m.emote") { + if (isRedacted) { + const UnknownBody = sdk.getComponent('messages.UnknownBody'); + contentContainer = (); + } else if (mxEvent.getContent().msgtype === "m.emote") { const name = mxEvent.sender ? mxEvent.sender.name : mxEvent.getSender(); contentContainer = (
    { name } @@ -63,7 +97,15 @@ export default class EditHistoryMessage extends React.PureComponent { contentContainer = (
    {contentElements}
    ); } const timestamp = formatTime(new Date(mxEvent.getTs()), this.props.isTwelveHour); - return
  • + const sendStatus = mxEvent.getAssociatedStatus(); + const isSending = (['sending', 'queued', 'encrypting'].indexOf(sendStatus) !== -1); + const classes = classNames({ + "mx_EventTile": true, + "mx_EventTile_redacted": isRedacted, + "mx_EventTile_sending": isSending, + "mx_EventTile_notSent": sendStatus === 'not_sent', + }); + return
  • {timestamp} { contentContainer } diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 0f1b6ebbc1..acabe191b4 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -93,6 +93,7 @@ "Failed to add the following rooms to %(groupId)s:": "Failed to add the following rooms to %(groupId)s:", "Unnamed Room": "Unnamed Room", "Error": "Error", + "You cannot delete this message. (%(code)s)": "You cannot delete this message. (%(code)s)", "Unable to load! Check your network connectivity and try again.": "Unable to load! Check your network connectivity and try again.", "Dismiss": "Dismiss", "Riot does not have permission to send you notifications - please check your browser settings": "Riot does not have permission to send you notifications - please check your browser settings", @@ -1125,6 +1126,7 @@ "Start chatting": "Start chatting", "Click on the button below to start chatting!": "Click on the button below to start chatting!", "Start Chatting": "Start Chatting", + "Removing…": "Removing…", "Confirm Removal": "Confirm Removal", "Are you sure you wish to remove (delete) this event? Note that if you delete a room name or topic change, it could undo the change.": "Are you sure you wish to remove (delete) this event? Note that if you delete a room name or topic change, it could undo the change.", "Community IDs cannot be empty.": "Community IDs cannot be empty.", @@ -1306,7 +1308,6 @@ "Reject invitation": "Reject invitation", "Are you sure you want to reject the invitation?": "Are you sure you want to reject the invitation?", "Unable to reject invite": "Unable to reject invite", - "You cannot delete this message. (%(code)s)": "You cannot delete this message. (%(code)s)", "Resend": "Resend", "Resend edit": "Resend edit", "Resend %(unsentCount)s reaction(s)": "Resend %(unsentCount)s reaction(s)", From 89d568ce9791d6a4d20529eb59ebd9d7caf0dba6 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 5 Jul 2019 08:36:16 +0100 Subject: [PATCH 09/31] Don't allow editing via up-arrow when Replying Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/views/rooms/MessageComposerInput.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/rooms/MessageComposerInput.js b/src/components/views/rooms/MessageComposerInput.js index 6feb9e264e..45a27c4253 100644 --- a/src/components/views/rooms/MessageComposerInput.js +++ b/src/components/views/rooms/MessageComposerInput.js @@ -1143,7 +1143,7 @@ export default class MessageComposerInput extends React.Component { const editingEnabled = SettingsStore.isFeatureEnabled("feature_message_editing"); const shouldSelectHistory = (editingEnabled && e.altKey) || !editingEnabled; - const shouldEditLastMessage = editingEnabled && !e.altKey && up; + const shouldEditLastMessage = editingEnabled && !e.altKey && up && !RoomViewStore.getQuotingEvent(); if (shouldSelectHistory) { // Try select composer history From 2182248d7c90907df23b74a6812aaad579b1ff41 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 5 Jul 2019 16:03:34 +0200 Subject: [PATCH 10/31] mark events from /relations as locally redacted if any pending redaction --- .../views/dialogs/MessageEditHistoryDialog.js | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/components/views/dialogs/MessageEditHistoryDialog.js b/src/components/views/dialogs/MessageEditHistoryDialog.js index b30891488b..53dd6b2a1b 100644 --- a/src/components/views/dialogs/MessageEditHistoryDialog.js +++ b/src/components/views/dialogs/MessageEditHistoryDialog.js @@ -46,12 +46,13 @@ export default class MessageEditHistoryDialog extends React.PureComponent { const opts = {from: this.state.nextBatch}; const roomId = this.props.mxEvent.getRoomId(); const eventId = this.props.mxEvent.getId(); + const client = MatrixClientPeg.get(); let result; let resolve; let reject; const promise = new Promise((_resolve, _reject) => {resolve = _resolve; reject = _reject;}); try { - result = await MatrixClientPeg.get().relations( + result = await client.relations( roomId, eventId, "m.replace", "m.room.message", opts); } catch (error) { // log if the server returned an error @@ -61,8 +62,11 @@ export default class MessageEditHistoryDialog extends React.PureComponent { this.setState({error}, () => reject(error)); return promise; } + + const newEvents = result.events; + this._locallyRedactEventsIfNeeded(newEvents); this.setState({ - events: this.state.events.concat(result.events), + events: this.state.events.concat(newEvents), nextBatch: result.nextBatch, isLoading: false, }, () => { @@ -72,6 +76,21 @@ export default class MessageEditHistoryDialog extends React.PureComponent { return promise; } + _locallyRedactEventsIfNeeded(newEvents) { + const roomId = this.props.mxEvent.getRoomId(); + const client = MatrixClientPeg.get(); + const room = client.getRoom(roomId); + const pendingEvents = room.getPendingEvents(); + for (const e of newEvents) { + const pendingRedaction = pendingEvents.find(pe => { + return pe.getType() === "m.room.redaction" && pe.getAssociatedId() === e.getId(); + }); + if (pendingRedaction) { + e.markLocallyRedacted(pendingRedaction); + } + } + } + componentDidMount() { this.loadMoreEdits(); } From 0aa1252d014d20fb73b1e961428a93097c38894e Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 5 Jul 2019 16:04:34 +0200 Subject: [PATCH 11/31] monitor associated send status for edit history events to update local echo if needed --- .../views/messages/EditHistoryMessage.js | 28 ++++++++++++++----- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/components/views/messages/EditHistoryMessage.js b/src/components/views/messages/EditHistoryMessage.js index 67ab2f0e2c..f2a721b52d 100644 --- a/src/components/views/messages/EditHistoryMessage.js +++ b/src/components/views/messages/EditHistoryMessage.js @@ -38,10 +38,17 @@ export default class EditHistoryMessage extends React.PureComponent { const {userId} = cli.credentials; const event = this.props.mxEvent; const room = cli.getRoom(event.getRoomId()); + if (event.localRedactionEvent()) { + event.localRedactionEvent().on("status", this._onAssociatedStatusChanged); + } const canRedact = room.currentState.maySendRedactionForEvent(event, userId); - this.state = {canRedact}; + this.state = {canRedact, sendStatus: event.getAssociatedStatus()}; } + _onAssociatedStatusChanged = () => { + this.setState({sendStatus: this.props.mxEvent.getAssociatedStatus()}); + }; + _onRedactClick = async () => { const event = this.props.mxEvent; const cli = MatrixClientPeg.get(); @@ -63,15 +70,24 @@ export default class EditHistoryMessage extends React.PureComponent { this.pillifyLinks(); } + componentWillUnmount() { + const event = this.props.mxEvent; + if (event.localRedactionEvent()) { + event.localRedactionEvent().off("status", this._onAssociatedStatusChanged); + } + } + componentDidUpdate() { this.pillifyLinks(); } _renderActionBar() { const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); + // hide the button when already redacted if (this.props.mxEvent.isRedacted()) { return null; } + // disabled remove button when not allowed return (
    {_t("Remove")}
    ); @@ -82,9 +98,8 @@ export default class EditHistoryMessage extends React.PureComponent { const originalContent = mxEvent.getOriginalContent(); const content = originalContent["m.new_content"] || originalContent; const contentElements = HtmlUtils.bodyToHtml(content); - const isRedacted = this.props.mxEvent.isRedacted(); let contentContainer; - if (isRedacted) { + if (mxEvent.isRedacted()) { const UnknownBody = sdk.getComponent('messages.UnknownBody'); contentContainer = (); } else if (mxEvent.getContent().msgtype === "m.emote") { @@ -97,13 +112,12 @@ export default class EditHistoryMessage extends React.PureComponent { contentContainer = (
    {contentElements}
    ); } const timestamp = formatTime(new Date(mxEvent.getTs()), this.props.isTwelveHour); - const sendStatus = mxEvent.getAssociatedStatus(); - const isSending = (['sending', 'queued', 'encrypting'].indexOf(sendStatus) !== -1); + const isSending = (['sending', 'queued', 'encrypting'].indexOf(this.state.sendStatus) !== -1); const classes = classNames({ "mx_EventTile": true, - "mx_EventTile_redacted": isRedacted, + "mx_EventTile_redacted": mxEvent.isRedacted(), "mx_EventTile_sending": isSending, - "mx_EventTile_notSent": sendStatus === 'not_sent', + "mx_EventTile_notSent": this.state.sendStatus === 'not_sent', }); return
  • From f4a8314c4f6f51fe3b1f56030e6664cfb50844d1 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 5 Jul 2019 16:05:40 +0200 Subject: [PATCH 12/31] make dom tree similar to eventtile so red lozenge style applies --- src/components/views/messages/EditHistoryMessage.js | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/components/views/messages/EditHistoryMessage.js b/src/components/views/messages/EditHistoryMessage.js index f2a721b52d..8069a8e290 100644 --- a/src/components/views/messages/EditHistoryMessage.js +++ b/src/components/views/messages/EditHistoryMessage.js @@ -119,11 +119,13 @@ export default class EditHistoryMessage extends React.PureComponent { "mx_EventTile_sending": isSending, "mx_EventTile_notSent": this.state.sendStatus === 'not_sent', }); - return
  • -
    - {timestamp} - { contentContainer } - { this._renderActionBar() } + return
  • +
    +
    + {timestamp} + { contentContainer } + { this._renderActionBar() } +
  • ; } From 70334b69ec2cb7510d3a6433142578c0c9c5b688 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Fri, 5 Jul 2019 16:11:15 +0200 Subject: [PATCH 13/31] implement view source for edits --- .../views/messages/EditHistoryMessage.js | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/src/components/views/messages/EditHistoryMessage.js b/src/components/views/messages/EditHistoryMessage.js index 8069a8e290..9d1c4bd784 100644 --- a/src/components/views/messages/EditHistoryMessage.js +++ b/src/components/views/messages/EditHistoryMessage.js @@ -59,6 +59,15 @@ export default class EditHistoryMessage extends React.PureComponent { }, 'mx_Dialog_confirmredact'); }; + _onViewSourceClick = () => { + const ViewSource = sdk.getComponent('structures.ViewSource'); + Modal.createTrackedDialog('View Event Source', '', ViewSource, { + roomId: this.props.mxEvent.getRoomId(), + eventId: this.props.mxEvent.getId(), + content: this.props.mxEvent.event, + }, 'mx_Dialog_viewsource'); + }; + pillifyLinks() { // not present for redacted events if (this.refs.content) { @@ -84,12 +93,19 @@ export default class EditHistoryMessage extends React.PureComponent { _renderActionBar() { const AccessibleButton = sdk.getComponent('elements.AccessibleButton'); // hide the button when already redacted - if (this.props.mxEvent.isRedacted()) { - return null; + let redactButton; + if (!this.props.mxEvent.isRedacted()) { + redactButton = ( + {_t("Remove")} + ); } + const viewSourceButton = ( + {_t("View Source")} + ); // disabled remove button when not allowed return (
    - {_t("Remove")} + {redactButton} + {viewSourceButton}
    ); } From 55b4ef2169e8640417084deff0197f8ede95e3ea Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 5 Jul 2019 13:52:14 -0600 Subject: [PATCH 14/31] Change soft logout rehydrate text if there's pending key backups Fixes https://github.com/vector-im/riot-web/issues/10263 Requires https://github.com/matrix-org/matrix-js-sdk/pull/982 --- src/components/structures/auth/SoftLogout.js | 16 +++++++++++++++- src/i18n/strings/en_EN.json | 2 ++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/components/structures/auth/SoftLogout.js b/src/components/structures/auth/SoftLogout.js index e01be3c1f0..475ed1108a 100644 --- a/src/components/structures/auth/SoftLogout.js +++ b/src/components/structures/auth/SoftLogout.js @@ -64,6 +64,7 @@ export default class SoftLogout extends React.Component { userId, displayName, loginView: LOGIN_VIEW.LOADING, + keyBackupNeeded: true, // assume we do while we figure it out (see componentWillMount) busy: false, password: "", @@ -73,6 +74,12 @@ export default class SoftLogout extends React.Component { this._initLogin(); } + componentWillMount(): void { + MatrixClientPeg.get().flagAllGroupSessionsForBackup().then(remaining => { + this.setState({keyBackupNeeded: remaining > 0}); + }); + } + onClearAll = () => { const ConfirmWipeDeviceDialog = sdk.getComponent('dialogs.ConfirmWipeDeviceDialog'); Modal.createTrackedDialog('Clear Data', 'Soft Logout', ConfirmWipeDeviceDialog, { @@ -158,9 +165,16 @@ export default class SoftLogout extends React.Component { error = {this.state.errorText}; } + let introText = _t("Enter your password to sign in and regain access to your account."); + if (this.state.keyBackupNeeded) { + introText = _t( + "Regain access your account and recover encryption keys stored on this device. " + + "Without them, you won’t be able to read all of your secure messages on any device."); + } + return ( -

    {_t("Enter your password to sign in and regain access to your account.")}

    +

    {introText}

    {error} log in to your new account.": "You can now close this window or log in to your new account.", "Registration Successful": "Registration Successful", "Create your account": "Create your account", + "Failed to re-authenticate due to a homeserver problem": "Failed to re-authenticate due to a homeserver problem", "Failed to re-authenticate": "Failed to re-authenticate", "Enter your password to sign in and regain access to your account.": "Enter your password to sign in and regain access to your account.", + "Regain access your account and recover encryption keys stored on this device. Without them, you won’t be able to read all of your secure messages on any device.": "Regain access your account and recover encryption keys stored on this device. Without them, you won’t be able to read all of your secure messages on any device.", "Forgotten your password?": "Forgotten your password?", "Cannot re-authenticate with your account. Please contact your homeserver admin for more information.": "Cannot re-authenticate with your account. Please contact your homeserver admin for more information.", "You're signed out": "You're signed out", From 1f1a5b2aac607a6d9c61c2b2890ce9c36b86ca77 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Fri, 5 Jul 2019 14:35:21 -0600 Subject: [PATCH 15/31] Fix React crash when using a non-default homeserver on soft logout The function used exists on the peg, not the client. This commit also fixes the name of the function in a backwards compatible way. --- src/MatrixClientPeg.js | 9 ++++++++- src/components/structures/auth/SoftLogout.js | 2 +- src/components/views/directory/NetworkDropdown.js | 8 ++++---- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/MatrixClientPeg.js b/src/MatrixClientPeg.js index 07499a3a87..a994725f56 100644 --- a/src/MatrixClientPeg.js +++ b/src/MatrixClientPeg.js @@ -193,7 +193,7 @@ class MatrixClientPeg { * Throws an error if unable to deduce the homeserver name * (eg. if the user is not logged in) */ - getHomeServerName() { + getHomeserverName() { const matches = /^@.+:(.+)$/.exec(this.matrixClient.credentials.userId); if (matches === null || matches.length < 1) { throw new Error("Failed to derive homeserver name from user ID!"); @@ -201,6 +201,13 @@ class MatrixClientPeg { return matches[1]; } + /** + * @deprecated Use getHomeserverName() instead (correct spelling) + */ + getHomeServerName() { + return this.getHomeserverName(); + } + _createClient(creds: MatrixClientCreds) { const aggregateRelations = SettingsStore.isFeatureEnabled("feature_reactions"); const enableEdits = SettingsStore.isFeatureEnabled("feature_message_editing"); diff --git a/src/components/structures/auth/SoftLogout.js b/src/components/structures/auth/SoftLogout.js index 85654d512a..9ecd7a3bbd 100644 --- a/src/components/structures/auth/SoftLogout.js +++ b/src/components/structures/auth/SoftLogout.js @@ -37,7 +37,7 @@ export default class SoftLogout extends React.Component { const hsUrl = MatrixClientPeg.get().getHomeserverUrl(); const domainName = hsUrl === defaultServerConfig.hsUrl ? defaultServerConfig.hsName - : MatrixClientPeg.get().getHomeServerName(); + : MatrixClientPeg.getHomeserverName(); const userId = MatrixClientPeg.get().getUserId(); const user = MatrixClientPeg.get().getUser(userId); diff --git a/src/components/views/directory/NetworkDropdown.js b/src/components/views/directory/NetworkDropdown.js index 360102490c..f30c02ad2c 100644 --- a/src/components/views/directory/NetworkDropdown.js +++ b/src/components/views/directory/NetworkDropdown.js @@ -37,7 +37,7 @@ export default class NetworkDropdown extends React.Component { this.inputTextBox = null; - const server = MatrixClientPeg.getHomeServerName(); + const server = MatrixClientPeg.getHomeserverName(); this.state = { expanded: false, selectedServer: server, @@ -138,8 +138,8 @@ export default class NetworkDropdown extends React.Component { servers = servers.concat(roomDirectory.servers); } - if (!servers.includes(MatrixClientPeg.getHomeServerName())) { - servers.unshift(MatrixClientPeg.getHomeServerName()); + if (!servers.includes(MatrixClientPeg.getHomeserverName())) { + servers.unshift(MatrixClientPeg.getHomeserverName()); } // For our own HS, we can use the instance_ids given in the third party protocols @@ -148,7 +148,7 @@ export default class NetworkDropdown extends React.Component { // we can only show the default room list. for (const server of servers) { options.push(this._makeMenuOption(server, null, true)); - if (server === MatrixClientPeg.getHomeServerName()) { + if (server === MatrixClientPeg.getHomeserverName()) { options.push(this._makeMenuOption(server, null, false)); if (this.props.protocols) { for (const proto of Object.keys(this.props.protocols)) { From 6b9c6a31f058a9af87f0c091ef54f1268d256e8f Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Sat, 6 Jul 2019 10:42:14 +0100 Subject: [PATCH 16/31] Don't show Remove button in ImageView if can't redact, delint ImageView Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- .eslintignore.errorfiles | 1 - src/components/views/elements/ImageView.js | 24 ++++++++++++++-------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/.eslintignore.errorfiles b/.eslintignore.errorfiles index 3b2e7bbb43..e7f6ee1f84 100644 --- a/.eslintignore.errorfiles +++ b/.eslintignore.errorfiles @@ -17,7 +17,6 @@ src/components/views/dialogs/SetPasswordDialog.js src/components/views/dialogs/UnknownDeviceDialog.js src/components/views/elements/AddressSelector.js src/components/views/elements/DirectorySearchBox.js -src/components/views/elements/ImageView.js src/components/views/elements/MemberEventListSummary.js src/components/views/elements/TintableSvg.js src/components/views/elements/UserSelector.js diff --git a/src/components/views/elements/ImageView.js b/src/components/views/elements/ImageView.js index 9a47bce553..c65de6b22e 100644 --- a/src/components/views/elements/ImageView.js +++ b/src/components/views/elements/ImageView.js @@ -1,5 +1,6 @@ /* Copyright 2015, 2016 OpenMarket Ltd +Copyright 2019 Michael Telatynski <7t3chguy@gmail.com> Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -60,7 +61,7 @@ export default class ImageView extends React.Component { } onKeyDown = (ev) => { - if (ev.keyCode == 27) { // escape + if (ev.keyCode === 27) { // escape ev.stopPropagation(); ev.preventDefault(); this.props.onFinished(); @@ -72,7 +73,6 @@ export default class ImageView extends React.Component { Modal.createTrackedDialog('Confirm Redact Dialog', 'Image View', ConfirmRedactDialog, { onFinished: (proceed) => { if (!proceed) return; - const self = this; MatrixClientPeg.get().redactEvent( this.props.mxEvent.getRoomId(), this.props.mxEvent.getId(), ).catch(function(e) { @@ -153,32 +153,38 @@ export default class ImageView extends React.Component { size = filesize(this.props.fileSize); } - let size_res; + let sizeRes; if (size && res) { - size_res = size + ", " + res; + sizeRes = size + ", " + res; } else { - size_res = size || res; + sizeRes = size || res; } + let mayRedact = false; const showEventMeta = !!this.props.mxEvent; let eventMeta; if (showEventMeta) { // Figure out the sender, defaulting to mxid let sender = this.props.mxEvent.getSender(); - const room = MatrixClientPeg.get().getRoom(this.props.mxEvent.getRoomId()); + const cli = MatrixClientPeg.get(); + const room = cli.getRoom(this.props.mxEvent.getRoomId()); if (room) { + mayRedact = room.currentState.maySendRedactionForEvent(this.props.mxEvent, cli.credentials.userId); const member = room.getMember(sender); if (member) sender = member.name; } eventMeta = (
    - { _t('Uploaded on %(date)s by %(user)s', {date: formatDate(new Date(this.props.mxEvent.getTs())), user: sender}) } + { _t('Uploaded on %(date)s by %(user)s', { + date: formatDate(new Date(this.props.mxEvent.getTs())), + user: sender, + }) }
    ); } let eventRedact; - if (showEventMeta) { + if (mayRedact) { eventRedact = (
    { _t('Remove') }
    ); @@ -213,7 +219,7 @@ export default class ImageView extends React.Component {
    { _t('Download this file') }
    - { size_res } + { sizeRes }
    { eventRedact } From 89ece266c6565deeb000813888c269f18c2d8b41 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Sat, 6 Jul 2019 11:15:10 +0100 Subject: [PATCH 17/31] Make id used in EditableItemList unique, namespace mx_EditableItemList_* Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/views/elements/EditableItemList.js | 7 +++---- src/components/views/room_settings/AliasSettings.js | 1 + src/components/views/room_settings/RelatedGroupSettings.js | 1 + 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/components/views/elements/EditableItemList.js b/src/components/views/elements/EditableItemList.js index ab0fe6e96a..f4c1325377 100644 --- a/src/components/views/elements/EditableItemList.js +++ b/src/components/views/elements/EditableItemList.js @@ -88,6 +88,7 @@ export class EditableItem extends React.Component { export default class EditableItemList extends React.Component { static propTypes = { + id: PropTypes.string.isRequired, items: PropTypes.arrayOf(PropTypes.string).isRequired, itemsLabel: PropTypes.string, noItemsLabel: PropTypes.string, @@ -121,10 +122,8 @@ export default class EditableItemList extends React.Component { return ( - + {_t("Add")} diff --git a/src/components/views/room_settings/AliasSettings.js b/src/components/views/room_settings/AliasSettings.js index df427171f1..a4f18faa4e 100644 --- a/src/components/views/room_settings/AliasSettings.js +++ b/src/components/views/room_settings/AliasSettings.js @@ -234,6 +234,7 @@ export default class AliasSettings extends React.Component {
    {canonicalAliasSection} Date: Sat, 6 Jul 2019 11:16:01 +0100 Subject: [PATCH 18/31] make things a tad saner Signed-off-by: Michael Telatynski <7t3chguy@gmail.com> --- src/components/views/elements/EditableItemList.js | 2 +- src/components/views/room_settings/AliasSettings.js | 2 +- src/components/views/room_settings/RelatedGroupSettings.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/views/elements/EditableItemList.js b/src/components/views/elements/EditableItemList.js index f4c1325377..a9513cfe2f 100644 --- a/src/components/views/elements/EditableItemList.js +++ b/src/components/views/elements/EditableItemList.js @@ -122,7 +122,7 @@ export default class EditableItemList extends React.Component { return ( - {_t("Add")} diff --git a/src/components/views/room_settings/AliasSettings.js b/src/components/views/room_settings/AliasSettings.js index a4f18faa4e..daf5c6edc2 100644 --- a/src/components/views/room_settings/AliasSettings.js +++ b/src/components/views/room_settings/AliasSettings.js @@ -234,7 +234,7 @@ export default class AliasSettings extends React.Component {
    {canonicalAliasSection} Date: Mon, 8 Jul 2019 10:12:04 +0200 Subject: [PATCH 19/31] set analyticsInfo for dialogs --- src/components/views/messages/EditHistoryMessage.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/views/messages/EditHistoryMessage.js b/src/components/views/messages/EditHistoryMessage.js index 9d1c4bd784..c873ebbcb2 100644 --- a/src/components/views/messages/EditHistoryMessage.js +++ b/src/components/views/messages/EditHistoryMessage.js @@ -54,14 +54,14 @@ export default class EditHistoryMessage extends React.PureComponent { const cli = MatrixClientPeg.get(); const ConfirmAndWaitRedactDialog = sdk.getComponent("dialogs.ConfirmAndWaitRedactDialog"); - Modal.createTrackedDialog('Confirm Redact Dialog from edit history', '', ConfirmAndWaitRedactDialog, { + Modal.createTrackedDialog('Confirm Redact Dialog', 'Edit history', ConfirmAndWaitRedactDialog, { redact: () => cli.redactEvent(event.getRoomId(), event.getId()), }, 'mx_Dialog_confirmredact'); }; _onViewSourceClick = () => { const ViewSource = sdk.getComponent('structures.ViewSource'); - Modal.createTrackedDialog('View Event Source', '', ViewSource, { + Modal.createTrackedDialog('View Event Source', 'Edit history', ViewSource, { roomId: this.props.mxEvent.getRoomId(), eventId: this.props.mxEvent.getId(), content: this.props.mxEvent.event, From 1af2ca6b36b32c2505a1ee429a134ac7c4145abf Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Mon, 8 Jul 2019 10:12:26 +0200 Subject: [PATCH 20/31] constistent jsx bracket and indent styling --- .../dialogs/ConfirmAndWaitRedactDialog.js | 13 +++-- .../views/messages/EditHistoryMessage.js | 56 +++++++++++-------- 2 files changed, 41 insertions(+), 28 deletions(-) diff --git a/src/components/views/dialogs/ConfirmAndWaitRedactDialog.js b/src/components/views/dialogs/ConfirmAndWaitRedactDialog.js index 5fd5129550..db00f445a8 100644 --- a/src/components/views/dialogs/ConfirmAndWaitRedactDialog.js +++ b/src/components/views/dialogs/ConfirmAndWaitRedactDialog.js @@ -73,15 +73,18 @@ export default class ConfirmAndWaitRedactDialog extends React.PureComponent { } else { const BaseDialog = sdk.getComponent("dialogs.BaseDialog"); const Spinner = sdk.getComponent('elements.Spinner'); - return ( + return ( + + + ); } } else { const ConfirmRedactDialog = sdk.getComponent("dialogs.ConfirmRedactDialog"); - return (); + return ; } } } diff --git a/src/components/views/messages/EditHistoryMessage.js b/src/components/views/messages/EditHistoryMessage.js index c873ebbcb2..797e010aae 100644 --- a/src/components/views/messages/EditHistoryMessage.js +++ b/src/components/views/messages/EditHistoryMessage.js @@ -95,18 +95,24 @@ export default class EditHistoryMessage extends React.PureComponent { // hide the button when already redacted let redactButton; if (!this.props.mxEvent.isRedacted()) { - redactButton = ( - {_t("Remove")} - ); + redactButton = ( + + {_t("Remove")} + + ); } - const viewSourceButton = ( + const viewSourceButton = ( + {_t("View Source")} - ); + + ); // disabled remove button when not allowed - return (
    - {redactButton} - {viewSourceButton} -
    ); + return ( +
    + {redactButton} + {viewSourceButton} +
    + ); } render() { @@ -117,15 +123,17 @@ export default class EditHistoryMessage extends React.PureComponent { let contentContainer; if (mxEvent.isRedacted()) { const UnknownBody = sdk.getComponent('messages.UnknownBody'); - contentContainer = (); + contentContainer = ; } else if (mxEvent.getContent().msgtype === "m.emote") { const name = mxEvent.sender ? mxEvent.sender.name : mxEvent.getSender(); - contentContainer = (
    *  - { name } -  {contentElements} -
    ); + contentContainer = ( +
    *  + { name } +  {contentElements} +
    + ); } else { - contentContainer = (
    {contentElements}
    ); + contentContainer =
    {contentElements}
    ; } const timestamp = formatTime(new Date(mxEvent.getTs()), this.props.isTwelveHour); const isSending = (['sending', 'queued', 'encrypting'].indexOf(this.state.sendStatus) !== -1); @@ -135,14 +143,16 @@ export default class EditHistoryMessage extends React.PureComponent { "mx_EventTile_sending": isSending, "mx_EventTile_notSent": this.state.sendStatus === 'not_sent', }); - return
  • -
    -
    - {timestamp} - { contentContainer } - { this._renderActionBar() } + return ( +
  • +
    +
    + {timestamp} + { contentContainer } + { this._renderActionBar() } +
    -
  • - ; + + ); } } From 33eba0e500e94e12dafa934ed2bd35ff54acb449 Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Mon, 8 Jul 2019 10:49:43 +0100 Subject: [PATCH 21/31] Upgrade to JS SDK 2.1.0 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 74ce948653..2220fd0553 100644 --- a/package.json +++ b/package.json @@ -81,7 +81,7 @@ "linkifyjs": "^2.1.6", "lodash": "^4.13.1", "lolex": "2.3.2", - "matrix-js-sdk": "2.1.0-rc.1", + "matrix-js-sdk": "2.1.0", "optimist": "^0.6.1", "pako": "^1.0.5", "png-chunks-extract": "^1.0.0", diff --git a/yarn.lock b/yarn.lock index 2d6c8169bc..09d3ae60d7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4877,10 +4877,10 @@ mathml-tag-names@^2.0.1: resolved "https://registry.yarnpkg.com/mathml-tag-names/-/mathml-tag-names-2.1.0.tgz#490b70e062ee24636536e3d9481e333733d00f2c" integrity sha512-3Zs9P/0zzwTob2pdgT0CHZuMbnSUSp8MB1bddfm+HDmnFWHGT4jvEZRf+2RuPoa+cjdn/z25SEt5gFTqdhvJAg== -matrix-js-sdk@2.1.0-rc.1: - version "2.1.0-rc.1" - resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-2.1.0-rc.1.tgz#0eff1224c6877538df2ccdd8e5b65892473f646f" - integrity sha512-YXybCKTdY8aHKJnr/zl8TR1iEIL890RLrD3Wc3YNWdbIt0ldnrdedreZYMmDhuSVFWbLwx1q8QDHwLZJvUGCdQ== +matrix-js-sdk@2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/matrix-js-sdk/-/matrix-js-sdk-2.1.0.tgz#a8192d700e4d96028cdb64f3453935292e76faaf" + integrity sha512-fVgqxp9rrcGhQ9cnU2WW3KJCOIn/WJu/G2tTgWEtzeDkUl22JXiB6iYfrJO7XF8nm8W5DbJVtxWRRnV8BvWatQ== dependencies: another-json "^0.2.0" babel-runtime "^6.26.0" From 6cafcf64088d459fd6be01fa51f84bded0881cca Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Mon, 8 Jul 2019 10:53:03 +0100 Subject: [PATCH 22/31] Prepare changelog for v1.3.0 --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 47e7c75d18..1fd5522d8d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +Changes in [1.3.0](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v1.3.0) (2019-07-08) +=================================================================================================== +[Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v1.3.0-rc.1...v1.3.0) + +No changes since rc.1 + Changes in [1.3.0-rc.1](https://github.com/matrix-org/matrix-react-sdk/releases/tag/v1.3.0-rc.1) (2019-07-03) ============================================================================================================= [Full Changelog](https://github.com/matrix-org/matrix-react-sdk/compare/v1.2.2...v1.3.0-rc.1) From 61e2d87152a99267518bd8143796a0445689d74c Mon Sep 17 00:00:00 2001 From: RiotRobot Date: Mon, 8 Jul 2019 10:53:03 +0100 Subject: [PATCH 23/31] v1.3.0 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 2220fd0553..68a1b13a1e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "matrix-react-sdk", - "version": "1.3.0-rc.1", + "version": "1.3.0", "description": "SDK for matrix.org using React", "author": "matrix.org", "repository": { From 888e4d1ec258f93f9fdcae94c56379a265b4cf7d Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Mon, 8 Jul 2019 15:25:44 +0200 Subject: [PATCH 24/31] preserve reply fallback when editing --- .../views/elements/MessageEditor.js | 138 ++++++++++++------ src/editor/serialize.js | 4 +- 2 files changed, 94 insertions(+), 48 deletions(-) diff --git a/src/components/views/elements/MessageEditor.js b/src/components/views/elements/MessageEditor.js index 0243ea737a..60e07bd951 100644 --- a/src/components/views/elements/MessageEditor.js +++ b/src/components/views/elements/MessageEditor.js @@ -33,6 +33,80 @@ import {MatrixClient} from 'matrix-js-sdk'; import classNames from 'classnames'; import {EventStatus} from 'matrix-js-sdk'; +function _isReply(mxEvent) { + const relatesTo = mxEvent.getContent()["m.relates_to"]; + const isReply = !!(relatesTo && relatesTo["m.in_reply_to"]); + return isReply; +} + +function getHtmlReplyFallback(mxEvent) { + const html = mxEvent.getContent().formatted_body; + if (!html) { + return ""; + } + const rootNode = new DOMParser().parseFromString(html, "text/html").body; + const mxReply = rootNode.querySelector("mx-reply"); + return (mxReply && mxReply.outerHTML) || ""; +} + +function getTextReplyFallback(mxEvent) { + const body = mxEvent.getContent().body; + const lines = body.split("\n").map(l => l.trim()); + if (lines.length > 2 && lines[0].startsWith("> ") && lines[1].length === 0) { + return `${lines[0]}\n\n`; + } + return ""; +} + +function _isEmote(model) { + const firstPart = model.parts[0]; + return firstPart && firstPart.type === "plain" && firstPart.text.startsWith("/me "); +} + +function createEditContent(model, editedEvent) { + const isEmote = _isEmote(model); + if (isEmote) { + // trim "/me " + model = model.clone(); + model.removeText({index: 0, offset: 0}, 4); + } + const isReply = _isReply(editedEvent); + let plainPrefix = ""; + let htmlPrefix = ""; + + if (isReply) { + plainPrefix = getTextReplyFallback(editedEvent); + htmlPrefix = getHtmlReplyFallback(editedEvent); + } + + const body = textSerialize(model); + + const newContent = { + "msgtype": isEmote ? "m.emote" : "m.text", + "body": plainPrefix + body, + }; + const contentBody = { + msgtype: newContent.msgtype, + body: `${plainPrefix} * ${body}`, + }; + + const formattedBody = htmlSerializeIfNeeded(model, /*forceHtml=*/ isReply); + if (formattedBody) { + newContent.format = "org.matrix.custom.html"; + newContent.formatted_body = htmlPrefix + formattedBody; + contentBody.format = newContent.format; + contentBody.formatted_body = `${htmlPrefix} * ${formattedBody}`; + } + + return Object.assign({ + "m.new_content": newContent, + "m.relates_to": { + "rel_type": "m.replace", + "event_id": editedEvent.getId(), + }, + }, contentBody); +} + export default class MessageEditor extends React.Component { static propTypes = { // the message event being edited @@ -53,7 +127,7 @@ export default class MessageEditor extends React.Component { }; this._editorRef = null; this._autocompleteRef = null; - this._hasModifications = false; + this._modifiedFlag = false; } _getRoom() { @@ -73,7 +147,7 @@ export default class MessageEditor extends React.Component { } _onInput = (event) => { - this._hasModifications = true; + this._modifiedFlag = true; const sel = document.getSelection(); const {caret, text} = getCaretOffsetAndText(this._editorRef, sel); this.model.update(text, event.inputType, caret); @@ -131,7 +205,7 @@ export default class MessageEditor extends React.Component { } else if (event.key === "Escape") { this._cancelEdit(); } else if (event.key === "ArrowUp") { - if (this._hasModifications || !this._isCaretAtStart()) { + if (this._modifiedFlag || !this._isCaretAtStart()) { return; } const previousEvent = findEditableEvent(this._getRoom(), false, this.props.editState.getEvent().getId()); @@ -140,7 +214,7 @@ export default class MessageEditor extends React.Component { event.preventDefault(); } } else if (event.key === "ArrowDown") { - if (this._hasModifications || !this._isCaretAtEnd()) { + if (this._modifiedFlag || !this._isCaretAtEnd()) { return; } const nextEvent = findEditableEvent(this._getRoom(), true, this.props.editState.getEvent().getId()); @@ -159,56 +233,28 @@ export default class MessageEditor extends React.Component { dis.dispatch({action: 'focus_composer'}); } - _isEmote() { - const firstPart = this.model.parts[0]; - return firstPart && firstPart.type === "plain" && firstPart.text.startsWith("/me "); - } - - _sendEdit = () => { - const isEmote = this._isEmote(); - let model = this.model; - if (isEmote) { - // trim "/me " - model = model.clone(); - model.removeText({index: 0, offset: 0}, 4); - } - const newContent = { - "msgtype": isEmote ? "m.emote" : "m.text", - "body": textSerialize(model), - }; - const contentBody = { - msgtype: newContent.msgtype, - body: ` * ${newContent.body}`, - }; - const formattedBody = htmlSerializeIfNeeded(model); - if (formattedBody) { - newContent.format = "org.matrix.custom.html"; - newContent.formatted_body = formattedBody; - contentBody.format = newContent.format; - contentBody.formatted_body = ` * ${newContent.formatted_body}`; - } - + _hasModifications(newContent) { // if nothing has changed then bail const oldContent = this.props.editState.getEvent().getContent(); - if (!this._hasModifications || + if (!this._modifiedFlag || (oldContent["msgtype"] === newContent["msgtype"] && oldContent["body"] === newContent["body"] && oldContent["format"] === newContent["format"] && oldContent["formatted_body"] === newContent["formatted_body"])) { - this._cancelEdit(); + return false; + } + return true; + } + + _sendEdit = () => { + const editedEvent = this.props.editState.getEvent(); + const editContent = createEditContent(this.model, editedEvent); + const newContent = editContent["m.new_content"]; + if (!this._hasModifications(newContent)) { return; } - - const content = Object.assign({ - "m.new_content": newContent, - "m.relates_to": { - "rel_type": "m.replace", - "event_id": this.props.editState.getEvent().getId(), - }, - }, contentBody); - - const roomId = this.props.editState.getEvent().getRoomId(); + const roomId = editedEvent.getRoomId(); this._cancelPreviousPendingEdit(); - this.context.matrixClient.sendMessage(roomId, content); + this.context.matrixClient.sendMessage(roomId, editContent); dis.dispatch({action: "edit_event", event: null}); dis.dispatch({action: 'focus_composer'}); diff --git a/src/editor/serialize.js b/src/editor/serialize.js index 876130074c..9790597b13 100644 --- a/src/editor/serialize.js +++ b/src/editor/serialize.js @@ -33,10 +33,10 @@ export function mdSerialize(model) { }, ""); } -export function htmlSerializeIfNeeded(model) { +export function htmlSerializeIfNeeded(model, forceHtml = false) { const md = mdSerialize(model); const parser = new Markdown(md); - if (!parser.isPlainText()) { + if (!parser.isPlainText() || forceHtml) { return parser.toHTML(); } } From e601037cd27e9bbb17d05639371b421eb5d4f25c Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Mon, 8 Jul 2019 15:32:38 +0200 Subject: [PATCH 25/31] don't show reply fallback in edit history --- src/components/views/messages/EditHistoryMessage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/views/messages/EditHistoryMessage.js b/src/components/views/messages/EditHistoryMessage.js index 797e010aae..44d98abc0a 100644 --- a/src/components/views/messages/EditHistoryMessage.js +++ b/src/components/views/messages/EditHistoryMessage.js @@ -119,7 +119,7 @@ export default class EditHistoryMessage extends React.PureComponent { const {mxEvent} = this.props; const originalContent = mxEvent.getOriginalContent(); const content = originalContent["m.new_content"] || originalContent; - const contentElements = HtmlUtils.bodyToHtml(content); + const contentElements = HtmlUtils.bodyToHtml(content, null, {stripReplyFallback: true}); let contentContainer; if (mxEvent.isRedacted()) { const UnknownBody = sdk.getComponent('messages.UnknownBody'); From f6e71b233592270ad775dd21886ca70b9e02ac97 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Mon, 8 Jul 2019 16:55:56 +0200 Subject: [PATCH 26/31] turn flag into options object --- src/components/views/elements/MessageEditor.js | 2 +- src/editor/serialize.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/views/elements/MessageEditor.js b/src/components/views/elements/MessageEditor.js index 60e07bd951..cf306d80bb 100644 --- a/src/components/views/elements/MessageEditor.js +++ b/src/components/views/elements/MessageEditor.js @@ -90,7 +90,7 @@ function createEditContent(model, editedEvent) { body: `${plainPrefix} * ${body}`, }; - const formattedBody = htmlSerializeIfNeeded(model, /*forceHtml=*/ isReply); + const formattedBody = htmlSerializeIfNeeded(model, {forceHTML: isReply}); if (formattedBody) { newContent.format = "org.matrix.custom.html"; newContent.formatted_body = htmlPrefix + formattedBody; diff --git a/src/editor/serialize.js b/src/editor/serialize.js index 9790597b13..37565b64a0 100644 --- a/src/editor/serialize.js +++ b/src/editor/serialize.js @@ -33,10 +33,10 @@ export function mdSerialize(model) { }, ""); } -export function htmlSerializeIfNeeded(model, forceHtml = false) { +export function htmlSerializeIfNeeded(model, {forceHTML = false}) { const md = mdSerialize(model); const parser = new Markdown(md); - if (!parser.isPlainText() || forceHtml) { + if (!parser.isPlainText() || forceHTML) { return parser.toHTML(); } } From c3383e93159159f818a2385164fb8b052a768fd4 Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 8 Jul 2019 11:51:22 -0600 Subject: [PATCH 27/31] Move _initLogin to componentDidMount --- src/components/structures/auth/SoftLogout.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/components/structures/auth/SoftLogout.js b/src/components/structures/auth/SoftLogout.js index e01be3c1f0..57deee7175 100644 --- a/src/components/structures/auth/SoftLogout.js +++ b/src/components/structures/auth/SoftLogout.js @@ -69,7 +69,9 @@ export default class SoftLogout extends React.Component { password: "", errorText: "", }; + } + componentDidMount(): void { this._initLogin(); } From d2ab0a5ca791061d53564601fa54c4976376332a Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 8 Jul 2019 11:53:26 -0600 Subject: [PATCH 28/31] Move key backup init to componentDidMount --- src/components/structures/auth/SoftLogout.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/components/structures/auth/SoftLogout.js b/src/components/structures/auth/SoftLogout.js index a6e89c1326..0c589c5bb1 100644 --- a/src/components/structures/auth/SoftLogout.js +++ b/src/components/structures/auth/SoftLogout.js @@ -74,9 +74,7 @@ export default class SoftLogout extends React.Component { componentDidMount(): void { this._initLogin(); - } - componentWillMount(): void { MatrixClientPeg.get().flagAllGroupSessionsForBackup().then(remaining => { this.setState({keyBackupNeeded: remaining > 0}); }); From ab63e8bd049a1923e45d893187109e59e56e965f Mon Sep 17 00:00:00 2001 From: Travis Ralston Date: Mon, 8 Jul 2019 11:55:00 -0600 Subject: [PATCH 29/31] Remove backwards compat function --- src/MatrixClientPeg.js | 7 ------- src/components/structures/RoomDirectory.js | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/src/MatrixClientPeg.js b/src/MatrixClientPeg.js index a994725f56..db3e542af9 100644 --- a/src/MatrixClientPeg.js +++ b/src/MatrixClientPeg.js @@ -201,13 +201,6 @@ class MatrixClientPeg { return matches[1]; } - /** - * @deprecated Use getHomeserverName() instead (correct spelling) - */ - getHomeServerName() { - return this.getHomeserverName(); - } - _createClient(creds: MatrixClientCreds) { const aggregateRelations = SettingsStore.isFeatureEnabled("feature_reactions"); const enableEdits = SettingsStore.isFeatureEnabled("feature_message_editing"); diff --git a/src/components/structures/RoomDirectory.js b/src/components/structures/RoomDirectory.js index a98afdce2a..eb78888741 100644 --- a/src/components/structures/RoomDirectory.js +++ b/src/components/structures/RoomDirectory.js @@ -145,7 +145,7 @@ module.exports = React.createClass({ // too. If it's changed, appending to the list will corrupt it. const my_next_batch = this.nextBatch; const opts = {limit: 20}; - if (my_server != MatrixClientPeg.getHomeServerName()) { + if (my_server != MatrixClientPeg.getHomeserverName()) { opts.server = my_server; } if (this.state.instanceId) { From 58d7ed02b7cc24030d2c8b7e4acb66ed8c8f7a66 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 9 Jul 2019 11:31:29 +0200 Subject: [PATCH 30/31] use method that also takes server aggregations into account for tooltip date --- src/components/views/messages/TextualBody.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/views/messages/TextualBody.js b/src/components/views/messages/TextualBody.js index 25316844df..8f95c9cf5c 100644 --- a/src/components/views/messages/TextualBody.js +++ b/src/components/views/messages/TextualBody.js @@ -364,11 +364,11 @@ module.exports = React.createClass({ let editedTooltip; if (this.state.editedMarkerHovered) { const Tooltip = sdk.getComponent('elements.Tooltip'); - const editEvent = this.props.mxEvent.replacingEvent(); - const date = editEvent && formatDate(editEvent.getDate()); + const date = this.props.mxEvent.replacingEventDate(); + const dateString = date && formatDate(date); editedTooltip = ; } return ( From f03187190eca9d2a30fec1d71cc3bb45cc572aa2 Mon Sep 17 00:00:00 2001 From: Bruno Windels Date: Tue, 9 Jul 2019 15:00:26 +0200 Subject: [PATCH 31/31] Don't try to call bodyToHtml with an empty content with the stripReply flag, this crashes. --- .../views/messages/EditHistoryMessage.js | 23 +++++++++++-------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/components/views/messages/EditHistoryMessage.js b/src/components/views/messages/EditHistoryMessage.js index 44d98abc0a..fe8d465698 100644 --- a/src/components/views/messages/EditHistoryMessage.js +++ b/src/components/views/messages/EditHistoryMessage.js @@ -119,22 +119,25 @@ export default class EditHistoryMessage extends React.PureComponent { const {mxEvent} = this.props; const originalContent = mxEvent.getOriginalContent(); const content = originalContent["m.new_content"] || originalContent; - const contentElements = HtmlUtils.bodyToHtml(content, null, {stripReplyFallback: true}); let contentContainer; if (mxEvent.isRedacted()) { const UnknownBody = sdk.getComponent('messages.UnknownBody'); contentContainer = ; - } else if (mxEvent.getContent().msgtype === "m.emote") { - const name = mxEvent.sender ? mxEvent.sender.name : mxEvent.getSender(); - contentContainer = ( -
    *  - { name } -  {contentElements} -
    - ); } else { - contentContainer =
    {contentElements}
    ; + const contentElements = HtmlUtils.bodyToHtml(content, null, {stripReplyFallback: true}); + if (mxEvent.getContent().msgtype === "m.emote") { + const name = mxEvent.sender ? mxEvent.sender.name : mxEvent.getSender(); + contentContainer = ( +
    *  + { name } +  {contentElements} +
    + ); + } else { + contentContainer =
    {contentElements}
    ; + } } + const timestamp = formatTime(new Date(mxEvent.getTs()), this.props.isTwelveHour); const isSending = (['sending', 'queued', 'encrypting'].indexOf(this.state.sendStatus) !== -1); const classes = classNames({