1
0
mirror of https://github.com/ascribe/onion.git synced 2024-06-30 13:41:57 +02:00
onion/js/components/ascribe_uploader/ascribe_file_drag_and_drop/file_drag_and_drop.js
Brett Sun d23331d9b9 Remove ReactS3FineUploader's dependency on react-router's location
ReactS3FineUploader used to check the current url’s query params to
determine which method it should use to upload, but this decision means
the component is tightly coupled with react-router and history.js. A
major pain point is having to propagate the location prop all the way
down to this component even when it’s not necessary.

Now, ReactS3FineUploader’s parent elements can either parse the current
query params themselves or, if they have a location from react-router,
simply use the location.

Added a few utils to help parse url params.
2015-10-30 17:43:20 +01:00

227 lines
8.5 KiB
JavaScript

'use strict';
import React from 'react';
import ProgressBar from 'react-bootstrap/lib/ProgressBar';
import FileDragAndDropDialog from './file_drag_and_drop_dialog';
import FileDragAndDropPreviewIterator from './file_drag_and_drop_preview_iterator';
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,
onDrop: React.PropTypes.func.isRequired,
onDragOver: 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,
dropzoneInactive: React.PropTypes.bool,
areAssetsDownloadable: React.PropTypes.bool,
areAssetsEditable: React.PropTypes.bool,
enableLocalHashing: React.PropTypes.bool,
uploadMethod: React.PropTypes.string,
// triggers a FileDragAndDrop-global spinner
hashingProgress: React.PropTypes.number,
// sets the value of this.state.hashingProgress in reactfineuploader
// to -1 which is code for: aborted
handleCancelHashing: React.PropTypes.func,
// A class of a file the user has to upload
// Needs to be defined both in singular as well as in plural
fileClassToUpload: React.PropTypes.shape({
singular: React.PropTypes.string,
plural: React.PropTypes.string
}),
allowedExtensions: React.PropTypes.string
},
handleDragOver(event) {
event.preventDefault();
if (typeof this.props.onDragOver === 'function') {
this.props.onDragOver(event);
}
},
handleDrop(event) {
event.preventDefault();
event.stopPropagation();
let files;
if(this.props.dropzoneInactive) {
// if there is a handle function for doing stuff
// when the dropzone is inactive, then call it
if(this.props.onInactive) {
this.props.onInactive();
}
return;
}
// handle Drag and Drop
if(event.dataTransfer && event.dataTransfer.files.length > 0) {
files = event.dataTransfer.files;
} else if(event.target.files) { // handle input type file
files = event.target.files;
}
if(typeof this.props.onDrop === 'function' && files) {
this.props.onDrop(files);
}
},
handleDeleteFile(fileId) {
// input's value is not change the second time someone
// inputs the same file again, therefore we need to reset its value
this.refs.fileinput.getDOMNode().value = '';
this.props.handleDeleteFile(fileId);
},
handleCancelFile(fileId) {
// input's value is not change the second time someone
// inputs the same file again, therefore we need to reset its value
this.refs.fileinput.getDOMNode().value = '';
this.props.handleCancelFile(fileId);
},
handlePauseFile(fileId) {
// input's value is not change the second time someone
// inputs the same file again, therefore we need to reset its value
this.refs.fileinput.getDOMNode().value = '';
this.props.handlePauseFile(fileId);
},
handleResumeFile(fileId) {
// input's value is not change the second time someone
// inputs the same file again, therefore we need to reset its value
this.refs.fileinput.getDOMNode().value = '';
this.props.handleResumeFile(fileId);
},
handleOnClick() {
let evt;
// when multiple is set to false and the user already uploaded a piece,
// do not propagate event
if(this.props.dropzoneInactive) {
// if there is a handle function for doing stuff
// when the dropzone is inactive, then call it
if(this.props.onInactive) {
this.props.onInactive();
}
return;
}
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);
}
this.refs.fileinput.getDOMNode().dispatchEvent(evt);
},
render: function () {
const {
filesToUpload,
dropzoneInactive,
className,
hashingProgress,
handleCancelHashing,
multiple,
enableLocalHashing,
uploadMethod,
fileClassToUpload,
areAssetsDownloadable,
areAssetsEditable,
allowedExtensions } = this.props;
// has files only is true if there are files that do not have the status deleted or canceled
let hasFiles = filesToUpload.filter((file) => file.status !== 'deleted' && file.status !== 'canceled' && file.size !== -1).length > 0;
let updatedClassName = hasFiles ? 'has-files ' : '';
updatedClassName += dropzoneInactive ? 'inactive-dropzone' : 'active-dropzone';
updatedClassName += ' file-drag-and-drop';
// if !== -2: triggers a FileDragAndDrop-global spinner
if(hashingProgress !== -2) {
return (
<div className={className}>
<div className="file-drag-and-drop-hashing-dialog">
<p>{getLangText('Computing hash(es)... This may take a few minutes.')}</p>
<p>
<a onClick={handleCancelHashing}> {getLangText('Cancel hashing')}</a>
</p>
<ProgressBar
now={Math.ceil(hashingProgress)}
label="%(percent)s%"
className="ascribe-progress-bar"/>
</div>
</div>
);
} else {
return (
<div
className={updatedClassName}
onDrag={this.handleDrop}
onDragOver={this.handleDragOver}
onDrop={this.handleDrop}>
<FileDragAndDropDialog
multipleFiles={multiple}
hasFiles={hasFiles}
onClick={this.handleOnClick}
enableLocalHashing={enableLocalHashing}
uploadMethod={uploadMethod}
fileClassToUpload={fileClassToUpload} />
<FileDragAndDropPreviewIterator
files={filesToUpload}
handleDeleteFile={this.handleDeleteFile}
handleCancelFile={this.handleCancelFile}
handlePauseFile={this.handlePauseFile}
handleResumeFile={this.handleResumeFile}
areAssetsDownloadable={areAssetsDownloadable}
areAssetsEditable={areAssetsEditable}/>
{/*
Opera doesn't trigger simulated click events
if the targeted input has `display:none` set.
Which means we need to set its visibility to hidden
instead of using `display:none`.
See:
- http://stackoverflow.com/questions/12880604/jquery-triggerclick-not-working-on-opera-if-the-element-is-not-displayed
*/}
<input
multiple={multiple}
ref="fileinput"
type="file"
style={{
visibility: 'hidden',
position: 'absolute',
top: 0,
height: 0,
width: 0
}}
onChange={this.handleDrop}
accept={allowedExtensions}/>
</div>
);
}
}
});
export default FileDragAndDrop;