1
0
mirror of https://github.com/ascribe/onion.git synced 2025-02-14 21:10:27 +01:00

Refactor UploadButton to resemble HTML5 file chooser input

This commit is contained in:
Tim Daubenschütz 2015-11-12 14:18:08 +01:00
parent d1b931715d
commit 45d5821abb
3 changed files with 130 additions and 113 deletions

View File

@ -56,7 +56,7 @@ let ContractSettingsUpdateButton = React.createClass({
render() { render() {
return ( return (
<ReactS3FineUploader <ReactS3FineUploader
fileInputElement={UploadButton()} fileInputElement={UploadButton}
keyRoutine={{ keyRoutine={{
url: AppConstants.serverUrl + 's3/key/', url: AppConstants.serverUrl + 's3/key/',
fileClass: 'contract' fileClass: 'contract'

View File

@ -8,119 +8,132 @@ import { displayValidProgressFilesFilter } from '../react_s3_fine_uploader_utils
import { getLangText } from '../../../utils/lang_utils'; import { getLangText } from '../../../utils/lang_utils';
import { truncateTextAtCharIndex } from '../../../utils/general_utils'; import { truncateTextAtCharIndex } from '../../../utils/general_utils';
const { func, array, bool, shape, string } = React.PropTypes;
export default function UploadButton(label) { let UploadButton = React.createClass({
return React.createClass({ propTypes: {
propTypes: { onDrop: func.isRequired,
onDrop: React.PropTypes.func.isRequired, filesToUpload: array,
filesToUpload: React.PropTypes.array, multiple: bool,
multiple: React.PropTypes.bool,
// For simplification purposes we're just going to use this prop as a // For simplification purposes we're just going to use this prop as a
// label for the upload button // label for the upload button
fileClassToUpload: React.PropTypes.shape({ fileClassToUpload: shape({
singular: React.PropTypes.string, singular: string,
plural: React.PropTypes.string plural: string
}), }),
allowedExtensions: React.PropTypes.string allowedExtensions: string,
},
handleDrop(event) { handleCancelFile: func // provided by ReactS3FineUploader
event.preventDefault(); },
event.stopPropagation();
let files = event.target.files;
if(typeof this.props.onDrop === 'function' && files) { handleDrop(event) {
this.props.onDrop(files); event.preventDefault();
} event.stopPropagation();
let files = event.target.files;
}, if(typeof this.props.onDrop === 'function' && files) {
this.props.onDrop(files);
}
getUploadingFiles() { },
return this.props.filesToUpload.filter((file) => file.status === 'uploading');
},
getUploadedFile() { getUploadingFiles() {
return this.props.filesToUpload.filter((file) => file.status === 'upload successful')[0]; return this.props.filesToUpload.filter((file) => file.status === 'uploading');
}, },
handleOnClick() { getUploadedFile() {
let uploadingFiles = this.getUploadingFiles(); return this.props.filesToUpload.filter((file) => file.status === 'upload successful')[0];
},
handleOnClick() {
const uploadingFiles = this.getUploadingFiles();
const uploadedFile = this.getUploadedFile();
if(uploadedFile) {
this.props.handleCancelFile(uploadedFile.id);
}
if(uploadingFiles.length === 0) {
// We only want the button to be clickable if there are no files currently uploading // We only want the button to be clickable if there are no files currently uploading
if(uploadingFiles.length === 0) {
// Firefox only recognizes the simulated mouse click if bubbles is set to true,
// but since Google Chrome propagates the event much further than needed, we
// need to stop propagation as soon as the event is created
var evt = new MouseEvent('click', {
view: window,
bubbles: true,
cancelable: true
});
evt.stopPropagation(); // Firefox only recognizes the simulated mouse click if bubbles is set to true,
this.refs.fileinput.getDOMNode().dispatchEvent(evt); // but since Google Chrome propagates the event much further than needed, we
} // need to stop propagation as soon as the event is created
}, var evt = new MouseEvent('click', {
view: window,
bubbles: true,
cancelable: true
});
getButtonLabel() { evt.stopPropagation();
const uploadedFile = this.getUploadedFile(); this.refs.fileinput.getDOMNode().dispatchEvent(evt);
let { filesToUpload, fileClassToUpload } = this.props; }
},
// filter invalid files that might have been deleted or canceled... getButtonLabel() {
filesToUpload = filesToUpload.filter(displayValidProgressFilesFilter); let { filesToUpload, fileClassToUpload } = this.props;
// Depending on whether there is an upload going on or not we // filter invalid files that might have been deleted or canceled...
// display the progress or the successfully uploaded file's name filesToUpload = filesToUpload.filter(displayValidProgressFilesFilter);
if(uploadedFile) {
return (
<span>
<Glyphicon glyph="ok" />
{' ' + truncateTextAtCharIndex(uploadedFile.name, 20)}
</span>
);
} else if(filesToUpload.length > 0) {
return getLangText('Upload progress') + ': ' + Math.ceil(filesToUpload[0].progress) + '%';
} else {
return fileClassToUpload.singular;
}
},
render() { if(this.getUploadingFiles().length !== 0) {
let { return getLangText('Upload progress') + ': ' + Math.ceil(filesToUpload[0].progress) + '%';
multiple, } else {
allowedExtensions return fileClassToUpload.singular;
} = this.props; }
},
/* getUploadedFileLabel() {
* We do not want a button that submits here. const uploadedFile = this.getUploadedFile();
* As UploadButton could be used in forms that want to be submitted independent
* of clicking the selector. if(uploadedFile) {
* Therefore the wrapping component needs to be an `anchor` tag instead of a `button`
*/
return ( return (
<div className="upload-button-wrapper"> <span>
<a <Glyphicon glyph="ok" />
onClick={this.handleOnClick} {' ' + truncateTextAtCharIndex(uploadedFile.name, 20)}
className="btn btn-default btn-sm margin-left-2px" </span>
disabled={this.getUploadingFiles().length !== 0 || !!this.getUploadedFile()}> );
{this.getButtonLabel()} } else {
<input return (
multiple={multiple} <span>{getLangText('No file chosen')}</span>
ref="fileinput"
type="file"
style={{
display: 'none',
height: 0,
width: 0
}}
onChange={this.handleDrop}
accept={allowedExtensions}/>
</a>
{label}
</div>
); );
} }
}); },
}
render() {
let { multiple,
allowedExtensions } = this.props;
/*
* 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 (
<div className="upload-button-wrapper">
<a
onClick={this.handleOnClick}
className="btn btn-default btn-sm margin-left-2px"
disabled={this.getUploadingFiles().length !== 0}>
{this.getButtonLabel()}
<input
multiple={multiple}
ref="fileinput"
type="file"
style={{
display: 'none',
height: 0,
width: 0
}}
onChange={this.handleDrop}
accept={allowedExtensions}/>
</a>
{this.getUploadedFileLabel()}
</div>
);
}
});
export default UploadButton;

View File

@ -249,9 +249,10 @@ const PRRegisterPieceForm = React.createClass({
className="ascribe-form-bordered" className="ascribe-form-bordered"
ref="uploadersForm"> ref="uploadersForm">
<Property <Property
name="digitalWorkKey"> name="digitalWorkKey"
label={getLangText('Select the PDF with your work')}>
<InputFineuploader <InputFineuploader
fileInputElement={UploadButton(<span>{getLangText('Select the PDF with your work')}</span>)} fileInputElement={UploadButton}
isReadyForFormSubmission={formSubmissionValidation.atLeastOneUploadedFile} isReadyForFormSubmission={formSubmissionValidation.atLeastOneUploadedFile}
setIsUploadReady={this.setIsUploadReady('digitalWorkKeyReady')} setIsUploadReady={this.setIsUploadReady('digitalWorkKeyReady')}
createBlobRoutine={{ createBlobRoutine={{
@ -268,15 +269,16 @@ const PRRegisterPieceForm = React.createClass({
}} }}
location={location} location={location}
fileClassToUpload={{ fileClassToUpload={{
singular: getLangText('Upload the Portfolio'), singular: getLangText('Select the Portfolio'),
plural: getLangText('Upload the Portfolios') plural: getLangText('Select the Portfolios')
}} }}
required/> required/>
</Property> </Property>
<Property <Property
name="thumbnailKey"> name="thumbnailKey"
label={getLangText('Featured Cover photo')}>
<InputFineuploader <InputFineuploader
fileInputElement={UploadButton(<span>{getLangText('Featured Cover photo')}</span>)} fileInputElement={UploadButton}
createBlobRoutine={{ createBlobRoutine={{
url: ApiUrls.blob_thumbnails url: ApiUrls.blob_thumbnails
}} }}
@ -293,15 +295,16 @@ const PRRegisterPieceForm = React.createClass({
}} }}
location={location} location={location}
fileClassToUpload={{ fileClassToUpload={{
singular: getLangText('Upload cover photo'), singular: getLangText('Select cover photo'),
plural: getLangText('Upload cover photos') plural: getLangText('Select cover photos')
}} }}
required/> required/>
</Property> </Property>
<Property <Property
name="supportingMaterials"> name="supportingMaterials"
label={getLangText('Supporting Materials (Optional)')}>
<InputFineuploader <InputFineuploader
fileInputElement={UploadButton(<span>{getLangText('Supporting Materials (Optional)')}</span>)} fileInputElement={UploadButton}
isReadyForFormSubmission={formSubmissionValidation.atLeastOneUploadedFile} isReadyForFormSubmission={formSubmissionValidation.atLeastOneUploadedFile}
setIsUploadReady={this.setIsUploadReady('supportingMaterialsReady')} setIsUploadReady={this.setIsUploadReady('supportingMaterialsReady')}
createBlobRoutine={this.getCreateBlobRoutine()} createBlobRoutine={this.getCreateBlobRoutine()}
@ -315,14 +318,15 @@ const PRRegisterPieceForm = React.createClass({
}} }}
location={location} location={location}
fileClassToUpload={{ fileClassToUpload={{
singular: getLangText('Upload supporting material'), singular: getLangText('Select supporting material'),
plural: getLangText('Upload supporting materials') plural: getLangText('Select supporting materials')
}}/> }}/>
</Property> </Property>
<Property <Property
name="proofOfPayment"> name="proofOfPayment"
label={getLangText('Proof of payment')}>
<InputFineuploader <InputFineuploader
fileInputElement={UploadButton(<span>{getLangText('Proof of payment')}</span>)} fileInputElement={UploadButton}
isReadyForFormSubmission={formSubmissionValidation.atLeastOneUploadedFile} isReadyForFormSubmission={formSubmissionValidation.atLeastOneUploadedFile}
setIsUploadReady={this.setIsUploadReady('proofOfPaymentReady')} setIsUploadReady={this.setIsUploadReady('proofOfPaymentReady')}
createBlobRoutine={this.getCreateBlobRoutine()} createBlobRoutine={this.getCreateBlobRoutine()}
@ -337,8 +341,8 @@ const PRRegisterPieceForm = React.createClass({
}} }}
location={location} location={location}
fileClassToUpload={{ fileClassToUpload={{
singular: getLangText('Upload Screenshot'), singular: getLangText('Select Screenshot'),
plural: getLangText('Upload Screenshots') plural: getLangText('Select Screenshots')
}} }}
required/> required/>
</Property> </Property>