summaryrefslogtreecommitdiffstats
path: root/web
diff options
context:
space:
mode:
authorhmhealey <harrisonmhealey@gmail.com>2016-01-05 15:49:45 -0500
committerhmhealey <harrisonmhealey@gmail.com>2016-01-06 09:44:12 -0500
commit239d147d9757c62cbfb6ae7b2900b0e5ace6f71c (patch)
tree05032970def7f0a021fe4d5c403f0fb973c24ae9 /web
parent0eb145218edb37d911cc5ec135b0006f866a44b2 (diff)
downloadchat-239d147d9757c62cbfb6ae7b2900b0e5ace6f71c.tar.gz
chat-239d147d9757c62cbfb6ae7b2900b0e5ace6f71c.tar.bz2
chat-239d147d9757c62cbfb6ae7b2900b0e5ace6f71c.zip
Changed Audio/Video preview to just display a file info when encountering a file that cannot be played
Diffstat (limited to 'web')
-rw-r--r--web/react/components/audio_video_preview.jsx114
-rw-r--r--web/react/components/file_info_preview.jsx31
-rw-r--r--web/react/components/view_image.jsx104
-rw-r--r--web/react/utils/utils.jsx19
4 files changed, 190 insertions, 78 deletions
diff --git a/web/react/components/audio_video_preview.jsx b/web/react/components/audio_video_preview.jsx
new file mode 100644
index 000000000..7d00fbdaa
--- /dev/null
+++ b/web/react/components/audio_video_preview.jsx
@@ -0,0 +1,114 @@
+// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import Constants from '../utils/constants.jsx';
+import FileInfoPreview from './file_info_preview.jsx';
+import * as Utils from '../utils/utils.jsx';
+
+export default class AudioVideoPreview extends React.Component {
+ constructor(props) {
+ super(props);
+
+ this.handleFileInfoChanged = this.handleFileInfoChanged.bind(this);
+ this.handleLoadError = this.handleLoadError.bind(this);
+
+ this.stop = this.stop.bind(this);
+
+ this.state = {
+ canPlay: true
+ };
+ }
+
+ componentWillMount() {
+ this.handleFileInfoChanged(this.props.fileInfo);
+ }
+
+ componentDidMount() {
+ if (this.refs.source) {
+ $(ReactDOM.findDOMNode(this.refs.source)).one('error', this.handleLoadError);
+ }
+ }
+
+ componentWillReceiveProps(nextProps) {
+ if (this.props.fileUrl !== nextProps.fileUrl) {
+ this.handleFileInfoChanged(nextProps.fileInfo);
+ }
+ }
+
+ handleFileInfoChanged(fileInfo) {
+ let video = ReactDOM.findDOMNode(this.refs.video);
+ if (!video) {
+ video = document.createElement('video');
+ }
+
+ const canPlayType = video.canPlayType(fileInfo.mime_type);
+
+ this.setState({
+ canPlay: canPlayType === 'probably' || canPlayType === 'maybe'
+ });
+ }
+
+ componentDidUpdate() {
+ if (this.refs.source) {
+ $(ReactDOM.findDOMNode(this.refs.source)).one('error', this.handleLoadError);
+ }
+ }
+
+ handleLoadError() {
+ this.setState({
+ canPlay: false
+ });
+ }
+
+ stop() {
+ if (this.refs.video) {
+ const video = ReactDOM.findDOMNode(this.refs.video);
+ video.pause();
+ video.currentTime = 0;
+ }
+ }
+
+ render() {
+ if (!this.state.canPlay) {
+ return (
+ <FileInfoPreview
+ filename={this.props.filename}
+ fileUrl={this.props.fileUrl}
+ fileInfo={this.props.fileInfo}
+ />
+ );
+ }
+
+ let width = Constants.WEB_VIDEO_WIDTH;
+ let height = Constants.WEB_VIDEO_HEIGHT;
+ if (Utils.isMobile()) {
+ width = Constants.MOBILE_VIDEO_WIDTH;
+ height = Constants.MOBILE_VIDEO_HEIGHT;
+ }
+
+ // add a key to the video to prevent React from using an old video source while a new one is loading
+ return (
+ <video
+ key={this.props.filename}
+ ref='video'
+ style={{maxHeight: this.props.maxHeight}}
+ data-setup='{}'
+ controls='controls'
+ width={width}
+ height={height}
+ >
+ <source
+ ref='source'
+ src={this.props.fileUrl}
+ />
+ </video>
+ );
+ }
+}
+
+AudioVideoPreview.propTypes = {
+ filename: React.PropTypes.string.isRequired,
+ fileUrl: React.PropTypes.string.isRequired,
+ fileInfo: React.PropTypes.object.isRequired,
+ maxHeight: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]).isRequired
+};
diff --git a/web/react/components/file_info_preview.jsx b/web/react/components/file_info_preview.jsx
new file mode 100644
index 000000000..4b76cd162
--- /dev/null
+++ b/web/react/components/file_info_preview.jsx
@@ -0,0 +1,31 @@
+// Copyright (c) 2016 Mattermost, Inc. All Rights Reserved.
+// See License.txt for license information.
+
+import * as Utils from '../utils/utils.jsx';
+
+export default function FileInfoPreview({filename, fileUrl, fileInfo}) {
+ // non-image files include a section providing details about the file
+ let infoString = 'File type ' + fileInfo.extension.toUpperCase();
+ if (fileInfo.size > 0) {
+ infoString += ', Size ' + Utils.fileSizeToString(fileInfo.size);
+ }
+
+ const name = decodeURIComponent(Utils.getFileName(filename));
+
+ return (
+ <div className='file-details__container'>
+ <a
+ className={'file-details__preview'}
+ href={fileUrl}
+ target='_blank'
+ >
+ <span className='file-details__preview-helper' />
+ <img src={Utils.getPreviewImagePath(filename)}/>
+ </a>
+ <div className='file-details'>
+ <div className='file-details__name'>{name}</div>
+ <div className='file-details__info'>{infoString}</div>
+ </div>
+ </div>
+ );
+}
diff --git a/web/react/components/view_image.jsx b/web/react/components/view_image.jsx
index 196a44bd0..31ec91248 100644
--- a/web/react/components/view_image.jsx
+++ b/web/react/components/view_image.jsx
@@ -4,7 +4,9 @@
import * as AsyncClient from '../utils/async_client.jsx';
import * as Client from '../utils/client.jsx';
import * as Utils from '../utils/utils.jsx';
+import AudioVideoPreview from './audio_video_preview.jsx';
import Constants from '../utils/constants.jsx';
+import FileInfoPreview from './file_info_preview.jsx';
import FileStore from '../stores/file_store.jsx';
import ViewImagePopoverBar from './view_image_popover_bar.jsx';
const Modal = ReactBootstrap.Modal;
@@ -27,7 +29,6 @@ export default class ViewImageModal extends React.Component {
this.onFileStoreChange = this.onFileStoreChange.bind(this);
this.getPublicLink = this.getPublicLink.bind(this);
- this.getPreviewImagePath = this.getPreviewImagePath.bind(this);
this.onMouseEnterImage = this.onMouseEnterImage.bind(this);
this.onMouseLeaveImage = this.onMouseLeaveImage.bind(this);
@@ -83,9 +84,7 @@ export default class ViewImageModal extends React.Component {
$(window).off('keyup', this.handleKeyPress);
if (this.refs.video) {
- var video = ReactDOM.findDOMNode(this.refs.video);
- video.pause();
- video.currentTime = 0;
+ this.refs.video.stop();
}
FileStore.removeChangeListener(this.onFileStoreChange);
@@ -152,7 +151,7 @@ export default class ViewImageModal extends React.Component {
if (fileType === 'image') {
let previewUrl;
if (fileInfo.has_image_preview) {
- previewUrl = fileInfo.getPreviewImagePath(filename);
+ previewUrl = Utils.getPreviewImagePath(filename);
} else {
// some images (eg animated gifs) just show the file itself and not a preview
previewUrl = Utils.getFileUrl(filename);
@@ -198,25 +197,6 @@ export default class ViewImageModal extends React.Component {
);
}
- getPreviewImagePath(filename) {
- // Returns the path to a preview image that can be used to represent a file.
- var fileInfo = Utils.splitFileLocation(filename);
- var fileType = Utils.getFileType(fileInfo.ext);
-
- if (fileType === 'image') {
- // This is a temporary patch to fix issue with old files using absolute paths
- if (fileInfo.path.indexOf('/api/v1/files/get') !== -1) {
- fileInfo.path = fileInfo.path.split('/api/v1/files/get')[1];
- }
- fileInfo.path = Utils.getWindowLocationOrigin() + '/api/v1/files/get' + fileInfo.path;
-
- return fileInfo.path + '_preview.jpg?' + Utils.getSessionIndex();
- }
-
- // only images have proper previews, so just use a placeholder icon for non-images
- return Utils.getPreviewImagePathForFileType(fileType);
- }
-
onMouseEnterImage() {
this.setState({showFooter: true});
}
@@ -237,72 +217,33 @@ export default class ViewImageModal extends React.Component {
if (this.state.loaded[this.state.imgId]) {
// this.state.fileInfo is for the current image and we shoudl have it before we load the image
const fileInfo = this.state.fileInfo;
-
- const extension = Utils.splitFileLocation(filename).ext;
- const fileType = Utils.getFileType(extension);
+ const fileType = Utils.getFileType(fileInfo.extension);
if (fileType === 'image') {
- let previewUrl;
- if (fileInfo.has_preview_image) {
- previewUrl = this.getPreviewImagePath(filename);
- } else {
- previewUrl = fileUrl;
- }
-
content = (
<ImagePreview
+ filename={filename}
fileUrl={fileUrl}
- previewUrl={previewUrl}
+ fileInfo={fileInfo}
maxHeight={this.state.imgHeight}
/>
);
} else if (fileType === 'video' || fileType === 'audio') {
- let width = Constants.WEB_VIDEO_WIDTH;
- let height = Constants.WEB_VIDEO_HEIGHT;
- if (Utils.isMobile()) {
- width = Constants.MOBILE_VIDEO_WIDTH;
- height = Constants.MOBILE_VIDEO_HEIGHT;
- }
-
content = (
- <video
- style={{maxHeight: this.state.imgHeight}}
- ref='video'
- data-setup='{}'
- controls='controls'
- width={width}
- height={height}
- >
- <source src={Utils.getWindowLocationOrigin() + '/api/v1/files/get' + filename + '?' + Utils.getSessionIndex()} />
- </video>
+ <AudioVideoPreview
+ filename={filename}
+ fileUrl={fileUrl}
+ fileInfo={this.state.fileInfo}
+ maxHeight={this.state.imgHeight}
+ />
);
} else {
- // non-image files include a section providing details about the file
- let infoString = 'File type ' + fileInfo.extension.toUpperCase();
- if (fileInfo.size > 0) {
- infoString += ', Size ' + Utils.fileSizeToString(fileInfo.size);
- }
-
- const name = decodeURIComponent(Utils.getFileName(filename));
-
content = (
- <div className='file-details__container'>
- <a
- className={'file-details__preview'}
- href={fileUrl}
- target='_blank'
- >
- <span className='file-details__preview-helper' />
- <img
- ref='image'
- src={this.getPreviewImagePath(filename)}
- />
- </a>
- <div className='file-details'>
- <div className='file-details__name'>{name}</div>
- <div className='file-details__info'>{infoString}</div>
- </div>
- </div>
+ <FileInfoPreview
+ filename={filename}
+ fileUrl={fileUrl}
+ fileInfo={fileInfo}
+ />
);
}
} else {
@@ -424,7 +365,14 @@ function LoadingImagePreview({progress}) {
);
}
-function ImagePreview({maxHeight, fileUrl, previewUrl}) {
+function ImagePreview({filename, fileUrl, fileInfo, maxHeight}) {
+ let previewUrl;
+ if (fileInfo.has_preview_image) {
+ previewUrl = Utils.getPreviewImagePath(filename);
+ } else {
+ previewUrl = fileUrl;
+ }
+
return (
<a
href={fileUrl}
diff --git a/web/react/utils/utils.jsx b/web/react/utils/utils.jsx
index a808c9be3..41ede7712 100644
--- a/web/react/utils/utils.jsx
+++ b/web/react/utils/utils.jsx
@@ -527,6 +527,25 @@ export function splitFileLocation(fileLocation) {
return {ext: ext, name: filename, path: filePath};
}
+export function getPreviewImagePath(filename) {
+ // Returns the path to a preview image that can be used to represent a file.
+ const fileInfo = splitFileLocation(filename);
+ const fileType = getFileType(fileInfo.ext);
+
+ if (fileType === 'image') {
+ // This is a temporary patch to fix issue with old files using absolute paths
+ if (fileInfo.path.indexOf('/api/v1/files/get') !== -1) {
+ fileInfo.path = fileInfo.path.split('/api/v1/files/get')[1];
+ }
+ fileInfo.path = getWindowLocationOrigin() + '/api/v1/files/get' + fileInfo.path;
+
+ return fileInfo.path + '_preview.jpg?' + getSessionIndex();
+ }
+
+ // only images have proper previews, so just use a placeholder icon for non-images
+ return getPreviewImagePathForFileType(fileType);
+}
+
export function toTitleCase(str) {
function doTitleCase(txt) {
return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();