diff --git a/js/actions/user_actions.js b/js/actions/user_actions.js index 1ea0c560..44682f17 100644 --- a/js/actions/user_actions.js +++ b/js/actions/user_actions.js @@ -13,7 +13,7 @@ class UserActions { } fetchCurrentUser() { - UserFetcher.fetchOne() + return UserFetcher.fetchOne() .then((res) => { this.actions.updateCurrentUser(res.users[0]); }) diff --git a/js/components/ascribe_forms/form_login.js b/js/components/ascribe_forms/form_login.js index ee6efb54..24b0eb93 100644 --- a/js/components/ascribe_forms/form_login.js +++ b/js/components/ascribe_forms/form_login.js @@ -25,7 +25,8 @@ let LoginForm = React.createClass({ headerMessage: React.PropTypes.string, submitMessage: React.PropTypes.string, redirectOnLoggedIn: React.PropTypes.bool, - redirectOnLoginSuccess: React.PropTypes.bool + redirectOnLoginSuccess: React.PropTypes.bool, + onLogin: React.PropTypes.func }, mixins: [Router.Navigation], @@ -70,18 +71,29 @@ let LoginForm = React.createClass({ // The easiest way to check if the user was successfully logged in is to fetch the user // in the user store (which is obviously only possible if the user is logged in), since // register_piece is listening to the changes of the user_store. - UserActions.fetchCurrentUser(); + UserActions.fetchCurrentUser() + .then(() => { + if(this.props.redirectOnLoginSuccess) { + /* Taken from http://stackoverflow.com/a/14916411 */ + /* + We actually have to trick the Browser into showing the "save password" dialog + as Chrome expects the login page to be reloaded after the login. + Users on Stack Overflow claim this is a bug in chrome and should be fixed in the future. + Until then, we redirect the HARD way, but reloading the whole page using window.location + */ + window.location = AppConstants.baseUrl + 'collection'; + } else if(this.props.onLogin) { + // In some instances we want to give a callback to an outer container, + // to show that the one login action the user triggered actually went through. + // We can not do this by listening on a store's state as it wouldn't really tell us + // if the user did log in or was just fetching the user's data again + this.props.onLogin(); + } + }) + .catch((err) => { + console.logGlobal(err); + }); - /* Taken from http://stackoverflow.com/a/14916411 */ - /* - We actually have to trick the Browser into showing the "save password" dialog - as Chrome expects the login page to be reloaded after the login. - Users on Stack Overflow claim this is a bug in chrome and should be fixed in the future. - Until then, we redirect the HARD way, but reloading the whole page using window.location - */ - if(this.props.redirectOnLoginSuccess) { - window.location = AppConstants.baseUrl + 'collection'; - } }, render() { diff --git a/js/components/ascribe_forms/form_register_piece.js b/js/components/ascribe_forms/form_register_piece.js index 00d3c4d4..9e513558 100644 --- a/js/components/ascribe_forms/form_register_piece.js +++ b/js/components/ascribe_forms/form_register_piece.js @@ -21,8 +21,9 @@ let RegisterPieceForm = React.createClass({ headerMessage: React.PropTypes.string, submitMessage: React.PropTypes.string, handleSuccess: React.PropTypes.func, - isFineUploaderEditable: React.PropTypes.bool, - children: React.PropTypes.element + isFineUploaderActive: React.PropTypes.bool, + children: React.PropTypes.element, + onLoggedOut: React.PropTypes.func }, getDefaultProps() { @@ -94,7 +95,8 @@ let RegisterPieceForm = React.createClass({ submitKey={this.submitKey} setIsUploadReady={this.setIsUploadReady} isReadyForFormSubmission={this.isReadyForFormSubmission} - editable={this.props.isFineUploaderEditable}/> + isFineUploaderActive={this.props.isFineUploaderActive} + onLoggedOut={this.props.onLoggedOut}/> + }} + onInactive={this.props.onLoggedOut}/> ); } }); diff --git a/js/components/ascribe_slides_container/slides_container.js b/js/components/ascribe_slides_container/slides_container.js index 7e37c6c9..ad883d0c 100644 --- a/js/components/ascribe_slides_container/slides_container.js +++ b/js/components/ascribe_slides_container/slides_container.js @@ -17,7 +17,7 @@ let SlidesContainer = React.createClass({ getInitialState() { // handle queryParameters let queryParams = this.getQuery(); - let slideNum = 0; + let slideNum = -1; if(queryParams && 'slide_num' in queryParams) { slideNum = parseInt(queryParams.slide_num, 10); @@ -26,17 +26,12 @@ let SlidesContainer = React.createClass({ return { containerWidth: 0, - slideNum: slideNum + slideNum: slideNum, + historyLength: window.history.length }; }, componentDidMount() { - // check if slide_num was defined, and if not then default to 0 - let queryParams = this.getQuery(); - if(!('slide_num' in queryParams)) { - this.replaceWith(this.getPathname(), null, {slide_num: 0}); - } - // init container width this.handleContainerResize(); @@ -45,6 +40,12 @@ let SlidesContainer = React.createClass({ window.addEventListener('resize', this.handleContainerResize); }, + componentDidUpdate() { + // check if slide_num was defined, and if not then default to 0 + let queryParams = this.getQuery(); + this.setSlideNum(queryParams.slide_num); + }, + componentWillUnmount() { window.removeEventListener('resize', this.handleContainerResize); }, @@ -58,9 +59,45 @@ let SlidesContainer = React.createClass({ // We let every one from the outsite set the page number of the slider, // though only if the slideNum is actually in the range of our children-list. setSlideNum(slideNum) { - if(slideNum < 0 || slideNum < React.Children.count(this.props.children)) { + + // slideNum can in some instances be not a number, + // therefore we have to parse it to one and make sure that its not NaN + slideNum = parseInt(slideNum, 10); + + // if slideNum is not a number (even after we parsed it to one) and there has + // never been a transition to another slide (this.state.slideNum ==== -1 indicates that) + // then we want to "replace" (in this case append) the current url with ?slide_num=0 + if(isNaN(slideNum) && this.state.slideNum === -1) { + slideNum = 0; this.replaceWith(this.getPathname(), null, {slide_num: slideNum}); + this.setState({slideNum: slideNum}); + return; + + // slideNum always represents the future state. So if slideNum and + // this.state.slideNum are equal, there is no sense in redirecting + } else if(slideNum === this.state.slideNum) { + return; + + // if slideNum is within the range of slides and none of the previous cases + // where matched, we can actually do transitions + } else if(slideNum >= 0 || slideNum < React.Children.count(this.props.children)) { + + if(slideNum !== this.state.slideNum - 1) { + // Bootstrapping the component, getInitialState is called once to save + // the tabs history length. + // In order to know if we already pushed a new state on the history stack or not, + // we're comparing the old history length with the new one and if it didn't change then + // we push a new state on it ONCE (ever). + // Otherwise, we're able to use the browsers history.forward() method + // to keep the stack clean + if(this.state.historyLength === window.history.length) { + this.transitionTo(this.getPathname(), null, {slide_num: slideNum}); + } else { + window.history.forward(); + } + } + this.setState({ slideNum: slideNum }); diff --git a/js/components/ascribe_uploader/file_drag_and_drop.js b/js/components/ascribe_uploader/file_drag_and_drop.js index b95d4a19..36b83c62 100644 --- a/js/components/ascribe_uploader/file_drag_and_drop.js +++ b/js/components/ascribe_uploader/file_drag_and_drop.js @@ -18,6 +18,7 @@ let FileDragAndDrop = React.createClass({ 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, @@ -72,6 +73,15 @@ let FileDragAndDrop = React.createClass({ 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; @@ -113,10 +123,15 @@ let FileDragAndDrop = React.createClass({ this.props.handleResumeFile(fileId); }, - handleOnClick(event) { + handleOnClick() { // 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; } diff --git a/js/components/ascribe_uploader/react_s3_fine_uploader.js b/js/components/ascribe_uploader/react_s3_fine_uploader.js index b4726a98..7b570c2c 100644 --- a/js/components/ascribe_uploader/react_s3_fine_uploader.js +++ b/js/components/ascribe_uploader/react_s3_fine_uploader.js @@ -95,7 +95,8 @@ var ReactS3FineUploader = React.createClass({ isReadyForFormSubmission: React.PropTypes.func, areAssetsDownloadable: React.PropTypes.bool, areAssetsEditable: React.PropTypes.bool, - defaultErrorMessage: React.PropTypes.string + defaultErrorMessage: React.PropTypes.string, + onInactive: React.PropTypes.func }, getDefaultProps() { @@ -560,7 +561,8 @@ var ReactS3FineUploader = React.createClass({ multiple={this.props.multiple} areAssetsDownloadable={this.props.areAssetsDownloadable} areAssetsEditable={this.props.areAssetsEditable} - dropzoneInactive={!this.props.areAssetsEditable || !this.props.multiple && this.state.filesToUpload.filter((file) => file.status !== 'deleted' && file.status !== 'canceled' && file.size !== -1).length > 0} /> + dropzoneInactive={!this.props.areAssetsEditable || !this.props.multiple && this.state.filesToUpload.filter((file) => file.status !== 'deleted' && file.status !== 'canceled' && file.size !== -1).length > 0} + onInactive={this.props.onInactive}/> ); } diff --git a/js/components/login_container.js b/js/components/login_container.js index a8d5c1b1..f050014b 100644 --- a/js/components/login_container.js +++ b/js/components/login_container.js @@ -14,7 +14,8 @@ let LoginContainer = React.createClass({ propTypes: { message: React.PropTypes.string, redirectOnLoggedIn: React.PropTypes.bool, - redirectOnLoginSuccess: React.PropTypes.bool + redirectOnLoginSuccess: React.PropTypes.bool, + onLogin: React.PropTypes.func }, getDefaultProps() { @@ -31,7 +32,8 @@ let LoginContainer = React.createClass({ + message={this.props.message} + onLogin={this.props.onLogin}/>
{getLangText('Not an ascribe user')}? {getLangText('Sign up')}...
{getLangText('Forgot my password')}? {getLangText('Rescue me')}... diff --git a/js/components/register_piece.js b/js/components/register_piece.js index 37d496a8..20826b7d 100644 --- a/js/components/register_piece.js +++ b/js/components/register_piece.js @@ -59,7 +59,7 @@ let RegisterPiece = React.createClass( { PieceListStore.getState(), { selectedLicense: 0, - isFineUploaderEditable: false + isFineUploaderActive: false }); }, @@ -82,14 +82,10 @@ let RegisterPiece = React.createClass( { onChange(state) { this.setState(state); - // once the currentUser object from UserStore is defined (eventually the user was transitioned - // to the login form via the slider and successfully logged in), we can direct him back to the - // register_piece slide - if(state.currentUser && state.currentUser.email || this.state.currentUser && this.state.currentUser.email) { - this.refs.slidesContainer.setSlideNum(0); + if(this.state.currentUser && this.state.currentUser.email) { // we should also make the fineuploader component editable again this.setState({ - isFineUploaderEditable: true + isFineUploaderActive: true }); } }, @@ -105,7 +101,8 @@ let RegisterPiece = React.createClass( { this.state.pageSize, this.state.searchTerm, this.state.orderBy, - this.state.orderAsc); + this.state.orderAsc + ); this.transitionTo('piece', {pieceId: response.piece.id}); }, @@ -160,11 +157,25 @@ let RegisterPiece = React.createClass( { changeSlide() { // only transition to the login store, if user is not logged in // ergo the currentUser object is not properly defined - if(!this.state.currentUser.email) { + if(this.state.currentUser && !this.state.currentUser.email) { this.refs.slidesContainer.setSlideNum(1); } }, + // basically redirects to the second slide (index: 1), when the user is not logged in + onLoggedOut() { + this.refs.slidesContainer.setSlideNum(1); + }, + + onLogin() { + // once the currentUser object from UserStore is defined (eventually the user was transitioned + // to the login form via the slider and successfully logged in), we can direct him back to the + // register_piece slide + if(this.state.currentUser && this.state.currentUser.email) { + window.history.back(); + } + }, + render() { return ( @@ -175,8 +186,9 @@ let RegisterPiece = React.createClass( { + isFineUploaderActive={this.state.isFineUploaderActive} + handleSuccess={this.handleSuccess} + onLoggedOut={this.onLoggedOut}> {this.props.children} {this.getLicenses()} {this.getSpecifyEditions()} @@ -188,7 +200,8 @@ let RegisterPiece = React.createClass( { + redirectOnLoginSuccess={false} + onLogin={this.onLogin}/>
); diff --git a/sass/main.scss b/sass/main.scss index 473e57d4..ea7dbd58 100644 --- a/sass/main.scss +++ b/sass/main.scss @@ -43,6 +43,7 @@ html { .ascribe-default-app { max-width: 90%; padding-top: 70px; + overflow-x: hidden; } hr {