1
0
mirror of https://github.com/ascribe/onion.git synced 2024-06-30 05:31:58 +02:00
onion/js/components/ascribe_uploader/ascribe_upload_button/upload_button.js

191 lines
6.8 KiB
JavaScript
Raw Normal View History

'use strict';
import React from 'react';
2015-12-21 11:46:46 +01:00
import classNames from 'classnames';
import { displayValidProgressFilesFilter, FileStatus } from '../react_s3_fine_uploader_utils';
2015-09-16 09:47:22 +02:00
import { getLangText } from '../../../utils/lang_utils';
import { truncateTextAtCharIndex } from '../../../utils/general_utils';
2015-09-16 09:47:22 +02:00
const { func, array, bool, shape, string } = React.PropTypes;
2015-12-21 11:46:46 +01:00
export default function UploadButton({ className = 'btn btn-default btn-sm', showLabel = true } = {}) {
2015-11-17 11:22:24 +01:00
return React.createClass({
displayName: 'UploadButton',
propTypes: {
onDrop: func.isRequired,
filesToUpload: array,
multiple: bool,
// For simplification purposes we're just going to use this prop as a
// label for the upload button
fileClassToUpload: shape({
singular: string,
plural: string
}),
allowedExtensions: string,
// provided by ReactS3FineUploader
handleCancelFile: func,
handleDeleteFile: func
2015-11-17 11:22:24 +01:00
},
2015-12-08 20:55:13 +01:00
getInitialState() {
return {
disabled: this.getUploadingFiles().length !== 0
};
},
componentWillReceiveProps(nextProps) {
if(this.props.filesToUpload !== nextProps.filesToUpload) {
this.setState({
disabled: this.getUploadingFiles(nextProps.filesToUpload).length !== 0
});
}
},
2015-11-17 11:22:24 +01:00
handleDrop(event) {
event.preventDefault();
event.stopPropagation();
let files = event.target.files;
if(typeof this.props.onDrop === 'function' && files) {
2015-11-19 17:36:47 +01:00
this.props.onDrop(files);
2015-11-17 11:22:24 +01:00
}
},
2015-12-08 20:55:13 +01:00
getUploadingFiles(filesToUpload = this.props.filesToUpload) {
return filesToUpload.filter((file) => file.status === FileStatus.UPLOADING);
2015-11-17 11:22:24 +01:00
},
getUploadedFile() {
return this.props.filesToUpload.filter((file) => file.status === FileStatus.UPLOAD_SUCCESSFUL)[0];
2015-11-17 11:22:24 +01:00
},
2015-12-08 20:55:13 +01:00
clearSelection() {
this.refs.fileSelector.getDOMNode().value = '';
},
2015-11-17 11:22:24 +01:00
2015-12-08 20:55:13 +01:00
handleOnClick() {
if(!this.state.disabled) {
let evt;
// First, remove any currently uploading or uploaded items
this.onClickRemove();
2015-12-08 20:55:13 +01:00
try {
evt = new MouseEvent('click', {
view: window,
bubbles: true,
cancelable: true
});
} catch(e) {
// For browsers that do not support the new MouseEvent syntax
evt = document.createEvent('MouseEvents');
evt.initMouseEvent('click', true, true, window, 0, 0, 0, 80, 20, false, false, false, false, 0, null);
}
2015-11-17 11:22:24 +01:00
evt.stopPropagation();
2015-12-08 20:55:13 +01:00
this.refs.fileSelector.getDOMNode().dispatchEvent(evt);
2015-11-17 11:22:24 +01:00
}
},
onClickRemove() {
const uploadingFiles = this.getUploadingFiles();
const uploadedFile = this.getUploadedFile();
this.clearSelection();
if(uploadingFiles.length) {
this.props.handleCancelFile(uploadingFiles[0].id);
} else if(uploadedFile && !uploadedFile.s3UrlSafe) {
this.props.handleCancelFile(uploadedFile.id);
} else if(uploadedFile && uploadedFile.s3UrlSafe) {
this.props.handleDeleteFile(uploadedFile.id);
}
},
2015-12-08 20:55:13 +01:00
2015-11-17 11:22:24 +01:00
getButtonLabel() {
let { filesToUpload, fileClassToUpload } = this.props;
// filter invalid files that might have been deleted or canceled...
filesToUpload = filesToUpload.filter(displayValidProgressFilesFilter);
if(this.getUploadingFiles().length !== 0) {
return getLangText('Upload progress') + ': ' + Math.ceil(filesToUpload[0].progress) + '%';
} else {
return fileClassToUpload.singular;
}
},
getUploadedFileLabel() {
2015-12-21 11:46:46 +01:00
if (showLabel) {
const uploadedFile = this.getUploadedFile();
const uploadingFiles = this.getUploadingFiles();
2015-11-17 11:22:24 +01:00
2015-12-21 11:46:46 +01:00
if (uploadingFiles.length) {
return (
<span>
{' ' + truncateTextAtCharIndex(uploadingFiles[0].name, 40) + ' '}
[<a onClick={this.onClickRemove}>{getLangText('cancel upload')}</a>]
</span>
);
} else if (uploadedFile) {
return (
<span>
<span className='ascribe-icon icon-ascribe-ok'/>
{' ' + truncateTextAtCharIndex(uploadedFile.name, 40) + ' '}
[<a onClick={this.onClickRemove}>{getLangText('remove')}</a>]
</span>
);
} else {
return <span>{getLangText('No file chosen')}</span>;
}
2015-11-17 11:22:24 +01:00
}
},
render() {
2015-12-08 20:55:13 +01:00
const {
multiple,
allowedExtensions } = this.props;
const { disabled } = this.state;
2015-11-17 11:22:24 +01:00
/*
* We do not want a button that submits here.
* As UploadButton could be used in forms that want to be submitted independent
* of clicking the selector.
* Therefore the wrapping component needs to be an `anchor` tag instead of a `button`
*/
return (
2015-12-21 11:46:46 +01:00
<div className={classNames('ascribe-upload-button', {'ascribe-upload-button-has-label': showLabel})}>
2015-12-08 20:55:13 +01:00
{/*
The button needs to be of `type="button"` as it would
otherwise submit the form its in.
*/}
<button
type="button"
2015-11-17 11:22:24 +01:00
onClick={this.handleOnClick}
className={className}
2015-12-08 20:55:13 +01:00
disabled={disabled}>
2015-11-17 11:22:24 +01:00
{this.getButtonLabel()}
<input
multiple={multiple}
2015-12-08 20:55:13 +01:00
ref="fileSelector"
2015-11-17 11:22:24 +01:00
type="file"
style={{
display: 'none',
height: 0,
width: 0
}}
onChange={this.handleDrop}
accept={allowedExtensions}/>
2015-12-08 20:55:13 +01:00
</button>
2015-11-17 11:22:24 +01:00
{this.getUploadedFileLabel()}
</div>
);
}
2015-11-17 11:22:24 +01:00
});
}