1
0
mirror of https://github.com/ascribe/onion.git synced 2024-11-14 17:15:08 +01:00

First cut: Upload button for contract settings

This commit is contained in:
Tim Daubenschütz 2015-09-15 16:35:45 +02:00
parent 497a330e1a
commit 83b20e6472
7 changed files with 209 additions and 33 deletions

View File

@ -113,9 +113,7 @@ let ContractSettings = React.createClass({
content={contract.name}
buttons={
<div className="pull-right">
<button className="btn btn-default btn-sm margin-left-2px">
UPDATE
</button>
<ContractSettingsUpdateButton />
<a
className="btn btn-default btn-sm margin-left-2px"
href={contract.blob.url_safe}

View File

@ -2,13 +2,65 @@
import React from 'react';
import ReactS3FineUploader from '../ascribe_uploader/react_s3_fine_uploader';
import UploadButton from '../ascribe_uploader/ascribe_upload_button/upload_button';
import AppConstants from '../../constants/application_constants';
import ApiUrls from '../../constants/api_urls';
import { formSubmissionValidation } from '../ascribe_uploader/react_s3_fine_uploader_utils';
import { getCookie } from '../../utils/fetch_api_utils';
import { getLangText } from '../../utils/lang_utils';
let ContractSettingsUpdateButton = React.createClass({
setIsUploadReady() {
console.log('upload done');
},
submitFile(file) {
console.log(file);
},
render() {
return (
<button className="btn btn-default btn-sm margin-left-2px">
UPDATE
</button>
<ReactS3FineUploader
fileInputElement={UploadButton}
keyRoutine={{
url: AppConstants.serverUrl + 's3/key/',
fileClass: 'contract'
}}
createBlobRoutine={{
url: ApiUrls.blob_contracts
}}
validation={{
itemLimit: 100000,
sizeLimit: '50000000',
allowedExtensions: ['pdf']
}}
setIsUploadReady={this.setIsUploadReady}
signature={{
endpoint: AppConstants.serverUrl + 's3/signature/',
customHeaders: {
'X-CSRFToken': getCookie(AppConstants.csrftoken)
}
}}
deleteFile={{
enabled: true,
method: 'DELETE',
endpoint: AppConstants.serverUrl + 's3/delete',
customHeaders: {
'X-CSRFToken': getCookie(AppConstants.csrftoken)
}
}}
fileClassToUpload={{
singular: getLangText('UPDATE'),
plural: getLangText('UPDATE')
}}
isReadyForFormSubmission={formSubmissionValidation.atLeastOneUploadedFile}
submitFile={this.submitFile}
/>
);
}
});

View File

@ -12,7 +12,6 @@ import { getLangText } from '../../../utils/lang_utils';
// Taken from: https://github.com/fedosejev/react-file-drag-and-drop
let FileDragAndDrop = React.createClass({
propTypes: {
className: React.PropTypes.string,
onDragStart: React.PropTypes.func,
onDrop: React.PropTypes.func.isRequired,
onDrag: React.PropTypes.func,
@ -47,11 +46,7 @@ let FileDragAndDrop = React.createClass({
plural: React.PropTypes.string
}),
validation: React.PropTypes.shape({
itemLimit: React.PropTypes.number,
sizeLimit: React.PropTypes.string,
allowedExtensions: React.PropTypes.arrayOf(React.PropTypes.string)
})
allowedExtensions: React.PropTypes.string
},
handleDragStart(event) {
@ -183,7 +178,7 @@ let FileDragAndDrop = React.createClass({
fileClassToUpload,
areAssetsDownloadable,
areAssetsEditable,
validation
allowedExtensions
} = this.props;
// has files only is true if there are files that do not have the status deleted or canceled
@ -209,22 +204,6 @@ let FileDragAndDrop = React.createClass({
</div>
);
} else {
let accept = '';
/**
* Fineuploader allows to specify the file extensions that are allowed to upload.
* For our self defined input, we can reuse those declarations to restrict which files
* the user can pick from his hard drive.
*/
if(validation && validation.allowedExtensions && validation.allowedExtensions.length > 0) {
// add a dot in front of the extension
let prefixedAllowedExtensions = validation.allowedExtensions.map((ext) => '.' + ext);
// generate a comma separated list to add them to the DOM element
// See: http://stackoverflow.com/questions/4328947/limit-file-format-when-using-input-type-file
accept = prefixedAllowedExtensions.join(', ');
}
return (
<div
className={updatedClassName}
@ -259,7 +238,7 @@ let FileDragAndDrop = React.createClass({
width: 0
}}
onChange={this.handleDrop}
accept={accept}/>
accept={allowedExtensions}/>
</div>
);
}

View File

@ -0,0 +1,114 @@
'use strict';
import React from 'react';
import { displayValidProgressFilesFilter } from '../react_s3_fine_uploader_utils';
let UploadButton = React.createClass({
propTypes: {
onDragStart: React.PropTypes.func,
onDrop: React.PropTypes.func.isRequired,
onDrag: React.PropTypes.func,
onDragEnter: React.PropTypes.func,
onLeave: React.PropTypes.func,
onDragLeave: React.PropTypes.func,
onDragOver: React.PropTypes.func,
onDragEnd: React.PropTypes.func,
onInactive: React.PropTypes.func,
filesToUpload: React.PropTypes.array,
handleDeleteFile: React.PropTypes.func,
handleCancelFile: React.PropTypes.func,
handlePauseFile: React.PropTypes.func,
handleResumeFile: React.PropTypes.func,
multiple: React.PropTypes.bool,
// For simplification purposes we're just going to use this prop as a
// label for the upload button
fileClassToUpload: React.PropTypes.shape({
singular: React.PropTypes.string,
plural: React.PropTypes.string
}),
allowedExtensions: React.PropTypes.string
},
handleDrop(event) {
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');
},
handleOnClick() {
let uploadingFiles = this.getUploadingFiles();
// 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();
this.refs.fileinput.getDOMNode().dispatchEvent(evt);
}
},
getButtonLabel() {
let { filesToUpload, fileClassToUpload } = this.props;
// filter invalid files that might have been deleted or canceled...
filesToUpload = filesToUpload.filter(displayValidProgressFilesFilter);
// Depending on wether there is an upload going on or not we
// display the progress
if(filesToUpload.length > 0) {
return 'Upload progress: ' + Math.ceil(filesToUpload[0].progress) + '%';
} else {
return fileClassToUpload.singular;
}
},
render() {
let {
multiple,
fileClassToUpload,
allowedExtensions
} = this.props;
return (
<button
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}/>
</button>
);
}
});
export default UploadButton;

View File

@ -16,7 +16,7 @@ import AppConstants from '../../constants/application_constants';
import { computeHashOfFile } from '../../utils/file_utils';
import { displayValidFilesFilter } from './react_s3_fine_uploader_utils';
import { displayValidFilesFilter, transformAllowedExtensionsToInputAcceptProp } from './react_s3_fine_uploader_utils';
import { getCookie } from '../../utils/fetch_api_utils';
import { getLangText } from '../../utils/lang_utils';
@ -125,7 +125,10 @@ let ReactS3FineUploader = React.createClass({
// Uploading functionality of react fineuploader is disconnected from its UI
// layer, which means that literally every (properly adjusted) react element
// can handle the UI handling.
fileInputElement: React.PropTypes.func
fileInputElement: React.PropTypes.oneOfType([
React.PropTypes.func,
React.PropTypes.element
])
},
mixins: [Router.State],
@ -838,6 +841,16 @@ let ReactS3FineUploader = React.createClass({
},
getAllowedExtensions() {
let { validation } = this.props;
if(validation && validation.allowedExtensions && validation.allowedExtensions.length > 0) {
return transformAllowedExtensionsToInputAcceptProp(validation.allowedExtensions);
} else {
return null;
}
},
render() {
let {
multiple,
@ -868,7 +881,7 @@ let ReactS3FineUploader = React.createClass({
hashingProgress: this.state.hashingProgress,
enableLocalHashing: enableLocalHashing,
fileClassToUpload: fileClassToUpload,
validation: validation
allowedExtensions: this.getAllowedExtensions()
});
}

View File

@ -52,3 +52,22 @@ export function displayValidProgressFilesFilter(file) {
return file.status !== 'deleted' && file.status !== 'canceled' && file.status !== 'online';
}
/**
* Fineuploader allows to specify the file extensions that are allowed to upload.
* For our self defined input, we can reuse those declarations to restrict which files
* the user can pick from his hard drive.
*
* Takes an array of file extensions (['pdf', 'png', ...]) and transforms them into a string
* that can be passed into an html5 input via its 'accept' prop.
* @param {array} allowedExtensions Array of strings without a dot prefixed
* @return {string} Joined string (comma-separated) of the passed-in array
*/
export function transformAllowedExtensionsToInputAcceptProp(allowedExtensions) {
// add a dot in front of the extension
let prefixedAllowedExtensions = allowedExtensions.map((ext) => '.' + ext);
// generate a comma separated list to add them to the DOM element
// See: http://stackoverflow.com/questions/4328947/limit-file-format-when-using-input-type-file
return prefixedAllowedExtensions.join(', ');
}

View File

@ -9,6 +9,7 @@
text-align: center;
vertical-align: middle;
cursor: default !important;
padding: 1.5em 0 1.5em 0;
.file-drag-and-drop-dialog > p:first-child {
font-size: 1.5em !important;