diff --git a/.eslintrc b/.eslintrc index 2312f48f..d41c0a2a 100644 --- a/.eslintrc +++ b/.eslintrc @@ -22,7 +22,7 @@ "react/jsx-sort-props": 0, "react/jsx-uses-react": 1, "react/jsx-uses-vars": 1, - "react/no-did-mount-set-state": 1, + "react/no-did-mount-set-state": [1, "allow-in-func"], "react/no-did-update-set-state": 1, "react/no-multi-comp": 0, "react/no-unknown-property": 1, @@ -58,4 +58,4 @@ "superInFunctions": 1, "templateStrings": 1 } -} \ No newline at end of file +} diff --git a/js/components/ascribe_detail/edition_container.js b/js/components/ascribe_detail/edition_container.js index 046d8942..165913d4 100644 --- a/js/components/ascribe_detail/edition_container.js +++ b/js/components/ascribe_detail/edition_container.js @@ -9,6 +9,9 @@ import Edition from './edition'; import AscribeSpinner from '../ascribe_spinner'; +import { setDocumentTitle } from '../../utils/dom_utils'; + + /** * This is the component that implements resource/data specific functionality */ @@ -64,6 +67,8 @@ let EditionContainer = React.createClass({ render() { if(this.state.edition && this.state.edition.title) { + setDocumentTitle([this.state.edition.artist_name, this.state.edition.title].join(', ')); + return ( ` component (because ready is false) + * 1) set `state.libraryLoaded = null` (state.libraryLoaded can be in three states: `null` + * if we don't know anything about it, `true` if the external library has been loaded, + * `false` if we failed to load the external library) + * 2) render the cover using the `` component (because libraryLoaded is null) * 3) on `componentDidMount`, we load the external `css` and `js` resources using * the `InjectInHeadMixin`, attaching a function to `Promise.then` to change - * `state.ready` to true - * 4) when the promise is succesfully resolved, we change `state.ready` triggering + * `state.libraryLoaded` to true + * 4) when the promise is succesfully resolved, we change `state.libraryLoaded` triggering * a re-render * 5) the new render calls `prepareVideoHTML` to get the raw HTML of the video tag * (that will be later processed and expanded by VideoJS) @@ -129,18 +132,19 @@ let Video = React.createClass({ mixins: [InjectInHeadMixin], getInitialState() { - return { ready: false, videoMounted: false }; + return { libraryLoaded: null, videoMounted: false }; }, componentDidMount() { Q.all([ this.inject('//vjs.zencdn.net/4.12/video-js.css'), - this.inject('//vjs.zencdn.net/4.12/video.js') - ]).then(this.ready); + this.inject('//vjs.zencdn.net/4.12/video.js')]) + .then(() => this.setState({libraryLoaded: true})) + .fail(() => this.setState({libraryLoaded: false})); }, componentDidUpdate() { - if (this.state.ready && !this.state.videoMounted) { + if (this.state.libraryLoaded && !this.state.videoMounted) { window.videojs('#mainvideo'); /* eslint-disable */ this.setState({videoMounted: true}); @@ -149,11 +153,9 @@ let Video = React.createClass({ }, componentWillUnmount() { - window.videojs('#mainvideo').dispose(); - }, - - ready() { - this.setState({ready: true, videoMounted: false}); + if (this.state.videoMounted) { + window.videojs('#mainvideo').dispose(); + } }, prepareVideoHTML() { @@ -171,7 +173,7 @@ let Video = React.createClass({ }, render() { - if (this.state.ready) { + if (this.state.libraryLoaded !== null) { return (
); diff --git a/js/components/ascribe_settings/account_settings.js b/js/components/ascribe_settings/account_settings.js index 5f4cfe7a..f337a17b 100644 --- a/js/components/ascribe_settings/account_settings.js +++ b/js/components/ascribe_settings/account_settings.js @@ -96,11 +96,15 @@ let AccountSettings = React.createClass({ title={getLangText('Account')} defaultExpanded={true}> {content} - + + + {profile} ); } }); -export default AccountSettings; \ No newline at end of file +export default AccountSettings; diff --git a/js/components/ascribe_settings/contract_settings.js b/js/components/ascribe_settings/contract_settings.js index 741039ee..71d97542 100644 --- a/js/components/ascribe_settings/contract_settings.js +++ b/js/components/ascribe_settings/contract_settings.js @@ -23,6 +23,7 @@ import GlobalNotificationActions from '../../actions/global_notification_actions import AclProxy from '../acl_proxy'; import { getLangText } from '../../utils/lang_utils'; +import { setDocumentTitle } from '../../utils/dom_utils'; import { mergeOptions, truncateTextAtCharIndex } from '../../utils/general_utils'; @@ -86,6 +87,8 @@ let ContractSettings = React.createClass({ let privateContracts = this.getPrivateContracts(); let createPublicContractForm = null; + setDocumentTitle(getLangText('Contracts settings')); + if(publicContracts.length === 0) { createPublicContractForm = ( diff --git a/js/components/ascribe_uploader/ascribe_file_drag_and_drop/file_drag_and_drop.js b/js/components/ascribe_uploader/ascribe_file_drag_and_drop/file_drag_and_drop.js index c7f62b4c..38ec459a 100644 --- a/js/components/ascribe_uploader/ascribe_file_drag_and_drop/file_drag_and_drop.js +++ b/js/components/ascribe_uploader/ascribe_file_drag_and_drop/file_drag_and_drop.js @@ -12,6 +12,7 @@ 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, @@ -108,6 +109,7 @@ let FileDragAndDrop = React.createClass({ }, handleOnClick() { + let evt; // when multiple is set to false and the user already uploaded a piece, // do not propagate event if(this.props.dropzoneInactive) { @@ -119,16 +121,18 @@ let FileDragAndDrop = React.createClass({ return; } - // 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 - }); + 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); + } - evt.stopPropagation(); this.refs.fileinput.getDOMNode().dispatchEvent(evt); }, @@ -160,10 +164,10 @@ let FileDragAndDrop = React.createClass({

{getLangText('Computing hash(es)... This may take a few minutes.')}

- {getLangText('Cancel hashing')} + {getLangText('Cancel hashing')}

@@ -191,12 +195,23 @@ let FileDragAndDrop = React.createClass({ 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 + */}
diff --git a/js/components/login_container.js b/js/components/login_container.js index 33919cd6..46c14d65 100644 --- a/js/components/login_container.js +++ b/js/components/login_container.js @@ -6,6 +6,7 @@ import { Link } from 'react-router'; import LoginForm from './ascribe_forms/form_login'; import { getLangText } from '../utils/lang_utils'; +import { setDocumentTitle } from '../utils/dom_utils'; let LoginContainer = React.createClass({ @@ -26,6 +27,8 @@ let LoginContainer = React.createClass({ }, render() { + setDocumentTitle(getLangText('Log in')); + return (
diff --git a/js/components/password_reset_container.js b/js/components/password_reset_container.js index 64aaa889..31275a08 100644 --- a/js/components/password_reset_container.js +++ b/js/components/password_reset_container.js @@ -11,6 +11,7 @@ import AscribeSpinner from './ascribe_spinner'; import GlobalNotificationModel from '../models/global_notification_model'; import GlobalNotificationActions from '../actions/global_notification_actions'; import { getLangText } from '../utils/lang_utils'; +import { setDocumentTitle } from '../utils/dom_utils'; let PasswordResetContainer = React.createClass({ @@ -76,6 +77,8 @@ let PasswordRequestResetForm = React.createClass({ }, render() { + setDocumentTitle(getLangText('Reset your password')); + return (
; let AccordionListItemType = this.props.accordionListItemType; + setDocumentTitle(getLangText('Collection')); + return (
diff --git a/js/components/signup_container.js b/js/components/signup_container.js index 7c7b5ee7..e6c6fb73 100644 --- a/js/components/signup_container.js +++ b/js/components/signup_container.js @@ -6,6 +6,7 @@ import { Link } from 'react-router'; import SignupForm from './ascribe_forms/form_signup'; import { getLangText } from '../utils/lang_utils'; +import { setDocumentTitle } from '../utils/dom_utils'; let SignupContainer = React.createClass({ @@ -28,6 +29,8 @@ let SignupContainer = React.createClass({ }, render() { + setDocumentTitle(getLangText('Sign up')); + if (this.state.submitted){ return (
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 f288670d..a5f9838f 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 @@ -40,6 +40,7 @@ import DetailProperty from '../../../../ascribe_detail/detail_property'; import ApiUrls from '../../../../../constants/api_urls'; import { mergeOptions } from '../../../../../utils/general_utils'; import { getLangText } from '../../../../../utils/lang_utils'; +import { setDocumentTitle } from '../../../../../utils/dom_utils'; /** @@ -112,12 +113,22 @@ let PieceContainer = React.createClass({ // 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 )) ? -