mirror of
https://github.com/ascribe/onion.git
synced 2024-11-15 01:25:17 +01:00
Merge remote-tracking branch 'origin/master' into AD-699-rename-prize-endpoint-to-prizes
This commit is contained in:
commit
2c7c78af67
@ -3,6 +3,8 @@
|
||||
import React from 'react';
|
||||
import Q from 'q';
|
||||
|
||||
import { escapeHTML } from '../../utils/general_utils';
|
||||
|
||||
import InjectInHeadMixin from '../../mixins/inject_in_head_mixin';
|
||||
import Panel from 'react-bootstrap/lib/Panel';
|
||||
import ProgressBar from 'react-bootstrap/lib/ProgressBar';
|
||||
@ -86,7 +88,29 @@ let Audio = 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: {
|
||||
preview: React.PropTypes.string.isRequired,
|
||||
url: React.PropTypes.string.isRequired,
|
||||
@ -97,7 +121,7 @@ let Video = React.createClass({
|
||||
mixins: [InjectInHeadMixin],
|
||||
|
||||
getInitialState() {
|
||||
return { ready: false };
|
||||
return { ready: false, videoMounted: false };
|
||||
},
|
||||
|
||||
componentDidMount() {
|
||||
@ -108,24 +132,40 @@ let Video = React.createClass({
|
||||
},
|
||||
|
||||
componentDidUpdate() {
|
||||
if (this.state.ready && !this.state.videojs) {
|
||||
window.videojs(React.findDOMNode(this.refs.video));
|
||||
if (this.state.ready && !this.state.videoMounted) {
|
||||
window.videojs('#mainvideo');
|
||||
/* eslint-disable */
|
||||
this.setState({videoMounted: true});
|
||||
/* eslint-enable*/
|
||||
}
|
||||
},
|
||||
|
||||
componentWillUnmount() {
|
||||
window.videojs('#mainvideo').dispose();
|
||||
},
|
||||
|
||||
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() {
|
||||
if (this.state.ready) {
|
||||
return (
|
||||
<video ref="video" className="video-js vjs-default-skin" poster={this.props.preview}
|
||||
controls preload="none" width="auto" height="auto">
|
||||
{this.props.extraData.map((data, i) =>
|
||||
<source key={i} type={'video/' + data.type} src={data.url} />
|
||||
)}
|
||||
</video>
|
||||
<div dangerouslySetInnerHTML={{__html: this.prepareVideoHTML() }}/>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
|
@ -117,8 +117,7 @@ let AccountSettings = React.createClass({
|
||||
<InputCheckbox
|
||||
defaultChecked={this.state.currentUser.profile.hash_locally}>
|
||||
<span>
|
||||
{' ' + getLangText('Enable hash option for slow connections. ' +
|
||||
'Computes and uploads a hash of the work instead.')}
|
||||
{' ' + getLangText('Enable hash option, e.g. slow connections or to keep piece private')}
|
||||
</span>
|
||||
</InputCheckbox>
|
||||
</Property>
|
||||
|
@ -166,3 +166,15 @@ function _mergeOptions(obj1, obj2) {
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user