diff --git a/src/components/views/messages/MImageBody.js b/src/components/views/messages/MImageBody.js index f5515fad90..55d5a18a25 100644 --- a/src/components/views/messages/MImageBody.js +++ b/src/components/views/messages/MImageBody.js @@ -30,35 +30,45 @@ import Promise from 'bluebird'; import { _t } from '../../../languageHandler'; import SettingsStore from "../../../settings/SettingsStore"; -module.exports = React.createClass({ - displayName: 'MImageBody', +export default class extends React.Component { + displayName: 'MImageBody' - propTypes: { + static propTypes = { /* the MatrixEvent to show */ mxEvent: PropTypes.object.isRequired, /* called when the image has loaded */ onWidgetLoad: PropTypes.func.isRequired, - }, + } - contextTypes: { + static contextTypes = { matrixClient: PropTypes.instanceOf(MatrixClient), - }, + } - getInitialState: function() { - return { + constructor(props) { + super(props); + + this.onAction = this.onAction.bind(this); + this.onImageEnter = this.onImageEnter.bind(this); + this.onImageLeave = this.onImageLeave.bind(this); + this.onClientSync = this.onClientSync.bind(this); + this.onClick = this.onClick.bind(this); + this.fixupHeight = this.fixupHeight.bind(this); + this._isGif = this._isGif.bind(this); + + this.state = { decryptedUrl: null, decryptedThumbnailUrl: null, decryptedBlob: null, error: null, imgError: false, }; - }, + } componentWillMount() { this.unmounted = false; this.context.matrixClient.on('sync', this.onClientSync); - }, + } onClientSync(syncState, prevState) { if (this.unmounted) return; @@ -71,9 +81,9 @@ module.exports = React.createClass({ imgError: false, }); } - }, + } - onClick: function onClick(ev) { + onClick(ev) { if (ev.button == 0 && !ev.metaKey) { ev.preventDefault(); const content = this.props.mxEvent.getContent(); @@ -93,49 +103,49 @@ module.exports = React.createClass({ Modal.createDialog(ImageView, params, "mx_Dialog_lightbox"); } - }, + } - _isGif: function() { + _isGif() { const content = this.props.mxEvent.getContent(); return ( content && content.info && content.info.mimetype === "image/gif" ); - }, + } - onImageEnter: function(e) { + onImageEnter(e) { if (!this._isGif() || SettingsStore.getValue("autoplayGifsAndVideos")) { return; } const imgElement = e.target; imgElement.src = this._getContentUrl(); - }, + } - onImageLeave: function(e) { + onImageLeave(e) { if (!this._isGif() || SettingsStore.getValue("autoplayGifsAndVideos")) { return; } const imgElement = e.target; imgElement.src = this._getThumbUrl(); - }, + } - onImageError: function() { + onImageError() { this.setState({ imgError: true, }); - }, + } - _getContentUrl: function() { + _getContentUrl() { const content = this.props.mxEvent.getContent(); if (content.file !== undefined) { return this.state.decryptedUrl; } else { return this.context.matrixClient.mxcUrlToHttp(content.url); } - }, + } - _getThumbUrl: function() { + _getThumbUrl() { const content = this.props.mxEvent.getContent(); if (content.file !== undefined) { // Don't use the thumbnail for clients wishing to autoplay gifs. @@ -146,9 +156,9 @@ module.exports = React.createClass({ } else { return this.context.matrixClient.mxcUrlToHttp(content.url, 800, 600); } - }, + } - componentDidMount: function() { + componentDidMount() { this.dispatcherRef = dis.register(this.onAction); this.fixupHeight(); const content = this.props.mxEvent.getContent(); @@ -182,23 +192,23 @@ module.exports = React.createClass({ }); }).done(); } - }, + } - componentWillUnmount: function() { + componentWillUnmount() { this.unmounted = true; dis.unregister(this.dispatcherRef); this.context.matrixClient.removeListener('sync', this.onClientSync); - }, + } - onAction: function(payload) { + onAction(payload) { if (payload.action === "timeline_resize") { this.fixupHeight(); } - }, + } - fixupHeight: function() { + fixupHeight() { if (!this.refs.image) { - console.warn("Refusing to fix up height on MImageBody with no image element"); + console.warn(`Refusing to fix up height on ${this.displayName} with no image element`); return; } @@ -214,10 +224,25 @@ module.exports = React.createClass({ } this.refs.image.style.height = thumbHeight + "px"; // console.log("Image height now", thumbHeight); - }, + } - render: function() { - const TintableSvg = sdk.getComponent("elements.TintableSvg"); + _messageContent(contentUrl, thumbUrl, content) { + return ( + + + {content.body} + + + + ); + } + + render() { const content = this.props.mxEvent.getContent(); if (this.state.error !== null) { @@ -265,19 +290,7 @@ module.exports = React.createClass({ } if (thumbUrl) { - return ( - - - {content.body} - - - - ); + return this._messageContent(contentUrl, thumbUrl, content); } else if (content.body) { return ( @@ -291,5 +304,5 @@ module.exports = React.createClass({ ); } - }, -}); + } +} diff --git a/src/components/views/messages/MStickerBody.js b/src/components/views/messages/MStickerBody.js index bd86eed568..95f5d827bb 100644 --- a/src/components/views/messages/MStickerBody.js +++ b/src/components/views/messages/MStickerBody.js @@ -16,209 +16,27 @@ limitations under the License. 'use strict'; -import React from 'react'; -import MatrixClientPeg from '../../../MatrixClientPeg'; -import ImageUtils from '../../../ImageUtils'; -import dis from '../../../dispatcher'; -import { decryptFile, readBlobAsDataUri } from '../../../utils/DecryptFile'; -import Promise from 'bluebird'; -import { _t } from '../../../languageHandler'; -import SettingsStore from "../../../settings/SettingsStore"; +import MImageBody from "./MImageBody"; -module.exports = React.createClass({ - displayName: 'MStickerBody', +export default class MStickerBody extends MImageBody { + displayName: 'MStickerBody' - propTypes: { - /* the MatrixEvent to show */ - mxEvent: React.PropTypes.object.isRequired, + constructor(props) { + super(props); + } - /* called when the image has loaded */ - onWidgetLoad: React.PropTypes.func.isRequired, - }, - - getInitialState: function() { - return { - decryptedUrl: null, - decryptedThumbnailUrl: null, - decryptedBlob: null, - error: null, - }; - }, - - _isGif: function() { - const content = this.props.mxEvent.getContent(); + _messageContent(contentUrl, thumbUrl, content) { return ( - content && - content.info && - content.info.mimetype === "image/gif" + + {content.body} + ); - }, + } - onImageEnter: function(e) { - if (!this._isGif() || SettingsStore.getValue("autoplayGifsAndVideos")) { - return; - } - const imgElement = e.target; - imgElement.src = this._getContentUrl(); - }, - - onImageLeave: function(e) { - if (!this._isGif() || SettingsStore.getValue("autoplayGifsAndVideos")) { - return; - } - const imgElement = e.target; - imgElement.src = this._getThumbUrl(); - }, - - _getContentUrl: function() { - const content = this.props.mxEvent.getContent(); - if (content.file !== undefined) { - return this.state.decryptedUrl; - } else { - return MatrixClientPeg.get().mxcUrlToHttp(content.url); - } - }, - - _getThumbUrl: function() { - const content = this.props.mxEvent.getContent(); - if (content.file !== undefined) { - // Don't use the thumbnail for clients wishing to autoplay gifs. - if (this.state.decryptedThumbnailUrl) { - return this.state.decryptedThumbnailUrl; - } - return this.state.decryptedUrl; - } else { - return MatrixClientPeg.get().mxcUrlToHttp(content.url, 800, 600); - } - }, - - componentDidMount: function() { - this.dispatcherRef = dis.register(this.onAction); - this.fixupHeight(); - const content = this.props.mxEvent.getContent(); - if (content.file !== undefined && this.state.decryptedUrl === null) { - let thumbnailPromise = Promise.resolve(null); - if (content.info.thumbnail_file) { - thumbnailPromise = decryptFile( - content.info.thumbnail_file, - ).then(function(blob) { - return readBlobAsDataUri(blob); - }); - } - let decryptedBlob; - thumbnailPromise.then((thumbnailUrl) => { - return decryptFile(content.file).then(function(blob) { - decryptedBlob = blob; - return readBlobAsDataUri(blob); - }).then((contentUrl) => { - this.setState({ - decryptedUrl: contentUrl, - decryptedThumbnailUrl: thumbnailUrl, - decryptedBlob: decryptedBlob, - }); - this.props.onWidgetLoad(); - }); - }).catch((err) => { - console.warn("Unable to decrypt attachment: ", err); - // Set a placeholder image when we can't decrypt the image. - this.setState({ - error: err, - }); - }).done(); - } - }, - - componentWillUnmount: function() { - dis.unregister(this.dispatcherRef); - }, - - onAction: function(payload) { - if (payload.action === "timeline_resize") { - this.fixupHeight(); - } - }, - - fixupHeight: function() { - if (!this.refs.image) { - console.warn("Refusing to fix up height on MStickerBody with no image element"); - return; - } - - const content = this.props.mxEvent.getContent(); - const timelineWidth = this.refs.body.offsetWidth; - const maxHeight = 600; // let images take up as much width as they can so long as the height doesn't exceed 600px. - // the alternative here would be 600*timelineWidth/800; to scale them down to fit inside a 4:3 bounding box - - //console.log("trying to fit image into timelineWidth of " + this.refs.body.offsetWidth + " or " + this.refs.body.clientWidth); - let thumbHeight = null; - if (content.info) { - thumbHeight = ImageUtils.thumbHeight(content.info.w, content.info.h, timelineWidth, maxHeight); - } - this.refs.image.style.height = thumbHeight + "px"; - // console.log("Image height now", thumbHeight); - }, - - render: function() { - const content = this.props.mxEvent.getContent(); - - if (this.state.error !== null) { - return ( - - - { _t("Error decrypting image") } - - ); - } - - if (content.file !== undefined && this.state.decryptedUrl === null) { - // Need to decrypt the attachment - // The attachment is decrypted in componentDidMount. - // For now add an img tag with a spinner. - return ( - -
- {content.body} -
-
- ); - } - - const contentUrl = this._getContentUrl(); - let thumbUrl; - if (this._isGif() && SettingsStore.getValue("autoplayGifsAndVideos")) { - thumbUrl = contentUrl; - } else { - thumbUrl = this._getThumbUrl(); - } - - if (thumbUrl) { - return ( - - {content.body} - - ); - } else if (content.body) { - return ( - - { _t("Image '%(Body)s' cannot be displayed.", {Body: content.body}) } - - ); - } else { - return ( - - { _t("This image cannot be displayed.") } - - ); - } - }, -}); + onClick() { + } +}