From e71c2f9fe092a05b96d9ea44e16e7c81ecde4f0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Mon, 13 Jul 2015 17:09:44 +0200 Subject: [PATCH 1/5] separate create edition form logic --- .../accordion_list_item.js | 17 ++- .../accordion_list_item_create_editions.js | 51 --------- js/components/ascribe_buttons/acl_button.js | 26 +++-- .../ascribe_buttons/acl_button_list.js | 15 ++- .../ascribe_buttons/create_editions_button.js | 88 +++++++++++---- js/components/ascribe_detail/edition.js | 10 +- js/components/ascribe_detail/header.js | 26 ----- js/components/ascribe_detail/piece.js | 105 +++++++++--------- .../ascribe_forms/create_editions_form.js | 50 +++++++++ js/constants/languages.js | 3 + 10 files changed, 216 insertions(+), 175 deletions(-) delete mode 100644 js/components/ascribe_accordion_list/accordion_list_item_create_editions.js delete mode 100644 js/components/ascribe_detail/header.js create mode 100644 js/components/ascribe_forms/create_editions_form.js diff --git a/js/components/ascribe_accordion_list/accordion_list_item.js b/js/components/ascribe_accordion_list/accordion_list_item.js index 4d057c44..a5e5679d 100644 --- a/js/components/ascribe_accordion_list/accordion_list_item.js +++ b/js/components/ascribe_accordion_list/accordion_list_item.js @@ -8,7 +8,7 @@ import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger'; import Tooltip from 'react-bootstrap/lib/Tooltip'; import AccordionListItemEditionWidget from './accordion_list_item_edition_widget'; -import AccordionListItemCreateEditions from './accordion_list_item_create_editions'; +import CreateEditionsForm from '../ascribe_forms/create_editions_form'; import PieceListActions from '../../actions/piece_list_actions'; import EditionListActions from '../../actions/edition_list_actions'; @@ -101,6 +101,18 @@ let AccordionListItem = React.createClass({ }); }, + getCreateEditionsDialog() { + if(this.props.content.num_editions < 1 && this.state.showCreateEditionsDialog) { + return ( +
+ +
+ ); + } + }, + render() { let linkData; @@ -150,8 +162,9 @@ let AccordionListItem = React.createClass({ - {this.props.content.num_editions < 1 && this.state.showCreateEditionsDialog ? : null} + {this.getCreateEditionsDialog()} + {/* this.props.children is AccordionListItemTableEditions */} {this.props.children} diff --git a/js/components/ascribe_accordion_list/accordion_list_item_create_editions.js b/js/components/ascribe_accordion_list/accordion_list_item_create_editions.js deleted file mode 100644 index 30a6efbc..00000000 --- a/js/components/ascribe_accordion_list/accordion_list_item_create_editions.js +++ /dev/null @@ -1,51 +0,0 @@ -'use strict'; - -import React from 'react'; - -import Form from '../ascribe_forms/form'; -import Property from '../ascribe_forms/property'; - -import apiUrls from '../../constants/api_urls'; -import { getLangText } from '../../utils/lang_utils'; - -let AccordionListItemCreateEditions = React.createClass({ - - propTypes: { - pieceId: React.PropTypes.number, - handleSuccess: React.PropTypes.func - }, - - getFormData(){ - return { - piece_id: parseInt(this.props.pieceId, 10) - }; - }, - - render() { - return ( -
-
- - - }> - - - -
-
- ); - } -}); - -export default AccordionListItemCreateEditions; \ No newline at end of file diff --git a/js/components/ascribe_buttons/acl_button.js b/js/components/ascribe_buttons/acl_button.js index 1e20d0d8..e9d2aa2a 100644 --- a/js/components/ascribe_buttons/acl_button.js +++ b/js/components/ascribe_buttons/acl_button.js @@ -105,6 +105,20 @@ let AclButton = React.createClass({ } }, + getShareMessage(){ + return ( + ` +${getLangText('Hi')}, + +${getLangText('I am sharing')}: +${this.getTitlesString()} ${getLangText('with you')}. + +${getLangText('Truly yours')}, +${this.props.currentUser.username} + ` + ); + }, + render() { let shouldDisplay = this.props.availableAcls.indexOf(this.props.action) > -1; let aclProps = this.actionProperties(); @@ -121,18 +135,6 @@ let AclButton = React.createClass({ { aclProps.form } ); - }, - - getShareMessage(){ - return ( -`${getLangText('Hi')}, - -${getLangText('I am sharing')} : -${this.getTitlesString()}${getLangText('with you')}. - -${getLangText('Truly yours')}, -${this.props.currentUser.username}` - ); } }); diff --git a/js/components/ascribe_buttons/acl_button_list.js b/js/components/ascribe_buttons/acl_button_list.js index eb3dc720..5fb3b224 100644 --- a/js/components/ascribe_buttons/acl_button_list.js +++ b/js/components/ascribe_buttons/acl_button_list.js @@ -7,14 +7,20 @@ import UserStore from '../../stores/user_store'; import AclButton from '../ascribe_buttons/acl_button'; import DeleteButton from '../ascribe_buttons/delete_button'; -import CreateEditionButton from '../ascribe_buttons/create_editions_button'; let AclButtonList = React.createClass({ propTypes: { className: React.PropTypes.string, - editions: React.PropTypes.object, + editions: React.PropTypes.oneOfType([ + React.PropTypes.object, + React.PropTypes.array + ]), availableAcls: React.PropTypes.array, - handleSuccess: React.PropTypes.func + handleSuccess: React.PropTypes.func, + children: React.PropTypes.oneOfType([ + React.PropTypes.arrayOf(React.PropTypes.element), + React.PropTypes.element + ]) }, getInitialState() { @@ -69,8 +75,7 @@ let AclButtonList = React.createClass({ handleSuccess={this.props.handleSuccess} /> - + {this.props.children} ); } diff --git a/js/components/ascribe_buttons/create_editions_button.js b/js/components/ascribe_buttons/create_editions_button.js index 4b189db2..9ccb52cf 100644 --- a/js/components/ascribe_buttons/create_editions_button.js +++ b/js/components/ascribe_buttons/create_editions_button.js @@ -1,42 +1,82 @@ 'use strict'; import React from 'react'; -import Router from 'react-router'; - -import Button from 'react-bootstrap/lib/Button'; - -import EditionDeleteForm from '../ascribe_forms/form_delete_edition'; -import EditionRemoveFromCollectionForm from '../ascribe_forms/form_remove_editions_from_collection'; -import ModalWrapper from '../ascribe_modal/modal_wrapper'; -import AccordionListItemCreateEditions from './../ascribe_accordion_list/accordion_list_item_create_editions'; -import GlobalNotificationModel from '../../models/global_notification_model'; -import GlobalNotificationActions from '../../actions/global_notification_actions'; - -import { getAvailableAcls } from '../../utils/acl_utils'; -import { getLangText } from '../../utils/lang_utils.js' import EditionListActions from '../../actions/edition_list_actions'; +import PieceListActions from '../../actions/piece_list_actions'; + +import { getAvailableAcls } from '../../utils/acl_utils'; let CreateEditionsButton = React.createClass({ propTypes: { - piece: React.PropTypes.object.isRequired + piece: React.PropTypes.object.isRequired, + toggleCreateEditionsDialog: React.PropTypes.func.isRequired }, - mixins: [Router.Navigation], + getInitialState() { + return {}; + }, + + componentDidUpdate() { + if(this.props.piece.num_editions === 0 && typeof this.state.pollingIntervalIndex === 'undefined') { + this.startPolling(); + } + }, + + componentWillUnmount() { + clearInterval(this.state.pollingIntervalIndex); + }, + + startPolling() { + // start polling until editions are defined + let pollingIntervalIndex = setInterval(() => { + EditionListActions.fetchEditionList(this.props.piece.id) + .then((res) => { + + clearInterval(this.state.pollingIntervalIndex); + + PieceListActions.updatePropertyForPiece({ + pieceId: this.props.piece.id, + key: 'num_editions', + value: res.editions[0].num_editions + }); + + EditionListActions.toggleEditionList(this.props.piece.id); + + }) + .catch(() => { + /* Ignore and keep going */ + }); + }, 5000); + + this.setState({ + pollingIntervalIndex + }); + }, render: function () { - if (this.props.piece.constructor === Array){ + let piece = this.props.piece; + + let availableAcls = getAvailableAcls(piece); + if (availableAcls.indexOf('editions') < -1 || piece.num_editions > 0){ return null; } - let availableAcls = getAvailableAcls([this.props.piece]); - if (availableAcls.indexOf('editions') === -1){ - return null; + + if(piece.num_editions === 0) { + return ( + + ); + } else { + return ( + + ); } - return ( - - ); } }); diff --git a/js/components/ascribe_detail/edition.js b/js/components/ascribe_detail/edition.js index ea9b44c3..a47f2148 100644 --- a/js/components/ascribe_detail/edition.js +++ b/js/components/ascribe_detail/edition.js @@ -5,7 +5,6 @@ import Router from 'react-router'; import Row from 'react-bootstrap/lib/Row'; import Col from 'react-bootstrap/lib/Col'; -import Button from 'react-bootstrap/lib/Button'; import Glyphicon from 'react-bootstrap/lib/Glyphicon'; import UserActions from '../../actions/user_actions'; @@ -22,7 +21,6 @@ import Property from './../ascribe_forms/property'; import EditionDetailProperty from './detail_property'; import InputTextAreaToggable from './../ascribe_forms/input_textarea_toggable'; -import EditionHeader from './header'; import EditionFurtherDetails from './further_details'; //import PieceExtraDataForm from './../ascribe_forms/form_piece_extradata'; @@ -38,7 +36,6 @@ import GlobalNotificationActions from '../../actions/global_notification_actions import apiUrls from '../../constants/api_urls'; import AppConstants from '../../constants/application_constants'; -import { getCookie } from '../../utils/fetch_api_utils'; import { getLangText } from '../../utils/lang_utils'; let Link = Router.Link; @@ -76,7 +73,12 @@ let Edition = React.createClass({ content={this.props.edition}/> - +
+ {this.props.edition.title}
} /> + + +
+ diff --git a/js/components/ascribe_detail/header.js b/js/components/ascribe_detail/header.js deleted file mode 100644 index e9226a85..00000000 --- a/js/components/ascribe_detail/header.js +++ /dev/null @@ -1,26 +0,0 @@ -'use strict'; - -import React from 'react'; - -import EditionDetailProperty from './detail_property'; - - -let Header = React.createClass({ - propTypes: { - content: React.PropTypes.object - }, - - render() { - var titleHtml =
{this.props.content.title}
; - return ( -
- - - -
-
- ); - } -}); - -export default Header; \ No newline at end of file diff --git a/js/components/ascribe_detail/piece.js b/js/components/ascribe_detail/piece.js index d37addea..ec2bcb5a 100644 --- a/js/components/ascribe_detail/piece.js +++ b/js/components/ascribe_detail/piece.js @@ -15,21 +15,14 @@ import UserStore from '../../stores/user_store'; import MediaContainer from './media_container'; -import Header from './header'; +import EditionDetailProperty from './detail_property'; -import Form from './../ascribe_forms/form'; -import Property from './../ascribe_forms/property'; - -import RequestActionForm from './../ascribe_forms/form_request_action'; -import EditionActions from '../../actions/edition_actions'; import AclButtonList from './../ascribe_buttons/acl_button_list'; +import CreateEditionsForm from '../ascribe_forms/create_editions_form'; +import CreateEditionsButton from '../ascribe_buttons/create_editions_button'; - -import GlobalNotificationModel from '../../models/global_notification_model'; -import GlobalNotificationActions from '../../actions/global_notification_actions'; - -import apiUrls from '../../constants/api_urls'; import { getLangText } from '../../utils/lang_utils'; +import { mergeOptions } from '../../utils/general_utils'; /** * This is the component that implements display-specific functionality @@ -41,7 +34,12 @@ let Piece = React.createClass({ }, getInitialState() { - return UserStore.getState(); + return mergeOptions( + UserStore.getState(), + { + showCreateEditionsDialog: false + } + ); }, componentDidMount() { @@ -57,8 +55,28 @@ let Piece = React.createClass({ this.setState(state); }, - render() { + toggleCreateEditionsDialog() { + this.setState({ + showCreateEditionsDialog: !this.state.showCreateEditionsDialog + }); + }, + getCreateEditionsDialog() { + if(this.props.piece.num_editions < 1 && this.state.showCreateEditionsDialog) { + return ( +
+ +
+
+ ); + } else { + return (
); + } + }, + + render() { return ( @@ -66,12 +84,29 @@ let Piece = React.createClass({ content={this.props.piece}/> -
- +
+ {this.props.piece.title}
} /> + + + {this.props.piece.num_editions > 0 ? : null} +
+ +
+ +
+ + + + + + {this.getCreateEditionsDialog()} + -1 @@ -85,42 +120,10 @@ let Piece = React.createClass({ otherData={this.props.piece.other_data} handleSuccess={this.props.loadPiece}/> - ); } }); -let PieceSummary = React.createClass({ - propTypes: { - piece: React.PropTypes.object - }, - getActions(){ - let actions = ( - - - - - ); - return actions; - //return null; - }, - render() { - return ( -
- - {this.getActions()} -
-
- ); - - } -}); - - export default Piece; diff --git a/js/components/ascribe_forms/create_editions_form.js b/js/components/ascribe_forms/create_editions_form.js new file mode 100644 index 00000000..335851f9 --- /dev/null +++ b/js/components/ascribe_forms/create_editions_form.js @@ -0,0 +1,50 @@ +'use strict'; + +import React from 'react'; + +import Form from '../ascribe_forms/form'; +import Property from '../ascribe_forms/property'; + +import apiUrls from '../../constants/api_urls'; + +import { getLangText } from '../../utils/lang_utils'; + +let CreateEditionsForm = React.createClass({ + + propTypes: { + handleSuccess: React.PropTypes.func, + pieceId: React.PropTypes.number + }, + + getFormData(){ + return { + piece_id: parseInt(this.props.pieceId, 10) + }; + }, + + render() { + return ( +
+ + + }> + + + +
+ ); + } +}); + +export default CreateEditionsForm; \ No newline at end of file diff --git a/js/constants/languages.js b/js/constants/languages.js index c21bd0ad..d718fa69 100644 --- a/js/constants/languages.js +++ b/js/constants/languages.js @@ -210,6 +210,7 @@ const languages = { 'I agree to the Terms of Service': 'I agree to the Terms of Service', 'read': 'read', 'If your email address exists in our database, you will receive a password recovery link in a few minutes.': 'If your email address exists in our database, you will receive a password recovery link in a few minutes.', + 'REGISTREE': 'REGISTREE', }, 'de': { 'ID': 'ID', @@ -420,6 +421,7 @@ const languages = { 'I agree to the Terms of Service': 'I agree to the Terms of Service', 'read': 'read', 'If your email address exists in our database, you will receive a password recovery link in a few minutes.': 'If your email address exists in our database, you will receive a password recovery link in a few minutes.', + 'REGISTREE': 'REGISTREE', }, 'fr': { 'ID': 'ID', @@ -630,6 +632,7 @@ const languages = { 'I agree to the Terms of Service': 'I agree to the Terms of Service', 'read': 'read', 'If your email address exists in our database, you will receive a password recovery link in a few minutes.': 'Si votre adresse électronique existe dans notre base de données, vous recevrez un lien de récupération de mot de passe dans quelques minutes.', + 'REGISTREE': 'REGISTREE', } }; From 85ba816a53a3ff0deffa16cd7d7786f921649a67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Mon, 13 Jul 2015 18:13:16 +0200 Subject: [PATCH 2/5] separate polling-success functionality --- js/actions/piece_actions.js | 3 +- .../ascribe_buttons/create_editions_button.js | 46 +++++++++++-------- js/components/ascribe_detail/piece.js | 19 +++++++- .../ascribe_forms/create_editions_form.js | 14 +++++- js/stores/piece_store.js | 8 ++++ 5 files changed, 69 insertions(+), 21 deletions(-) diff --git a/js/actions/piece_actions.js b/js/actions/piece_actions.js index cd78569d..d52b8d43 100644 --- a/js/actions/piece_actions.js +++ b/js/actions/piece_actions.js @@ -7,7 +7,8 @@ import PieceFetcher from '../fetchers/piece_fetcher'; class PieceActions { constructor() { this.generateActions( - 'updatePiece' + 'updatePiece', + 'updateProperty' ); } diff --git a/js/components/ascribe_buttons/create_editions_button.js b/js/components/ascribe_buttons/create_editions_button.js index 9ccb52cf..9c161a7d 100644 --- a/js/components/ascribe_buttons/create_editions_button.js +++ b/js/components/ascribe_buttons/create_editions_button.js @@ -3,18 +3,35 @@ import React from 'react'; import EditionListActions from '../../actions/edition_list_actions'; -import PieceListActions from '../../actions/piece_list_actions'; +import EditionListStore from '../../stores/edition_list_store'; import { getAvailableAcls } from '../../utils/acl_utils'; +import classNames from 'classnames'; + let CreateEditionsButton = React.createClass({ propTypes: { + className: React.PropTypes.string, piece: React.PropTypes.object.isRequired, - toggleCreateEditionsDialog: React.PropTypes.func.isRequired + toggleCreateEditionsDialog: React.PropTypes.func.isRequired, + onPollingSuccess: React.PropTypes.func }, getInitialState() { - return {}; + return EditionListStore.getState(); + }, + + componentDidMount() { + EditionListStore.listen(this.onChange); + }, + + componentWillUnmount() { + EditionListStore.unlisten(this.onChange); + clearInterval(this.state.pollingIntervalIndex); + }, + + onChange(state) { + this.setState(state); }, componentDidUpdate() { @@ -23,10 +40,6 @@ let CreateEditionsButton = React.createClass({ } }, - componentWillUnmount() { - clearInterval(this.state.pollingIntervalIndex); - }, - startPolling() { // start polling until editions are defined let pollingIntervalIndex = setInterval(() => { @@ -35,13 +48,7 @@ let CreateEditionsButton = React.createClass({ clearInterval(this.state.pollingIntervalIndex); - PieceListActions.updatePropertyForPiece({ - pieceId: this.props.piece.id, - key: 'num_editions', - value: res.editions[0].num_editions - }); - - EditionListActions.toggleEditionList(this.props.piece.id); + this.props.onPollingSuccess(this.props.piece.id, res.editions[0].num_editions); }) .catch(() => { @@ -58,20 +65,23 @@ let CreateEditionsButton = React.createClass({ let piece = this.props.piece; let availableAcls = getAvailableAcls(piece); + if (availableAcls.indexOf('editions') < -1 || piece.num_editions > 0){ return null; } - if(piece.num_editions === 0) { + if(piece.num_editions === 0 && typeof this.state.editionList[piece.id] === 'undefined') { return ( - ); } else { return ( - diff --git a/js/components/ascribe_detail/piece.js b/js/components/ascribe_detail/piece.js index ec2bcb5a..8414656b 100644 --- a/js/components/ascribe_detail/piece.js +++ b/js/components/ascribe_detail/piece.js @@ -10,9 +10,12 @@ import CollapsibleParagraph from './../ascribe_collapsible/collapsible_paragraph import DetailProperty from './detail_property'; import FurtherDetails from './further_details'; + import UserActions from '../../actions/user_actions'; import UserStore from '../../stores/user_store'; +import PieceActions from '../../actions/piece_actions'; + import MediaContainer from './media_container'; import EditionDetailProperty from './detail_property'; @@ -61,6 +64,11 @@ let Piece = React.createClass({ }); }, + handleEditionCreationSuccess() { + PieceActions.updateProperty({key: 'num_editions', value: 0}); + this.toggleCreateEditionsDialog(); + }, + getCreateEditionsDialog() { if(this.props.piece.num_editions < 1 && this.state.showCreateEditionsDialog) { return ( @@ -76,6 +84,13 @@ let Piece = React.createClass({ } }, + handlePollingSuccess(pieceId, numEditions) { + PieceActions.updateProperty({ + key: 'num_editions', + value: numEditions + }); + }, + render() { return ( @@ -101,8 +116,10 @@ let Piece = React.createClass({ editions={this.props.piece} handleSuccess={this.props.handleSuccess}> + toggleCreateEditionsDialog={this.toggleCreateEditionsDialog} + onPollingSuccess={this.handlePollingSuccess}/> {this.getCreateEditionsDialog()} diff --git a/js/components/ascribe_forms/create_editions_form.js b/js/components/ascribe_forms/create_editions_form.js index 335851f9..5f52cf17 100644 --- a/js/components/ascribe_forms/create_editions_form.js +++ b/js/components/ascribe_forms/create_editions_form.js @@ -5,6 +5,9 @@ import React from 'react'; import Form from '../ascribe_forms/form'; import Property from '../ascribe_forms/property'; +import GlobalNotificationModel from '../../models/global_notification_model'; +import GlobalNotificationActions from '../../actions/global_notification_actions'; + import apiUrls from '../../constants/api_urls'; import { getLangText } from '../../utils/lang_utils'; @@ -22,13 +25,22 @@ let CreateEditionsForm = React.createClass({ }; }, + handleSuccess(response) { + let notification = new GlobalNotificationModel(response.notification, 'success', 10000); + GlobalNotificationActions.appendGlobalNotification(notification); + + if(this.props.handleSuccess) { + this.props.handleSuccess(); + } + }, + render() { return (
diff --git a/js/stores/piece_store.js b/js/stores/piece_store.js index 5d2651ad..0bebab10 100644 --- a/js/stores/piece_store.js +++ b/js/stores/piece_store.js @@ -13,6 +13,14 @@ class PieceStore { onUpdatePiece(piece) { this.piece = piece; } + + onUpdateProperty({key, value}) { + if(this.piece && key in this.piece) { + this.piece[key] = value; + } else { + throw new Error('There is no piece defined in PieceStore or the piece object does not have the property you\'re looking for.'); + } + } } export default alt.createStore(PieceStore, 'PieceStore'); From 1f73811950a736c4db08b78c4b9ee131a0ba988b Mon Sep 17 00:00:00 2001 From: diminator Date: Mon, 13 Jul 2015 18:13:47 +0200 Subject: [PATCH 3/5] register form separate spinner => spans --- .../accordion_list_item_create_editions.js | 4 +- js/components/ascribe_forms/form_login.js | 8 +- .../ascribe_forms/form_register_piece.js | 165 ++++++++++++++++++ js/components/ascribe_forms/form_signup.js | 4 +- js/components/coa_verify_container.js | 4 +- js/components/login_container.js | 10 +- js/components/password_reset_container.js | 8 +- js/components/register_piece.js | 147 +--------------- 8 files changed, 193 insertions(+), 157 deletions(-) create mode 100644 js/components/ascribe_forms/form_register_piece.js diff --git a/js/components/ascribe_accordion_list/accordion_list_item_create_editions.js b/js/components/ascribe_accordion_list/accordion_list_item_create_editions.js index 30a6efbc..66fadd8d 100644 --- a/js/components/ascribe_accordion_list/accordion_list_item_create_editions.js +++ b/js/components/ascribe_accordion_list/accordion_list_item_create_editions.js @@ -30,9 +30,9 @@ let AccordionListItemCreateEditions = React.createClass({ getFormData={this.getFormData} handleSuccess={this.props.handleSuccess} spinner={ - + }> } spinner={ - + }> file.status !== 'deleted' && file.status !== 'canceled'); + if (files.length > 0 && files[0].status === 'upload successful') { + return true; + } else { + return false; + } + }, + + render() { + return ( + + {getLangText('Register work')} + } + spinner={ + + + + }> + +

{getLangText('Register your work')}

+
+ + + + + + + + + + + + + {this.props.children} + + ); + } +}); + +let FileUploader = React.createClass({ + propTypes: { + setIsUploadReady: React.PropTypes.func, + submitKey: React.PropTypes.func, + isReadyForFormSubmission: React.PropTypes.func, + onClick: React.PropTypes.func, + // editable 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 + editable: React.PropTypes.bool + }, + + render() { + return ( + + ); + } +}); + +export default RegisterPieceForm; \ No newline at end of file diff --git a/js/components/ascribe_forms/form_signup.js b/js/components/ascribe_forms/form_signup.js index 258a3923..3c50c7fd 100644 --- a/js/components/ascribe_forms/form_signup.js +++ b/js/components/ascribe_forms/form_signup.js @@ -75,9 +75,9 @@ let SignupForm = React.createClass({ {getLangText('Sign up to ascribe')} } spinner={ - + }>

{getLangText('Welcome to ascribe')}

diff --git a/js/components/coa_verify_container.js b/js/components/coa_verify_container.js index 6afbdfa5..8c2f2e77 100644 --- a/js/components/coa_verify_container.js +++ b/js/components/coa_verify_container.js @@ -68,9 +68,9 @@ let CoaVerifyForm = React.createClass({ {getLangText('Verify your Certificate of Authenticity')} } spinner={ - + }>
{getLangText('Not an ascribe user')}? {getLangText('Sign up')}...
diff --git a/js/components/password_reset_container.js b/js/components/password_reset_container.js index 5ab258b0..b149d45d 100644 --- a/js/components/password_reset_container.js +++ b/js/components/password_reset_container.js @@ -82,9 +82,9 @@ let PasswordRequestResetForm = React.createClass({ {getLangText('Reset your password')} } spinner={ - + }> } spinner={ - + }> file.status !== 'deleted' && file.status !== 'canceled'); - if (files.length > 0 && files[0].status === 'upload successful') { - return true; - } else { - return false; - } - }, onLicenseChange(event){ //console.log(this.state.licenses[event.target.selectedIndex].url); this.setState({selectedLicense: event.target.selectedIndex}); @@ -170,59 +135,9 @@ let RegisterPiece = React.createClass( { onFocus={this.changeSlide}> -
- {getLangText('Register work')} - } - spinner={ - - }> - -

{getLangText('Register your work')}

-
- - - - - - - - - - - - + {getLangText('Editions')} @@ -232,7 +147,7 @@ let RegisterPiece = React.createClass( { min={0}/> {this.getLicenses()} - +
@@ -248,54 +163,4 @@ let RegisterPiece = React.createClass( { }); -let FileUploader = React.createClass({ - propTypes: { - setIsUploadReady: React.PropTypes.func, - submitKey: React.PropTypes.func, - isReadyForFormSubmission: React.PropTypes.func, - onClick: React.PropTypes.func, - // editable 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 - editable: React.PropTypes.bool - }, - - render() { - return ( - - ); - } -}); - export default RegisterPiece; From 463f205a6ed21acfb018bed5731db29065eb2756 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20Daubensch=C3=BCtz?= Date: Mon, 13 Jul 2015 18:52:55 +0200 Subject: [PATCH 4/5] finalized: separation of edition creation and edition form --- .../accordion_list_item.js | 52 ++++--------------- .../accordion_list_item_edition_widget.js | 41 ++++++--------- .../ascribe_buttons/create_editions_button.js | 7 +-- js/components/ascribe_detail/piece.js | 4 +- .../ascribe_forms/create_editions_form.js | 2 +- 5 files changed, 32 insertions(+), 74 deletions(-) diff --git a/js/components/ascribe_accordion_list/accordion_list_item.js b/js/components/ascribe_accordion_list/accordion_list_item.js index a5e5679d..150d6934 100644 --- a/js/components/ascribe_accordion_list/accordion_list_item.js +++ b/js/components/ascribe_accordion_list/accordion_list_item.js @@ -35,20 +35,6 @@ let AccordionListItem = React.createClass({ }; }, - componentDidUpdate() { - if(this.props.content.num_editions === 0 && typeof this.state.pollingIntervalIndex === 'undefined') { - this.startPolling(); - } - }, - - componentWillUnmount() { - clearInterval(this.state.pollingIntervalIndex); - }, - - onChange(state) { - this.setState(state); - }, - getGlyphicon(){ if (this.props.content.requestAction){ return ( @@ -66,39 +52,20 @@ let AccordionListItem = React.createClass({ }); }, - handleEditionCreationSuccess(response) { - let notification = new GlobalNotificationModel(response.notification, 'success', 10000); - GlobalNotificationActions.appendGlobalNotification(notification); + handleEditionCreationSuccess() { PieceListActions.updatePropertyForPiece({pieceId: this.props.content.id, key: 'num_editions', value: 0}); this.toggleCreateEditionsDialog(); }, - startPolling() { - // start polling until editions are defined - let pollingIntervalIndex = setInterval(() => { - EditionListActions.fetchEditionList(this.props.content.id) - .then((res) => { - - clearInterval(this.state.pollingIntervalIndex); - - PieceListActions.updatePropertyForPiece({ - pieceId: this.props.content.id, - key: 'num_editions', - value: res.editions[0].num_editions - }); - - EditionListActions.toggleEditionList(this.props.content.id); - - }) - .catch(() => { - /* Ignore and keep going */ - }); - }, 5000); - - this.setState({ - pollingIntervalIndex + onPollingSuccess(pieceId, numEditions) { + PieceListActions.updatePropertyForPiece({ + pieceId, + key: 'num_editions', + value: numEditions }); + + EditionListActions.toggleEditionList(pieceId); }, getCreateEditionsDialog() { @@ -153,7 +120,8 @@ let AccordionListItem = React.createClass({ + toggleCreateEditionsDialog={this.toggleCreateEditionsDialog} + onPollingSuccess={this.onPollingSuccess}/> diff --git a/js/components/ascribe_accordion_list/accordion_list_item_edition_widget.js b/js/components/ascribe_accordion_list/accordion_list_item_edition_widget.js index ba4ece2a..02328382 100644 --- a/js/components/ascribe_accordion_list/accordion_list_item_edition_widget.js +++ b/js/components/ascribe_accordion_list/accordion_list_item_edition_widget.js @@ -6,13 +6,16 @@ import classNames from 'classnames'; import EditionListActions from '../../actions/edition_list_actions'; import EditionListStore from '../../stores/edition_list_store'; +import CreateEditionsButton from '../ascribe_buttons/create_editions_button'; + import { getLangText } from '../../utils/lang_utils'; let AccordionListItemEditionWidget = React.createClass({ propTypes: { className: React.PropTypes.string, piece: React.PropTypes.object.isRequired, - toggleCreateEditionsDialog: React.PropTypes.func.isRequired + toggleCreateEditionsDialog: React.PropTypes.func.isRequired, + onPollingSuccess: React.PropTypes.func }, getInitialState() { @@ -55,16 +58,9 @@ let AccordionListItemEditionWidget = React.createClass({ let isEditionListOpen = this.state.isEditionListOpenForPieceId[pieceId] ? this.state.isEditionListOpenForPieceId[pieceId].show : false; if(isEditionListOpen) { - if(typeof this.state.editionList[pieceId] === 'undefined') { - return ( - - ); - } else { - return ( - - ); - } - + return ( + + ); } else { return ( @@ -76,23 +72,16 @@ let AccordionListItemEditionWidget = React.createClass({ let piece = this.props.piece; let numEditions = piece.num_editions; - if(numEditions === -1) { + if(numEditions <= 0) { return ( - + ); - } - else if(numEditions === 0) { - return ( - - ); - } - else if(numEditions === 1) { + } else if(numEditions === 1) { let editionMapping = piece && piece.first_edition ? piece.first_edition.edition_number + '/' + piece.num_editions : ''; return ( diff --git a/js/components/ascribe_buttons/create_editions_button.js b/js/components/ascribe_buttons/create_editions_button.js index 9c161a7d..63127c68 100644 --- a/js/components/ascribe_buttons/create_editions_button.js +++ b/js/components/ascribe_buttons/create_editions_button.js @@ -6,11 +6,13 @@ import EditionListActions from '../../actions/edition_list_actions'; import EditionListStore from '../../stores/edition_list_store'; import { getAvailableAcls } from '../../utils/acl_utils'; +import { getLangText } from '../../utils/lang_utils'; import classNames from 'classnames'; let CreateEditionsButton = React.createClass({ propTypes: { + label: React.PropTypes.string, className: React.PropTypes.string, piece: React.PropTypes.object.isRequired, toggleCreateEditionsDialog: React.PropTypes.func.isRequired, @@ -47,7 +49,6 @@ let CreateEditionsButton = React.createClass({ .then((res) => { clearInterval(this.state.pollingIntervalIndex); - this.props.onPollingSuccess(this.props.piece.id, res.editions[0].num_editions); }) @@ -75,7 +76,7 @@ let CreateEditionsButton = React.createClass({ ); } else { @@ -83,7 +84,7 @@ let CreateEditionsButton = React.createClass({ ); } diff --git a/js/components/ascribe_detail/piece.js b/js/components/ascribe_detail/piece.js index 8414656b..a0fb1dfc 100644 --- a/js/components/ascribe_detail/piece.js +++ b/js/components/ascribe_detail/piece.js @@ -113,9 +113,9 @@ let Piece = React.createClass({ + editions={this.props.piece}> Date: Mon, 13 Jul 2015 19:12:24 +0200 Subject: [PATCH 5/5] display spinner on pagination request --- js/actions/piece_list_actions.js | 15 +++++++++++++++ js/stores/piece_list_store.js | 1 + 2 files changed, 16 insertions(+) diff --git a/js/actions/piece_list_actions.js b/js/actions/piece_list_actions.js index ec7ad7a7..3c5b44d2 100644 --- a/js/actions/piece_list_actions.js +++ b/js/actions/piece_list_actions.js @@ -14,6 +14,21 @@ class PieceListActions { } fetchPieceList(page, pageSize, search, orderBy, orderAsc) { + // To prevent flickering on a pagination request, + // we overwrite the piecelist with an empty list before + // pieceListCount === -1 defines the loading state + this.actions.updatePieceList({ + page, + pageSize, + search, + orderBy, + orderAsc, + 'pieceList': [], + 'pieceListCount': -1 + }); + + // afterwards, we can load the list + return new Promise((resolve, reject) => { PieceListFetcher .fetch(page, pageSize, search, orderBy, orderAsc) diff --git a/js/stores/piece_list_store.js b/js/stores/piece_list_store.js index 63a109ca..22d8d5d6 100644 --- a/js/stores/piece_list_store.js +++ b/js/stores/piece_list_store.js @@ -19,6 +19,7 @@ class PieceListStore { * the number of items the resource actually - without pagination - provides. */ this.pieceList = []; + // -1 specifies that the store is currently loading this.pieceListCount = -1; this.page = 1; this.pageSize = 10;