mirror of
https://github.com/ascribe/onion.git
synced 2024-11-15 01:25:17 +01:00
Merge remote-tracking branch 'remotes/origin/AD-496-add-control-buttons-to-fineupload' into AD-368-harmonize-functionality-of-ascrib
This commit is contained in:
commit
fe4d4c6a72
@ -15,7 +15,6 @@ class CoaActions {
|
||||
CoaFetcher.fetchOne(id)
|
||||
.then((res) => {
|
||||
this.actions.updateCoa(res.coa);
|
||||
console.log(res.coa);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
@ -25,7 +24,6 @@ class CoaActions {
|
||||
CoaFetcher.create(edition.bitcoin_id)
|
||||
.then((res) => {
|
||||
this.actions.updateCoa(res.coa);
|
||||
console.log(res.coa);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
|
@ -16,6 +16,10 @@ let AccordionList = React.createClass({
|
||||
{this.props.children}
|
||||
</div>
|
||||
);
|
||||
} else if(this.props.itemList.length === 0) {
|
||||
return (
|
||||
<p className="text-center">You don't have any works yet...</p>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<div className={this.props.className + ' ascribe-accordion-list-loading'}>
|
||||
|
@ -4,8 +4,10 @@ import React from 'react';
|
||||
import FileDragAndDropPreviewIterator from './file_drag_and_drop_preview_iterator';
|
||||
|
||||
|
||||
let ReactTestUtils = React.addons.TestUtils;
|
||||
|
||||
// Taken from: https://github.com/fedosejev/react-file-drag-and-drop
|
||||
var FileDragAndDrop = React.createClass({
|
||||
let FileDragAndDrop = React.createClass({
|
||||
propTypes: {
|
||||
className: React.PropTypes.string,
|
||||
onDragStart: React.PropTypes.func,
|
||||
@ -19,8 +21,11 @@ var FileDragAndDrop = React.createClass({
|
||||
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
|
||||
dropzoneInactive: React.PropTypes.bool,
|
||||
areAssetsDownloadable: React.PropTypes.bool
|
||||
},
|
||||
|
||||
handleDragStart(event) {
|
||||
@ -93,6 +98,20 @@ var FileDragAndDrop = React.createClass({
|
||||
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() {
|
||||
// when multiple is set to false and the user already uploaded a piece,
|
||||
// do not propagate event
|
||||
@ -100,10 +119,16 @@ var FileDragAndDrop = React.createClass({
|
||||
return;
|
||||
}
|
||||
|
||||
// Simulate click on hidden file input
|
||||
var event = document.createEvent('HTMLEvents');
|
||||
event.initEvent('click', false, true);
|
||||
this.refs.fileinput.getDOMNode().dispatchEvent(event);
|
||||
// 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);
|
||||
},
|
||||
|
||||
render: function () {
|
||||
@ -128,7 +153,10 @@ var FileDragAndDrop = React.createClass({
|
||||
<FileDragAndDropPreviewIterator
|
||||
files={this.props.filesToUpload}
|
||||
handleDeleteFile={this.handleDeleteFile}
|
||||
handleCancelFile={this.handleCancelFile}/>
|
||||
handleCancelFile={this.handleCancelFile}
|
||||
handlePauseFile={this.handlePauseFile}
|
||||
handleResumeFile={this.handleResumeFile}
|
||||
areAssetsDownloadable={this.props.areAssetsDownloadable}/>
|
||||
<input
|
||||
multiple={this.props.multiple}
|
||||
ref="fileinput"
|
||||
|
@ -14,11 +14,18 @@ let FileDragAndDropPreview = React.createClass({
|
||||
type: React.PropTypes.string
|
||||
}).isRequired,
|
||||
handleDeleteFile: React.PropTypes.func,
|
||||
handleCancelFile: React.PropTypes.func
|
||||
handleCancelFile: React.PropTypes.func,
|
||||
handlePauseFile: React.PropTypes.func,
|
||||
handleResumeFile: React.PropTypes.func,
|
||||
areAssetsDownloadable: React.PropTypes.bool
|
||||
},
|
||||
|
||||
toggleUploadProcess() {
|
||||
|
||||
if(this.props.file.status === 'uploading') {
|
||||
this.props.handlePauseFile(this.props.file.id);
|
||||
} else if(this.props.file.status === 'paused') {
|
||||
this.props.handleResumeFile(this.props.file.id);
|
||||
}
|
||||
},
|
||||
|
||||
handleDeleteFile() {
|
||||
@ -45,18 +52,23 @@ let FileDragAndDropPreview = React.createClass({
|
||||
onClick={this.handleDeleteFile}
|
||||
progress={this.props.file.progress}
|
||||
url={this.props.file.url}
|
||||
toggleUploadProcess={this.toggleUploadProcess}/>);
|
||||
toggleUploadProcess={this.toggleUploadProcess}
|
||||
areAssetsDownloadable={this.props.areAssetsDownloadable}/>);
|
||||
} else {
|
||||
previewElement = (<FileDragAndDropPreviewOther
|
||||
onClick={this.handleDeleteFile}
|
||||
progress={this.props.file.progress}
|
||||
type={this.props.file.type.split('/')[1]}
|
||||
toggleUploadProcess={this.toggleUploadProcess}/>);
|
||||
toggleUploadProcess={this.toggleUploadProcess}
|
||||
areAssetsDownloadable={this.props.areAssetsDownloadable}/>);
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className="file-drag-and-drop-position">
|
||||
<div className="delete-file">
|
||||
<span className="glyphicon glyphicon-remove text-center" aria-hidden="true" title="Remove file" onClick={this.handleDeleteFile}/>
|
||||
</div>
|
||||
{previewElement}
|
||||
</div>
|
||||
);
|
||||
|
@ -3,12 +3,15 @@
|
||||
import React from 'react';
|
||||
import ProgressBar from 'react-progressbar';
|
||||
|
||||
import AppConstants from '../../constants/application_constants';
|
||||
|
||||
let FileDragAndDropPreviewImage = React.createClass({
|
||||
propTypes: {
|
||||
progress: React.PropTypes.number,
|
||||
url: React.PropTypes.string,
|
||||
toggleUploadProcess: React.PropTypes.func,
|
||||
downloadFile: React.PropTypes.func
|
||||
downloadFile: React.PropTypes.func,
|
||||
areAssetsDownloadable: React.PropTypes.bool
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
@ -17,28 +20,19 @@ let FileDragAndDropPreviewImage = React.createClass({
|
||||
};
|
||||
},
|
||||
|
||||
/*onClick(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
this.setState({
|
||||
loading: true
|
||||
});
|
||||
|
||||
this.props.onClick(e);
|
||||
},*/
|
||||
|
||||
toggleUploadProcess(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
this.setState({
|
||||
paused: true
|
||||
paused: !this.state.paused
|
||||
});
|
||||
|
||||
this.props.toggleUploadProcess();
|
||||
},
|
||||
|
||||
downloadFile() {
|
||||
|
||||
console.log('implement this');
|
||||
},
|
||||
|
||||
render() {
|
||||
@ -49,14 +43,22 @@ let FileDragAndDropPreviewImage = React.createClass({
|
||||
|
||||
let actionSymbol;
|
||||
|
||||
if(this.props.progress !== 100 && this.state.paused) {
|
||||
if(this.props.progress > 0 && this.props.progress < 99 && this.state.paused) {
|
||||
actionSymbol = <span className="glyphicon glyphicon-pause action-file" aria-hidden="true" title="Pause upload" onClick={this.toggleUploadProcess}/>;
|
||||
} else if(this.props.progress !== 100 && !this.state.paused) {
|
||||
} else if(this.props.progress > 0 && this.props.progress < 99 && !this.state.paused) {
|
||||
actionSymbol = <span className="glyphicon glyphicon-play action-file" aria-hidden="true" title="Resume uploading" onClick={this.toggleUploadProcess}/>;
|
||||
} else {
|
||||
} else if(this.props.progress === 100) {
|
||||
|
||||
// only if assets are actually downloadable, there should be a download icon if the process is already at
|
||||
// 100%. If not, no actionSymbol should be displayed
|
||||
if(this.props.areAssetsDownloadable) {
|
||||
actionSymbol = <span className="glyphicon glyphicon-download action-file" aria-hidden="true" title="Download file" onClick={this.props.downloadFile}/>;
|
||||
}
|
||||
|
||||
} else {
|
||||
actionSymbol = <img height={35} className="action-file" src={AppConstants.baseUrl + 'static/img/ascribe_animated_medium.gif'} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className="file-drag-and-drop-preview-image"
|
||||
|
@ -8,7 +8,10 @@ let FileDragAndDropPreviewIterator = React.createClass({
|
||||
propTypes: {
|
||||
files: React.PropTypes.array,
|
||||
handleDeleteFile: React.PropTypes.func,
|
||||
handleCancelFile: React.PropTypes.func
|
||||
handleCancelFile: React.PropTypes.func,
|
||||
handlePauseFile: React.PropTypes.func,
|
||||
handleResumeFile: React.PropTypes.func,
|
||||
areAssetsDownloadable: React.PropTypes.bool
|
||||
},
|
||||
|
||||
render() {
|
||||
@ -22,7 +25,10 @@ let FileDragAndDropPreviewIterator = React.createClass({
|
||||
key={i}
|
||||
file={file}
|
||||
handleDeleteFile={this.props.handleDeleteFile}
|
||||
handleCancelFile={this.props.handleCancelFile}/>
|
||||
handleCancelFile={this.props.handleCancelFile}
|
||||
handlePauseFile={this.props.handlePauseFile}
|
||||
handleResumeFile={this.props.handleResumeFile}
|
||||
areAssetsDownloadable={this.props.areAssetsDownloadable}/>
|
||||
);
|
||||
} else {
|
||||
return null;
|
||||
|
@ -9,35 +9,59 @@ let FileDragAndDropPreviewOther = React.createClass({
|
||||
propTypes: {
|
||||
type: React.PropTypes.string,
|
||||
progress: React.PropTypes.number,
|
||||
onClick: React.PropTypes.func
|
||||
areAssetsDownloadable: React.PropTypes.bool,
|
||||
toggleUploadProcess: React.PropTypes.func,
|
||||
downloadFile: React.PropTypes.func,
|
||||
},
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
loading: false
|
||||
paused: true
|
||||
};
|
||||
},
|
||||
|
||||
onClick(e) {
|
||||
toggleUploadProcess(e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
this.setState({
|
||||
loading: true
|
||||
paused: !this.state.paused
|
||||
});
|
||||
|
||||
this.props.onClick(e);
|
||||
this.props.toggleUploadProcess();
|
||||
},
|
||||
|
||||
downloadFile() {
|
||||
console.log('implement this');
|
||||
},
|
||||
|
||||
render() {
|
||||
//let actionSymbol = this.state.loading ? <img src={AppConstants.baseUrl + 'static/img/ascribe_animated_medium.gif'} /> : <span className="glyphicon glyphicon-remove delete-file" aria-hidden="true" title="Delete or cancel upload" onClick={this.onClick} />;
|
||||
|
||||
let actionSymbol;
|
||||
|
||||
if(this.props.progress > 0 && this.props.progress < 99 && this.state.paused) {
|
||||
actionSymbol = <span className="glyphicon glyphicon-pause action-file" aria-hidden="true" title="Pause upload" onClick={this.toggleUploadProcess}/>;
|
||||
} else if(this.props.progress > 0 && this.props.progress < 99 && !this.state.paused) {
|
||||
actionSymbol = <span className="glyphicon glyphicon-play action-file" aria-hidden="true" title="Resume uploading" onClick={this.toggleUploadProcess}/>;
|
||||
} else if(this.props.progress === 100) {
|
||||
|
||||
// only if assets are actually downloadable, there should be a download icon if the process is already at
|
||||
// 100%. If not, no actionSymbol should be displayed
|
||||
if(this.props.areAssetsDownloadable) {
|
||||
actionSymbol = <span className="glyphicon glyphicon-download action-file" aria-hidden="true" title="Download file" onClick={this.props.downloadFile}/>;
|
||||
}
|
||||
|
||||
} else {
|
||||
actionSymbol = <img height={35} src={AppConstants.baseUrl + 'static/img/ascribe_animated_medium.gif'} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className="file-drag-and-drop-preview">
|
||||
<ProgressBar completed={this.props.progress} color="black"/>
|
||||
<div className="file-drag-and-drop-preview-table-wrapper">
|
||||
<div className="file-drag-and-drop-preview-other">
|
||||
<span className="glyphicon glyphicon-pause delete-file" aria-hidden="true" title="Delete or cancel upload"/>
|
||||
{actionSymbol}
|
||||
<span>{'.' + this.props.type}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -9,6 +9,7 @@ import fetch from 'isomorphic-fetch';
|
||||
import AppConstants from '../../constants/application_constants';
|
||||
|
||||
import { getCookie } from '../../utils/fetch_api_utils';
|
||||
import S3Fetcher from '../../fetchers/s3_fetcher';
|
||||
|
||||
import fineUploader from 'fineUploader';
|
||||
import FileDragAndDrop from './file_drag_and_drop';
|
||||
@ -82,8 +83,9 @@ var ReactS3FineUploader = React.createClass({
|
||||
retry: React.PropTypes.shape({
|
||||
enableAuto: React.PropTypes.bool
|
||||
}),
|
||||
setUploadStatus: React.PropTypes.func,
|
||||
isReadyForFormSubmission: React.PropTypes.func
|
||||
setIsUploadReady: React.PropTypes.func,
|
||||
isReadyForFormSubmission: React.PropTypes.func,
|
||||
areAssetsDownloadable: React.PropTypes.bool
|
||||
},
|
||||
|
||||
getDefaultProps() {
|
||||
@ -183,7 +185,8 @@ var ReactS3FineUploader = React.createClass({
|
||||
onRetry: this.onRetry,
|
||||
onAutoRetry: this.onAutoRetry,
|
||||
onManualRetry: this.onManualRetry,
|
||||
onDeleteComplete: this.onDeleteComplete
|
||||
onDeleteComplete: this.onDeleteComplete,
|
||||
onSessionRequestComplete: this.onSessionRequestComplete
|
||||
}
|
||||
};
|
||||
},
|
||||
@ -247,9 +250,9 @@ var ReactS3FineUploader = React.createClass({
|
||||
// the form is ready for submission or not
|
||||
if(this.props.isReadyForFormSubmission && this.props.isReadyForFormSubmission(this.state.filesToUpload)) {
|
||||
// if so, set uploadstatus to true
|
||||
this.props.setUploadStatus(true);
|
||||
this.props.setIsUploadReady(true);
|
||||
} else {
|
||||
this.props.setUploadStatus(false);
|
||||
this.props.setIsUploadReady(false);
|
||||
}
|
||||
},
|
||||
|
||||
@ -305,9 +308,9 @@ var ReactS3FineUploader = React.createClass({
|
||||
|
||||
if(this.props.isReadyForFormSubmission && this.props.isReadyForFormSubmission(this.state.filesToUpload)) {
|
||||
// if so, set uploadstatus to true
|
||||
this.props.setUploadStatus(true);
|
||||
this.props.setIsUploadReady(true);
|
||||
} else {
|
||||
this.props.setUploadStatus(false);
|
||||
this.props.setIsUploadReady(false);
|
||||
}
|
||||
},
|
||||
|
||||
@ -324,14 +327,14 @@ var ReactS3FineUploader = React.createClass({
|
||||
|
||||
if(this.props.isReadyForFormSubmission && this.props.isReadyForFormSubmission(this.state.filesToUpload)) {
|
||||
// if so, set uploadstatus to true
|
||||
this.props.setUploadStatus(true);
|
||||
this.props.setIsUploadReady(true);
|
||||
} else {
|
||||
this.props.setUploadStatus(false);
|
||||
this.props.setIsUploadReady(false);
|
||||
}
|
||||
},
|
||||
|
||||
onProgress(id, name, uploadedBytes, totalBytes) {
|
||||
var newState = React.addons.update(this.state, {
|
||||
let newState = React.addons.update(this.state, {
|
||||
filesToUpload: { [id]: {
|
||||
progress: { $set: (uploadedBytes / totalBytes) * 100} }
|
||||
}
|
||||
@ -339,18 +342,84 @@ var ReactS3FineUploader = React.createClass({
|
||||
this.setState(newState);
|
||||
},
|
||||
|
||||
onSessionRequestComplete(response, success) {
|
||||
if(success) {
|
||||
// fetch blobs for images
|
||||
response = response.map((file) => {
|
||||
file.url = file.s3Url;
|
||||
file.status = 'online';
|
||||
file.progress = 100;
|
||||
return file;
|
||||
});
|
||||
|
||||
// add file to filesToUpload
|
||||
let updatedFilesToUpload = this.state.filesToUpload.concat(response);
|
||||
|
||||
// refresh all files ids,
|
||||
updatedFilesToUpload = updatedFilesToUpload.map((file, i) => {
|
||||
file.id = i;
|
||||
return file;
|
||||
});
|
||||
|
||||
let newState = React.addons.update(this.state, {filesToUpload: {$set: updatedFilesToUpload}});
|
||||
this.setState(newState);
|
||||
} else {
|
||||
let notification = new GlobalNotificationModel('Could not load attached files (Further data)', 'success', 5000);
|
||||
GlobalNotificationActions.appendGlobalNotification(notification);
|
||||
|
||||
throw new Error('The session request failed', response);
|
||||
}
|
||||
},
|
||||
|
||||
handleDeleteFile(fileId) {
|
||||
// In some instances (when the file was already uploaded and is just displayed to the user)
|
||||
// fineuploader does not register an id on the file (we do, don't be confused by this!).
|
||||
// Since you can only delete a file by its id, we have to implement this method ourselves
|
||||
//
|
||||
// So, if an id is not present, we delete the file manually
|
||||
// To check which files are already uploaded from previous sessions we check their status.
|
||||
// If they are, it is "online"
|
||||
|
||||
if(this.state.filesToUpload[fileId].status !== 'online') {
|
||||
// delete file from server
|
||||
this.state.uploader.deleteFile(fileId);
|
||||
// this is being continues in onDeleteFile, as
|
||||
// fineuploaders deleteFile does not return a correct callback or
|
||||
// promise
|
||||
} else {
|
||||
let fileToDelete = this.state.filesToUpload[fileId];
|
||||
S3Fetcher
|
||||
.deleteFile(fileToDelete.s3Key, fileToDelete.s3Bucket)
|
||||
.then((res) => {
|
||||
console.log(res);
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
handleCancelFile(fileId) {
|
||||
this.state.uploader.cancel(fileId);
|
||||
},
|
||||
|
||||
handlePauseFile(fileId) {
|
||||
if(this.state.uploader.pauseUpload(fileId)) {
|
||||
this.setStatusOfFile(fileId, 'paused');
|
||||
} else {
|
||||
throw new Error('File upload could not be paused.');
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
handleResumeFile(fileId) {
|
||||
if(this.state.uploader.continueUpload(fileId)) {
|
||||
this.setStatusOfFile(fileId, 'uploading');
|
||||
} else {
|
||||
throw new Error('File upload could not be resumed.');
|
||||
}
|
||||
},
|
||||
|
||||
handleUploadFile(files) {
|
||||
|
||||
// If multiple set and user already uploaded its work,
|
||||
@ -420,6 +489,20 @@ var ReactS3FineUploader = React.createClass({
|
||||
this.setState(newState);
|
||||
},
|
||||
|
||||
setStatusOfFile(fileId, status) {
|
||||
// also, sync files from state with the ones from fineuploader
|
||||
let filesToUpload = JSON.parse(JSON.stringify(this.state.filesToUpload));
|
||||
|
||||
// splice because I can
|
||||
filesToUpload[fileId].status = status;
|
||||
|
||||
// set state
|
||||
let newState = React.addons.update(this.state, {
|
||||
filesToUpload: { $set: filesToUpload }
|
||||
});
|
||||
this.setState(newState);
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
@ -429,7 +512,10 @@ var ReactS3FineUploader = React.createClass({
|
||||
filesToUpload={this.state.filesToUpload}
|
||||
handleDeleteFile={this.handleDeleteFile}
|
||||
handleCancelFile={this.handleCancelFile}
|
||||
handlePauseFile={this.handlePauseFile}
|
||||
handleResumeFile={this.handleResumeFile}
|
||||
multiple={this.props.multiple}
|
||||
areAssetsDownloadable={this.props.areAssetsDownloadable}
|
||||
dropzoneInactive={!this.props.multiple && this.state.filesToUpload.filter((file) => file.status !== 'deleted' && file.status !== 'canceled').length > 0} />
|
||||
</div>
|
||||
);
|
||||
|
@ -253,7 +253,7 @@ let EditionSummary = React.createClass({
|
||||
<Row>
|
||||
<Col md={12}>
|
||||
<AclButtonList
|
||||
className="pull-left"
|
||||
className="text-center"
|
||||
availableAcls={this.props.edition.acl}
|
||||
editions={[this.props.edition]}
|
||||
handleSuccess={this.handleSuccess} />
|
||||
@ -455,9 +455,9 @@ let EditionFurtherDetails = React.createClass({
|
||||
});
|
||||
},
|
||||
|
||||
setUploadStatus(isReady) {
|
||||
setIsUploadReady(isReady) {
|
||||
this.setState({
|
||||
uploadStatus: isReady
|
||||
isUploadReady: isReady
|
||||
});
|
||||
},
|
||||
|
||||
@ -495,7 +495,7 @@ let EditionFurtherDetails = React.createClass({
|
||||
edition={this.props.edition} />
|
||||
<FileUploader
|
||||
submitKey={this.submitKey}
|
||||
setUploadStatus={this.setUploadStatus}
|
||||
setIsUploadReady={this.setIsUploadReady}
|
||||
isReadyForFormSubmission={this.isReadyForFormSubmission}
|
||||
edition={this.props.edition}/>
|
||||
</Col>
|
||||
@ -506,7 +506,8 @@ let EditionFurtherDetails = React.createClass({
|
||||
|
||||
let FileUploader = React.createClass({
|
||||
propTypes: {
|
||||
setUploadStatus: React.PropTypes.func,
|
||||
edition: React.PropTypes.object,
|
||||
setIsUploadReady: React.PropTypes.func,
|
||||
submitKey: React.PropTypes.func,
|
||||
isReadyForFormSubmission: React.PropTypes.func
|
||||
},
|
||||
@ -528,7 +529,7 @@ let FileUploader = React.createClass({
|
||||
sizeLimit: '10000000'
|
||||
}}
|
||||
submitKey={this.props.submitKey}
|
||||
setUploadStatus={this.props.setUploadStatus}
|
||||
setIsUploadReady={this.props.setIsUploadReady}
|
||||
isReadyForFormSubmission={this.props.isReadyForFormSubmission}
|
||||
session={{
|
||||
endpoint: AppConstants.serverUrl + 'api/blob/otherdatas/fineuploader_session/',
|
||||
@ -536,9 +537,10 @@ let FileUploader = React.createClass({
|
||||
'X-CSRFToken': getCookie('csrftoken')
|
||||
},
|
||||
params: {
|
||||
'pk': this.props.edition.other_data.id
|
||||
'pk': this.props.edition.other_data ? this.props.edition.other_data.id : null
|
||||
}
|
||||
}}/>
|
||||
}}
|
||||
areAssetsDownloadable={true}/>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
@ -71,9 +71,9 @@ let RegisterPiece = React.createClass( {
|
||||
});
|
||||
},
|
||||
|
||||
setUploadStatus(isReady) {
|
||||
setIsUploadReady(isReady) {
|
||||
this.setState({
|
||||
uploadStatus: isReady
|
||||
isUploadReady: isReady
|
||||
});
|
||||
},
|
||||
|
||||
@ -118,15 +118,6 @@ let RegisterPiece = React.createClass( {
|
||||
},
|
||||
|
||||
render() {
|
||||
let buttons = <span />;
|
||||
|
||||
if (this.state.uploadStatus){
|
||||
buttons = (
|
||||
<button type="submit" className="btn ascribe-btn ascribe-btn-login">
|
||||
Register your artwork
|
||||
</button>);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="row ascribe-row">
|
||||
<div className="col-md-12">
|
||||
@ -136,7 +127,12 @@ let RegisterPiece = React.createClass( {
|
||||
url={apiUrls.pieces_list}
|
||||
getFormData={this.getFormData}
|
||||
handleSuccess={this.handleSuccess}
|
||||
buttons={buttons}
|
||||
buttons={<button
|
||||
type="submit"
|
||||
className="btn ascribe-btn ascribe-btn-login"
|
||||
disabled={!this.state.isUploadReady}>
|
||||
Register your artwork
|
||||
</button>}
|
||||
spinner={
|
||||
<button className="btn ascribe-btn ascribe-btn-login ascribe-btn-login-spinner">
|
||||
<img src="https://s3-us-west-2.amazonaws.com/ascribe0/media/thumbnails/ascribe_animated_medium.gif" />
|
||||
@ -146,7 +142,7 @@ let RegisterPiece = React.createClass( {
|
||||
label="Files to upload">
|
||||
<FileUploader
|
||||
submitKey={this.submitKey}
|
||||
setUploadStatus={this.setUploadStatus}
|
||||
setIsUploadReady={this.setIsUploadReady}
|
||||
isReadyForFormSubmission={this.isReadyForFormSubmission}/>
|
||||
</Property>
|
||||
<Property
|
||||
@ -195,7 +191,7 @@ let RegisterPiece = React.createClass( {
|
||||
|
||||
let FileUploader = React.createClass({
|
||||
propTypes: {
|
||||
setUploadStatus: React.PropTypes.func,
|
||||
setIsUploadReady: React.PropTypes.func,
|
||||
submitKey: React.PropTypes.func,
|
||||
isReadyForFormSubmission: React.PropTypes.func
|
||||
},
|
||||
@ -215,8 +211,9 @@ let FileUploader = React.createClass({
|
||||
itemLimit: 100000,
|
||||
sizeLimit: '25000000000'
|
||||
}}
|
||||
setUploadStatus={this.props.setUploadStatus}
|
||||
isReadyForFormSubmission={this.props.isReadyForFormSubmission}/>
|
||||
setIsUploadReady={this.props.setIsUploadReady}
|
||||
isReadyForFormSubmission={this.props.isReadyForFormSubmission}
|
||||
areAssetsDownloadable={false}/>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
@ -40,7 +40,8 @@ let apiUrls = {
|
||||
'users_signup': AppConstants.apiEndpoint + 'users/',
|
||||
'users_username': AppConstants.apiEndpoint + 'users/username/',
|
||||
'wallet_settings': AppConstants.apiEndpoint + 'users/wallet_settings/',
|
||||
'whitelabel_settings': AppConstants.apiEndpoint + 'whitelabel/settings/${subdomain}/'
|
||||
'whitelabel_settings': AppConstants.apiEndpoint + 'whitelabel/settings/${subdomain}/',
|
||||
'delete_s3_file': AppConstants.serverUrl + 's3/delete/'
|
||||
};
|
||||
|
||||
export default apiUrls;
|
||||
|
17
js/fetchers/s3_fetcher.js
Normal file
17
js/fetchers/s3_fetcher.js
Normal file
@ -0,0 +1,17 @@
|
||||
'use strict';
|
||||
|
||||
import requests from '../utils/requests';
|
||||
|
||||
let S3Fetcher = {
|
||||
/**
|
||||
* Fetch the registered applications of a user from the API.
|
||||
*/
|
||||
deleteFile(key, bucket) {
|
||||
return requests.delete('delete_s3_file', {
|
||||
key,
|
||||
bucket
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
export default S3Fetcher;
|
@ -70,3 +70,38 @@ export function getCookie(name) {
|
||||
return parts.pop().split(';').shift();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Given a url for an image, this method fetches it and returns a promise that resolves to
|
||||
a blob object.
|
||||
It can be used to create a 64base encoded data url.
|
||||
|
||||
Taken from: http://jsfiddle.net/jan_miksovsky/yy7zs/
|
||||
|
||||
*/
|
||||
export function fetchImageAsBlob(url) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let xhr = new XMLHttpRequest();
|
||||
|
||||
xhr.open('GET', url, true);
|
||||
|
||||
// Ask for the result as an ArrayBuffer.
|
||||
xhr.responseType = 'arraybuffer';
|
||||
|
||||
xhr.onreadystatechange = function() {
|
||||
if(xhr.readyState === 4 && xhr.status >= 400) {
|
||||
reject(xhr.statusText);
|
||||
}
|
||||
};
|
||||
|
||||
xhr.onload = function() {
|
||||
// Obtain a blob: URL for the image data.
|
||||
let arrayBufferView = new Uint8Array(this.response);
|
||||
let blob = new Blob([arrayBufferView], {type: 'image/jpeg'});
|
||||
resolve(blob);
|
||||
};
|
||||
|
||||
xhr.send();
|
||||
});
|
||||
}
|
@ -43,9 +43,29 @@
|
||||
}
|
||||
|
||||
.file-drag-and-drop-position {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
margin: 0 0 4% 4%;
|
||||
float:left;
|
||||
|
||||
.delete-file {
|
||||
display: block;
|
||||
background-color: black;
|
||||
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
position: absolute;
|
||||
right: -7px;
|
||||
top: -7px;
|
||||
border-radius: 1em;
|
||||
text-align: center;
|
||||
|
||||
cursor: pointer;
|
||||
|
||||
span {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.file-drag-and-drop-preview-table-wrapper {
|
||||
|
@ -1,3 +1,6 @@
|
||||
$ascribe-color: rgba(2, 182, 163, 0.5);
|
||||
$ascribe-color-dark: rgba(2, 182, 163, 0.8);
|
||||
$ascribe-color-full: rgba(2, 182, 163, 1);
|
||||
|
||||
$ascribe-brand-danger: #FC535F;
|
||||
$ascribe-brand-warning: #FFC354;
|
@ -3,8 +3,8 @@
|
||||
|
||||
$BASE_URL: '<%= BASE_URL %>';
|
||||
|
||||
@import 'variables';
|
||||
@import 'ascribe_variables';
|
||||
@import 'variables';
|
||||
@import '../node_modules/bootstrap-sass/assets/stylesheets/bootstrap';
|
||||
@import '../node_modules/react-datepicker/dist/react-datepicker';
|
||||
@import './ascribe-fonts/style';
|
||||
|
@ -18,8 +18,8 @@ $gray-lighter: lighten($gray-base, 93.5%) !default; // #eee
|
||||
$brand-primary: darken(#428bca, 6.5%) !default; // #337ab7
|
||||
$brand-success: #5cb85c !default;
|
||||
$brand-info: #5bc0de !default;
|
||||
$brand-warning: #f0ad4e !default;
|
||||
$brand-danger: #d9534f !default;
|
||||
$brand-warning: $ascribe-brand-warning !default;
|
||||
$brand-danger: $ascribe-brand-danger !default;
|
||||
|
||||
|
||||
//== Scaffolding
|
||||
@ -107,9 +107,9 @@ $padding-xs-horizontal: 5px !default;
|
||||
$line-height-large: 1.3333333 !default; // extra decimals for Win 8.1 Chrome
|
||||
$line-height-small: 1.5 !default;
|
||||
|
||||
$border-radius-base: 4px !default;
|
||||
$border-radius-large: 6px !default;
|
||||
$border-radius-small: 3px !default;
|
||||
$border-radius-base: 0 !default;
|
||||
$border-radius-large: 0 !default;
|
||||
$border-radius-small: 0 !default;
|
||||
|
||||
//** Global color for active items (e.g., navs or dropdowns).
|
||||
$component-active-color: #fff !default;
|
||||
@ -149,9 +149,9 @@ $table-border-color: #ddd !default;
|
||||
|
||||
$btn-font-weight: normal !default;
|
||||
|
||||
$btn-default-color: #333 !default;
|
||||
$btn-default-bg: #fff !default;
|
||||
$btn-default-border: #ccc !default;
|
||||
$btn-default-color: white !default;
|
||||
$btn-default-bg: $ascribe-color-full !default;
|
||||
$btn-default-border: $ascribe-color-full !default;
|
||||
|
||||
$btn-primary-color: #fff !default;
|
||||
$btn-primary-bg: $brand-primary !default;
|
||||
@ -171,7 +171,7 @@ $btn-warning-border: darken($btn-warning-bg, 5%) !default;
|
||||
|
||||
$btn-danger-color: #fff !default;
|
||||
$btn-danger-bg: $brand-danger !default;
|
||||
$btn-danger-border: darken($btn-danger-bg, 5%) !default;
|
||||
$btn-danger-border: $brand-danger !default;
|
||||
|
||||
$btn-link-disabled-color: $gray-light !default;
|
||||
|
||||
@ -186,7 +186,7 @@ $input-bg: #fff !default;
|
||||
$input-bg-disabled: $gray-lighter !default;
|
||||
|
||||
//** Text color for `<input>`s
|
||||
$input-color: $gray !default;
|
||||
$input-color: white !default;
|
||||
//** `<input>` border color
|
||||
$input-border: #ccc !default;
|
||||
|
||||
@ -219,9 +219,9 @@ $legend-color: $gray-dark !default;
|
||||
$legend-border-color: #e5e5e5 !default;
|
||||
|
||||
//** Background color for textual input addons
|
||||
$input-group-addon-bg: $gray-lighter !default;
|
||||
$input-group-addon-bg: $ascribe-color-full !default;
|
||||
//** Border color for textual input addons
|
||||
$input-group-addon-border-color: $input-border !default;
|
||||
$input-group-addon-border-color: $ascribe-color-full !default;
|
||||
|
||||
//** Disabled cursor for form controls and buttons.
|
||||
$cursor-disabled: not-allowed !default;
|
||||
|
Loading…
Reference in New Issue
Block a user