diff --git a/js/components/ascribe_forms/input_fineuploader.js b/js/components/ascribe_forms/input_fineuploader.js
new file mode 100644
index 00000000..52e1d5b5
--- /dev/null
+++ b/js/components/ascribe_forms/input_fineuploader.js
@@ -0,0 +1,95 @@
+'use strict';
+
+import React from 'react';
+
+import ReactS3FineUploader from '../ascribe_uploader/react_s3_fine_uploader';
+
+import AppConstants from '../../constants/application_constants';
+import ApiUrls from '../../constants/api_urls';
+
+import { getCookie } from '../../utils/fetch_api_utils';
+
+let InputFileUploader = React.createClass({
+ propTypes: {
+ setIsUploadReady: React.PropTypes.func,
+ isReadyForFormSubmission: React.PropTypes.func,
+ onClick: React.PropTypes.func,
+
+ // isFineUploaderActive is used to lock react fine uploader in case
+ // a user is actually not logged in already to prevent him from droping files
+ // before login in
+ isFineUploaderActive: React.PropTypes.bool,
+ onLoggedOut: React.PropTypes.func,
+ editable: React.PropTypes.bool,
+ enableLocalHashing: React.PropTypes.bool,
+
+ // provided by Property
+ disabled: React.PropTypes.bool
+ },
+
+ getInitialState() {
+ return {
+ value: null
+ };
+ },
+
+ submitKey(key){
+ this.setState({
+ value: key
+ });
+ },
+
+ reset() {
+ this.refs.fineuploader.reset();
+ },
+
+ render() {
+ let editable = this.props.isFineUploaderActive;
+
+ // if disabled is actually set by property, we want to override
+ // isFineUploaderActive
+ if(typeof this.props.disabled !== 'undefined') {
+ editable = !this.props.disabled;
+ }
+
+ return (
+
+ );
+ }
+});
+
+export default InputFileUploader;
\ No newline at end of file
diff --git a/js/components/ascribe_forms/input_textarea_toggable.js b/js/components/ascribe_forms/input_textarea_toggable.js
index bc70c530..ac3994a7 100644
--- a/js/components/ascribe_forms/input_textarea_toggable.js
+++ b/js/components/ascribe_forms/input_textarea_toggable.js
@@ -4,6 +4,7 @@ import React from 'react';
import TextareaAutosize from 'react-textarea-autosize';
+
let InputTextAreaToggable = React.createClass({
propTypes: {
editable: React.PropTypes.bool.isRequired,
@@ -17,14 +18,17 @@ let InputTextAreaToggable = React.createClass({
value: this.props.defaultValue
};
},
+
handleChange(event) {
this.setState({value: event.target.value});
this.props.onChange(event);
},
+
render() {
let className = 'form-control ascribe-textarea';
let textarea = null;
- if (this.props.editable){
+
+ if(this.props.editable) {
className = className + ' ascribe-textarea-editable';
textarea = (
);
- }
- else{
+ } else {
textarea =
{this.state.value}
;
}
+
return textarea;
}
});
diff --git a/js/components/ascribe_forms/property.js b/js/components/ascribe_forms/property.js
index cfc4c4d9..61c5c96e 100644
--- a/js/components/ascribe_forms/property.js
+++ b/js/components/ascribe_forms/property.js
@@ -29,8 +29,11 @@ let Property = React.createClass({
handleChange: React.PropTypes.func,
ignoreFocus: React.PropTypes.bool,
className: React.PropTypes.string,
+
onClick: React.PropTypes.func,
onChange: React.PropTypes.func,
+ onBlur: React.PropTypes.func,
+
children: React.PropTypes.oneOfType([
React.PropTypes.arrayOf(React.PropTypes.element),
React.PropTypes.element
@@ -96,12 +99,20 @@ let Property = React.createClass({
// resets the value of a plain HTML5 input
this.refs.input.getDOMNode().value = this.state.initialValue;
+ // For some inputs, reseting state.value is not enough to visually reset the
+ // component.
+ //
+ // So if the input actually needs a visual reset, it needs to implement
+ // a dedicated reset method.
+ if(this.refs.input.reset && typeof this.refs.input.reset === 'function') {
+ this.refs.input.reset();
+ }
},
handleChange(event) {
this.props.handleChange(event);
- if ('onChange' in this.props) {
+ if (this.props.onChange && typeof this.props.onChange === 'function') {
this.props.onChange(event);
}
@@ -117,7 +128,7 @@ let Property = React.createClass({
// if onClick is defined from the outside,
// just call it
- if(this.props.onClick) {
+ if(this.props.onClick && typeof this.props.onClick === 'function') {
this.props.onClick();
}
@@ -132,7 +143,7 @@ let Property = React.createClass({
isFocused: false
});
- if(this.props.onBlur) {
+ if(this.props.onBlur && typeof this.props.onBlur === 'function') {
this.props.onBlur(event);
}
},
@@ -190,6 +201,7 @@ let Property = React.createClass({
},
render() {
+ let footer = null;
let tooltip =
;
let style = this.props.style ? mergeOptions({}, this.props.style) : {};
@@ -199,7 +211,7 @@ let Property = React.createClass({
{this.props.tooltip}
);
}
- let footer = null;
+
if(this.props.footer){
footer = (
diff --git a/js/components/ascribe_forms/property_collapsible.js b/js/components/ascribe_forms/property_collapsible.js
index 03ec404d..ef9a1329 100644
--- a/js/components/ascribe_forms/property_collapsible.js
+++ b/js/components/ascribe_forms/property_collapsible.js
@@ -42,6 +42,13 @@ let PropertyCollapsile = React.createClass({
}
},
+ reset() {
+ // If the child input is a native HTML element, it will be reset automatically
+ // by the DOM.
+ // However, we need to collapse this component again.
+ this.setState(this.getInitialState());
+ },
+
render() {
let tooltip =
;
if (this.props.tooltip){
diff --git a/js/components/ascribe_media/media_player.js b/js/components/ascribe_media/media_player.js
index 09fafd27..e767a800 100644
--- a/js/components/ascribe_media/media_player.js
+++ b/js/components/ascribe_media/media_player.js
@@ -28,12 +28,20 @@ let Other = React.createClass({
},
render() {
- let ext = this.props.url.split('.').pop();
+ let filename = this.props.url.split('/').pop();
+ let tokens = filename.split('.');
+ let preview;
+
+ if (tokens.length > 1) {
+ preview = '.' + tokens.pop();
+ } else {
+ preview = 'file';
+ }
return (
- .{ext}
+ {preview}
);
diff --git a/js/components/ascribe_slides_container/slides_container.js b/js/components/ascribe_slides_container/slides_container.js
index 8b800377..84dff61c 100644
--- a/js/components/ascribe_slides_container/slides_container.js
+++ b/js/components/ascribe_slides_container/slides_container.js
@@ -4,13 +4,12 @@ import React from 'react';
import Router from 'react-router';
import ReactAddons from 'react/addons';
-import Col from 'react-bootstrap/lib/Col';
-
import SlidesContainerBreadcrumbs from './slides_container_breadcrumbs';
let State = Router.State;
let Navigation = Router.Navigation;
+
let SlidesContainer = React.createClass({
propTypes: {
children: React.PropTypes.arrayOf(React.PropTypes.element),
@@ -30,12 +29,15 @@ let SlidesContainer = React.createClass({
let slideNum = -1;
let startFrom = -1;
+ // We can actually need to check if slide_num is present as a key in queryParams.
+ // We do not really care about its value though...
if(queryParams && 'slide_num' in queryParams) {
slideNum = parseInt(queryParams.slide_num, 10);
}
// if slide_num is not set, this will be done in componentDidMount
// the query param 'start_from' removes all slide children before the respective number
+ // Also, we use the 'in' keyword for the same reason as above in 'slide_num'
if(queryParams && 'start_from' in queryParams) {
startFrom = parseInt(queryParams.start_from, 10);
}
@@ -51,6 +53,9 @@ let SlidesContainer = React.createClass({
componentDidMount() {
// check if slide_num was defined, and if not then default to 0
let queryParams = this.getQuery();
+
+ // We use 'in' to check if the key is present in the user's browser url bar,
+ // we do not really care about its value at this point
if(!('slide_num' in queryParams)) {
// we're first requiring all the other possible queryParams and then set
diff --git a/js/components/ascribe_uploader/react_s3_fine_uploader.js b/js/components/ascribe_uploader/react_s3_fine_uploader.js
index c2ec9d56..54a7c39c 100644
--- a/js/components/ascribe_uploader/react_s3_fine_uploader.js
+++ b/js/components/ascribe_uploader/react_s3_fine_uploader.js
@@ -20,7 +20,6 @@ import AppConstants from '../../constants/application_constants';
import { computeHashOfFile, displayValidFilesFilter } from '../../utils/file_utils';
var ReactS3FineUploader = React.createClass({
-
propTypes: {
keyRoutine: React.PropTypes.shape({
url: React.PropTypes.string,
@@ -125,6 +124,7 @@ var ReactS3FineUploader = React.createClass({
bucket: 'ascribe0'
},
request: {
+ //endpoint: 'https://www.ascribe.io.global.prod.fastly.net',
endpoint: 'https://ascribe0.s3.amazonaws.com',
accessKey: 'AKIAIVCZJ33WSCBQ3QDA'
},
@@ -235,6 +235,21 @@ var ReactS3FineUploader = React.createClass({
};
},
+ // Resets the whole react fineuploader component to its initial state
+ reset() {
+ // Cancel all currently ongoing uploads
+ this.state.uploader.cancelAll();
+
+ // and reset component in general
+ this.state.uploader.reset();
+
+ // proclaim that upload is not ready
+ this.props.setIsUploadReady(false);
+
+ // reset internal data structures of component
+ this.setState(this.getInitialState());
+ },
+
requestKey(fileId) {
let filename = this.state.uploader.getName(fileId);
let uuid = this.state.uploader.getUuid(fileId);
@@ -349,62 +364,56 @@ var ReactS3FineUploader = React.createClass({
onComplete(id, name, res, xhr) {
// there has been an issue with the server's connection
- if(xhr.status === 0) {
-
- console.logGlobal(new Error('Complete was called but there wasn\t a success'), false, {
+ if((xhr && xhr.status === 0) || res.error) {
+ console.logGlobal(new Error(res.error || 'Complete was called but there wasn\t a success'), false, {
files: this.state.filesToUpload,
chunks: this.state.chunks
});
+ } else {
+ let files = this.state.filesToUpload;
- return;
- }
+ // Set the state of the completed file to 'upload successful' in order to
+ // remove it from the GUI
+ files[id].status = 'upload successful';
+ files[id].key = this.state.uploader.getKey(id);
- let files = this.state.filesToUpload;
+ let filesToUpload = React.addons.update(this.state.filesToUpload, { $set: files });
+ this.setState({ filesToUpload });
- // Set the state of the completed file to 'upload successful' in order to
- // remove it from the GUI
- files[id].status = 'upload successful';
- files[id].key = this.state.uploader.getKey(id);
-
- let filesToUpload = React.addons.update(this.state.filesToUpload, { $set: files });
-
- this.setState({ filesToUpload });
-
- // Only after the blob has been created server-side, we can make the form submittable.
- this.createBlob(files[id])
- .then(() => {
- // since the form validation props isReadyForFormSubmission, setIsUploadReady and submitKey
- // are optional, we'll only trigger them when they're actually defined
- if(this.props.submitKey) {
- this.props.submitKey(files[id].key);
- } else {
- console.warn('You didn\'t define submitKey in as a prop in react-s3-fine-uploader');
- }
-
- // for explanation, check comment of if statement above
- if(this.props.isReadyForFormSubmission && this.props.setIsUploadReady) {
- // also, lets check if after the completion of this upload,
- // the form is ready for submission or not
- if(this.props.isReadyForFormSubmission(this.state.filesToUpload)) {
- // if so, set uploadstatus to true
- this.props.setIsUploadReady(true);
+ // Only after the blob has been created server-side, we can make the form submittable.
+ this.createBlob(files[id])
+ .then(() => {
+ // since the form validation props isReadyForFormSubmission, setIsUploadReady and submitKey
+ // are optional, we'll only trigger them when they're actually defined
+ if(this.props.submitKey) {
+ this.props.submitKey(files[id].key);
} else {
- this.props.setIsUploadReady(false);
+ console.warn('You didn\'t define submitKey in as a prop in react-s3-fine-uploader');
}
- } else {
- console.warn('You didn\'t define the functions isReadyForFormSubmission and/or setIsUploadReady in as a prop in react-s3-fine-uploader');
- }
- })
- .catch((err) => {
- console.logGlobal(err, false, {
- files: this.state.filesToUpload,
- chunks: this.state.chunks
+
+ // for explanation, check comment of if statement above
+ if(this.props.isReadyForFormSubmission && this.props.setIsUploadReady) {
+ // also, lets check if after the completion of this upload,
+ // the form is ready for submission or not
+ if(this.props.isReadyForFormSubmission(this.state.filesToUpload)) {
+ // if so, set uploadstatus to true
+ this.props.setIsUploadReady(true);
+ } else {
+ this.props.setIsUploadReady(false);
+ }
+ } else {
+ console.warn('You didn\'t define the functions isReadyForFormSubmission and/or setIsUploadReady in as a prop in react-s3-fine-uploader');
+ }
+ })
+ .catch((err) => {
+ console.logGlobal(err, false, {
+ files: this.state.filesToUpload,
+ chunks: this.state.chunks
+ });
+ let notification = new GlobalNotificationModel(err.message, 'danger', 5000);
+ GlobalNotificationActions.appendGlobalNotification(notification);
});
- let notification = new GlobalNotificationModel(err.message, 'danger', 5000);
- GlobalNotificationActions.appendGlobalNotification(notification);
- });
-
-
+ }
},
onError(id, name, errorReason) {
diff --git a/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js b/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js
index 4b785fc2..822557db 100644
--- a/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js
+++ b/js/components/whitelabel/prize/components/ascribe_detail/prize_piece_container.js
@@ -90,14 +90,23 @@ let PieceContainer = React.createClass({
},
render() {
- if('title' in this.state.piece) {
+ if(this.state.piece && this.state.piece.title) {
+ /*
+
+ This really needs a refactor!
+
+ - Tim
+
+ */
// Only show the artist name if you are the participant or if you are a judge and the piece is shortlisted
let artistName = ((this.state.currentUser.is_jury && !this.state.currentUser.is_judge) ||
(this.state.currentUser.is_judge && !this.state.piece.selected )) ?
: this.state.piece.artist_name;
+
// Only show the artist email if you are a judge and the piece is shortlisted
let artistEmail = (this.state.currentUser.is_judge && this.state.piece.selected ) ?
: null;
+
return (
{' ' + getLangText('I agree to the Terms of Service of IkonoTV Archive') + ' '}
- (
+ (
{getLangText('read')}
)
diff --git a/js/components/whitelabel/wallet/components/ikonotv/ascribe_detail/ikonotv_piece_container.js b/js/components/whitelabel/wallet/components/ikonotv/ascribe_detail/ikonotv_piece_container.js
index 7f094a26..276cebad 100644
--- a/js/components/whitelabel/wallet/components/ikonotv/ascribe_detail/ikonotv_piece_container.js
+++ b/js/components/whitelabel/wallet/components/ikonotv/ascribe_detail/ikonotv_piece_container.js
@@ -133,7 +133,7 @@ let IkonotvPieceContainer = React.createClass({
},
render() {
- if('title' in this.state.piece) {
+ if(this.state.piece && this.state.piece.title) {
return (