diff --git a/js/components/ascribe_settings/contract_settings.js b/js/components/ascribe_settings/contract_settings.js index a3c40380..8a6700f1 100644 --- a/js/components/ascribe_settings/contract_settings.js +++ b/js/components/ascribe_settings/contract_settings.js @@ -113,9 +113,7 @@ let ContractSettings = React.createClass({ content={contract.name} buttons={
- + - UPDATE - + ); } }); diff --git a/js/components/ascribe_uploader/ascribe_file_drag_and_drop/file_drag_and_drop.js b/js/components/ascribe_uploader/ascribe_file_drag_and_drop/file_drag_and_drop.js index 71f3a321..1e21aeb8 100644 --- a/js/components/ascribe_uploader/ascribe_file_drag_and_drop/file_drag_and_drop.js +++ b/js/components/ascribe_uploader/ascribe_file_drag_and_drop/file_drag_and_drop.js @@ -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({
); } 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 (
+ accept={allowedExtensions}/>
); } diff --git a/js/components/ascribe_uploader/ascribe_upload_button/upload_button.js b/js/components/ascribe_uploader/ascribe_upload_button/upload_button.js new file mode 100644 index 00000000..a3fa985c --- /dev/null +++ b/js/components/ascribe_uploader/ascribe_upload_button/upload_button.js @@ -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 ( + + ); + } +}); + +export default UploadButton; \ No newline at end of file diff --git a/js/components/ascribe_uploader/react_s3_fine_uploader.js b/js/components/ascribe_uploader/react_s3_fine_uploader.js index 8ba53444..05709ad2 100644 --- a/js/components/ascribe_uploader/react_s3_fine_uploader.js +++ b/js/components/ascribe_uploader/react_s3_fine_uploader.js @@ -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() }); } diff --git a/js/components/ascribe_uploader/react_s3_fine_uploader_utils.js b/js/components/ascribe_uploader/react_s3_fine_uploader_utils.js index 92d5c2ba..cd1dbce2 100644 --- a/js/components/ascribe_uploader/react_s3_fine_uploader_utils.js +++ b/js/components/ascribe_uploader/react_s3_fine_uploader_utils.js @@ -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(', '); +} diff --git a/sass/ascribe_uploader.scss b/sass/ascribe_uploader.scss index 6e9eebd9..331b6b00 100644 --- a/sass/ascribe_uploader.scss +++ b/sass/ascribe_uploader.scss @@ -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;