Skip to content

Instantly share code, notes, and snippets.

@itrelease
Created December 15, 2014 11:04
Show Gist options
  • Save itrelease/8788e39ce29aa367abe0 to your computer and use it in GitHub Desktop.
Save itrelease/8788e39ce29aa367abe0 to your computer and use it in GitHub Desktop.
'use strict';
var React = require('react'),
createStoreMixin = require('../mixins/createStoreMixin'),
ClassNameMixin = require('../mixins/ClassNameMixin'),
PlayerActionCreators = require('../actions/PlayerActionCreators'),
PlayerStore = require('../stores/PlayerStore'),
StampImageMixin = require('../mixins/StampImageMixin'),
PureRenderMixin = require('../mixins/PureRenderMixin'),
BlurredBackground = require('../atoms/BlurredBackground'),
Icon = require('../atoms/Icon'),
Button = require('../atoms/Button'),
formatTime = require('../utils/formatTime'),
noop = require('../utils/noop'),
{ PropTypes } = React;
var IMAGE_SIZES = {
'default': 480,
'xs': 640,
'sm': 992,
'md': 1024,
'lg': 1024,
'xl': 1280
};
var Video = React.createClass({
mixins: [
createStoreMixin(PlayerStore),
StampImageMixin,
ClassNameMixin,
PureRenderMixin
],
propTypes: {
uuid: PropTypes.string.isRequired,
sourceId: PropTypes.number.isRequired,
width: PropTypes.number.isRequired,
height: PropTypes.number.isRequired,
background: PropTypes.shape({
url: PropTypes.string.isRequired,
size: PropTypes.object.isRequired,
colors: PropTypes.object.isRequired
}).isRequired
},
className: 'stamp-Video',
getMediaId() {
return this.props.uuid;
},
getEmbedMaxHeight() {
var height = (this.props.height < 960 / this.props.width * this.props.height) ?
this.props.height :
960 / this.props.width * this.props.height;
return height < 540 ? 540 : height;
},
getInitialState() {
return {
isIframeVisible: false
};
},
getDefaultProps() {
return {
isImageInLightbox: noop
};
},
getStateFromStores() {
return {
isPlaying: PlayerStore.isPlaying(this.getMediaId())
};
},
getCSSModifiers() {
return [
this.state.isPlaying && 'playing',
this.state.isIframeVisible && 'isIframeVisible'
];
},
getContentWindow() {
return this.refs.iframe.getDOMNode().contentWindow;
},
getImageSizes() {
return IMAGE_SIZES;
},
getImage: function () {
return this.props.background;
},
componentDidMount() {
window.addEventListener('message', this.handleIframeMessage);
},
componentWillUnmount() {
this.pause();
window.removeEventListener('message', this.handleIframeMessage);
},
componentWillUpdate(nextProps, nextState) {
if (this.state.isPlaying && !nextState.isPlaying) {
this.postMessage('pause');
} else if (!this.state.isPlaying && nextState.isPlaying) {
this.postMessage('play');
}
},
render() {
var src = `http://player.vimeo.com/video/${this.props.sourceId}`,
height = this.getEmbedMaxHeight();
return (
<div className={this.getClassName()}
onClick={this.handlePlayClick}
data-scroll-anchor>
<div className='stamp-Video-bg'
style={{
backgroundImage: this.getBackgroundImageUrl()
}} />
<div className='stamp-Video-blurredBg'>
<BlurredBackground background={this.getImage()} />
</div>
{this.renderLoaderImg()}
<div className='stamp-Video-box'>
<div className='stamp-Video-embed'
style={{
paddingBottom: (height * 100 / 960) + '%'
}}>
<iframe src={src}
frameBorder='0'
webkitAllowFullScreen
mozAllowFullscreen
allowFullScreen
ref='iframe' />
<Button className='stamp-Video-play'
context='Video'
onClick={this.handlePlayClick}
size='xxxlarge'
color='black'
overlay
round>
<Icon name='play'
mode='stroke'
size='large' />
<div className='stamp-Video-duration utils--hideOnMobile'>
{formatTime(this.props.duration)}
</div>
</Button>
</div>
</div>
<div className='stamp-Video-meta'>
<div className='stamp-Video-title'>{this.props.title}</div>
<div className='stamp-Video-author'>{this.props.username}</div>
</div>
</div>
);
},
handlePlayClick() {
if (this.state.isPlaying) {
this.pause();
} else {
this.play();
}
this.setState({
isIframeVisible: true
});
},
handleIframeMessage(e) {
if (e.source !== this.getContentWindow()) {
return;
}
var data = JSON.parse(e.data);
switch (data.event) {
case 'ready':
this.postMessage('addEventListener', 'play');
this.postMessage('addEventListener', 'playProgress');
this.postMessage('addEventListener', 'pause');
this.postMessage('addEventListener', 'finish');
break;
case 'play':
this.play();
break;
case 'playProgress':
this.handleVideoProgress(data.data);
break;
case 'pause':
case 'finish':
this.pause();
break;
}
},
handleVideoProgress: function (data) {
// We want to rewind instead of showing related videos.
// It's too late to do this in `finish` handler or when `data.progress` is 1.
if (data.duration - data.seconds > 0.3) {
return;
}
// This works better than sending `unload` because it doesn't flicker:
this.postMessage('seekTo', 0);
this.postMessage('pause');
// Prevents play button stuck in "playing" state in Firefox:
requestAnimationFrame(() => {
this.postMessage('pause');
});
},
play() {
PlayerActionCreators.play(this.getMediaId());
},
pause() {
PlayerActionCreators.stop(this.getMediaId());
},
postMessage(action, value) {
var data = {
method: action,
value: value
};
var message = JSON.stringify(data),
contentWindow = this.getContentWindow(),
url = `http://player.vimeo.com/video/${this.props.sourceId}`;
contentWindow.postMessage(message, url);
}
});
module.exports = Video;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment