1
0
mirror of https://github.com/ascribe/onion.git synced 2025-01-03 18:35:09 +01:00

Merged in AD-699-rename-prize-endpoint-to-prizes (pull request #26)

Ad 699 rename prize endpoint to prizes
This commit is contained in:
TimDaubenschuetz 2015-08-04 16:09:02 +02:00
commit 64fedc7e32
7 changed files with 81 additions and 20 deletions

1
.gitignore vendored
View File

@ -8,6 +8,7 @@ lib-cov
*.gz *.gz
*.sublime-project *.sublime-project
*.sublime-workspace *.sublime-workspace
webapp-dependencies.txt
pids pids
logs logs

View File

@ -3,6 +3,8 @@
import React from 'react'; import React from 'react';
import Q from 'q'; import Q from 'q';
import { escapeHTML } from '../../utils/general_utils';
import InjectInHeadMixin from '../../mixins/inject_in_head_mixin'; import InjectInHeadMixin from '../../mixins/inject_in_head_mixin';
import Panel from 'react-bootstrap/lib/Panel'; import Panel from 'react-bootstrap/lib/Panel';
import ProgressBar from 'react-bootstrap/lib/ProgressBar'; import ProgressBar from 'react-bootstrap/lib/ProgressBar';
@ -86,7 +88,29 @@ let Audio = React.createClass({
} }
}); });
let Video = React.createClass({ let Video = React.createClass({
/**
* The solution here is a bit convoluted.
* ReactJS is responsible for DOM manipulation but VideoJS updates the DOM
* to install itself to display the video, therefore ReactJS complains that we are
* changing the DOM under its feet.
*
* What we do is the following:
* 1) set `state.ready = false`
* 2) render the cover using the `<Image />` component (because ready is false)
* 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
* 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)
* 6) `componentDidUpdate` is called after `render`, setting `state.videoMounted` to true,
* to avoid re-installing the VideoJS library
* 7) to close the lifecycle, `componentWillUnmount` is called removing VideoJS from the DOM.
*/
propTypes: { propTypes: {
preview: React.PropTypes.string.isRequired, preview: React.PropTypes.string.isRequired,
url: React.PropTypes.string.isRequired, url: React.PropTypes.string.isRequired,
@ -97,7 +121,7 @@ let Video = React.createClass({
mixins: [InjectInHeadMixin], mixins: [InjectInHeadMixin],
getInitialState() { getInitialState() {
return { ready: false }; return { ready: false, videoMounted: false };
}, },
componentDidMount() { componentDidMount() {
@ -108,24 +132,40 @@ let Video = React.createClass({
}, },
componentDidUpdate() { componentDidUpdate() {
if (this.state.ready && !this.state.videojs) { if (this.state.ready && !this.state.videoMounted) {
window.videojs(React.findDOMNode(this.refs.video)); window.videojs('#mainvideo');
/* eslint-disable */
this.setState({videoMounted: true});
/* eslint-enable*/
} }
}, },
componentWillUnmount() {
window.videojs('#mainvideo').dispose();
},
ready() { ready() {
this.setState({ready: true, videojs: false}); this.setState({ready: true, videoMounted: false});
},
prepareVideoHTML() {
let sources = this.props.extraData.map((data) => '<source type="video/' + data.type + '" src="' + escapeHTML(data.url) + '" />');
let html = [
'<video id="mainvideo" class="video-js vjs-default-skin" poster="' + escapeHTML(this.props.preview) + '"',
'controls preload="none" width="auto" height="auto">',
sources.join('\n'),
'</video>'];
return html.join('\n');
},
shouldComponentUpdate(nextProps, nextState) {
return nextState.videoMounted === false;
}, },
render() { render() {
if (this.state.ready) { if (this.state.ready) {
return ( return (
<video ref="video" className="video-js vjs-default-skin" poster={this.props.preview} <div dangerouslySetInnerHTML={{__html: this.prepareVideoHTML() }}/>
controls preload="none" width="auto" height="auto">
{this.props.extraData.map((data, i) =>
<source key={i} type={'video/' + data.type} src={data.url} />
)}
</video>
); );
} else { } else {
return ( return (

View File

@ -117,8 +117,7 @@ let AccountSettings = React.createClass({
<InputCheckbox <InputCheckbox
defaultChecked={this.state.currentUser.profile.hash_locally}> defaultChecked={this.state.currentUser.profile.hash_locally}>
<span> <span>
{' ' + getLangText('Enable hash option for slow connections. ' + {' ' + getLangText('Enable hash option, e.g. slow connections or to keep piece private')}
'Computes and uploads a hash of the work instead.')}
</span> </span>
</InputCheckbox> </InputCheckbox>
</Property> </Property>

View File

@ -1,15 +1,15 @@
'use strict'; 'use strict';
import AppConstants from '../../../../constants/application_constants'; import AppPrizeConstants from './application_prize_constants';
function getApiUrls(subdomain) { function getApiUrls(subdomain) {
return { return {
'pieces_list': AppConstants.apiEndpoint + 'prize/' + subdomain + '/pieces/', 'pieces_list': AppPrizeConstants.prizeApiEndpoint + subdomain + '/pieces/',
'users_login': AppConstants.apiEndpoint + 'prize/' + subdomain + '/users/login/', 'users_login': AppPrizeConstants.prizeApiEndpoint + subdomain + '/users/login/',
'users_signup': AppConstants.apiEndpoint + 'prize/' + subdomain + '/users/', 'users_signup': AppPrizeConstants.prizeApiEndpoint + subdomain + '/users/',
'user': AppConstants.apiEndpoint + 'prize/' + subdomain + '/users/', 'user': AppPrizeConstants.prizeApiEndpoint + subdomain + '/users/',
'piece_submit_to_prize': AppConstants.apiEndpoint + 'prize/' + subdomain + '/pieces/${piece_id}/submit/', 'piece_submit_to_prize': AppPrizeConstants.prizeApiEndpoint + subdomain + '/pieces/${piece_id}/submit/',
'piece': AppConstants.apiEndpoint + 'prize/' + subdomain + '/pieces/${piece_id}/' 'piece': AppPrizeConstants.prizeApiEndpoint + subdomain + '/pieces/${piece_id}/'
}; };
} }

View File

@ -0,0 +1,9 @@
'use strict';
import AppConstants from '../../../../constants/application_constants';
let constants = {
prizeApiEndpoint: AppConstants.apiEndpoint + 'prizes/'
};
export default constants;

View File

@ -21,7 +21,7 @@ let Route = Router.Route;
let baseUrl = AppConstants.baseUrl; let baseUrl = AppConstants.baseUrl;
function getRoutes(commonRoutes) { function getRoutes() {
return ( return (
<Route name="app" path={baseUrl} handler={App}> <Route name="app" path={baseUrl} handler={App}>
<Route name="landing" path={baseUrl} handler={Landing} /> <Route name="landing" path={baseUrl} handler={Landing} />

View File

@ -166,3 +166,15 @@ function _mergeOptions(obj1, obj2) {
} }
return obj3; return obj3;
} }
/**
* Escape HTML in a string so it can be injected safely using
* React's `dangerouslySetInnerHTML`
*
* @param s the string to be sanitized
*
* Taken from: http://stackoverflow.com/a/17546215/597097
*/
export function escapeHTML(s) {
return document.createElement('div').appendChild(document.createTextNode(s)).parentNode.innerHTML;
}