|
|
@ -17,6 +17,18 @@ const messages = defineMessages({ |
|
|
|
exit_fullscreen: { id: 'video.exit_fullscreen', defaultMessage: 'Exit full screen' }, |
|
|
|
exit_fullscreen: { id: 'video.exit_fullscreen', defaultMessage: 'Exit full screen' }, |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const formatTime = secondsNum => { |
|
|
|
|
|
|
|
let hours = Math.floor(secondsNum / 3600); |
|
|
|
|
|
|
|
let minutes = Math.floor((secondsNum - (hours * 3600)) / 60); |
|
|
|
|
|
|
|
let seconds = secondsNum - (hours * 3600) - (minutes * 60); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (hours < 10) hours = '0' + hours; |
|
|
|
|
|
|
|
if (minutes < 10) minutes = '0' + minutes; |
|
|
|
|
|
|
|
if (seconds < 10) seconds = '0' + seconds; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return (hours === '00' ? '' : `${hours}:`) + `${minutes}:${seconds}`; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const findElementPosition = el => { |
|
|
|
const findElementPosition = el => { |
|
|
|
let box; |
|
|
|
let box; |
|
|
|
|
|
|
|
|
|
|
@ -83,11 +95,13 @@ export default class Video extends React.PureComponent { |
|
|
|
startTime: PropTypes.number, |
|
|
|
startTime: PropTypes.number, |
|
|
|
onOpenVideo: PropTypes.func, |
|
|
|
onOpenVideo: PropTypes.func, |
|
|
|
onCloseVideo: PropTypes.func, |
|
|
|
onCloseVideo: PropTypes.func, |
|
|
|
|
|
|
|
detailed: PropTypes.bool, |
|
|
|
intl: PropTypes.object.isRequired, |
|
|
|
intl: PropTypes.object.isRequired, |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
state = { |
|
|
|
state = { |
|
|
|
progress: 0, |
|
|
|
currentTime: 0, |
|
|
|
|
|
|
|
duration: 0, |
|
|
|
paused: true, |
|
|
|
paused: true, |
|
|
|
dragging: false, |
|
|
|
dragging: false, |
|
|
|
fullscreen: false, |
|
|
|
fullscreen: false, |
|
|
@ -117,7 +131,10 @@ export default class Video extends React.PureComponent { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
handleTimeUpdate = () => { |
|
|
|
handleTimeUpdate = () => { |
|
|
|
this.setState({ progress: 100 * (this.video.currentTime / this.video.duration) }); |
|
|
|
this.setState({ |
|
|
|
|
|
|
|
currentTime: Math.floor(this.video.currentTime), |
|
|
|
|
|
|
|
duration: Math.floor(this.video.duration), |
|
|
|
|
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
handleMouseDown = e => { |
|
|
|
handleMouseDown = e => { |
|
|
@ -143,8 +160,10 @@ export default class Video extends React.PureComponent { |
|
|
|
|
|
|
|
|
|
|
|
handleMouseMove = throttle(e => { |
|
|
|
handleMouseMove = throttle(e => { |
|
|
|
const { x } = getPointerPosition(this.seek, e); |
|
|
|
const { x } = getPointerPosition(this.seek, e); |
|
|
|
this.video.currentTime = this.video.duration * x; |
|
|
|
const currentTime = Math.floor(this.video.duration * x); |
|
|
|
this.setState({ progress: x * 100 }); |
|
|
|
|
|
|
|
|
|
|
|
this.video.currentTime = currentTime; |
|
|
|
|
|
|
|
this.setState({ currentTime }); |
|
|
|
}, 60); |
|
|
|
}, 60); |
|
|
|
|
|
|
|
|
|
|
|
togglePlay = () => { |
|
|
|
togglePlay = () => { |
|
|
@ -226,11 +245,12 @@ export default class Video extends React.PureComponent { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
render () { |
|
|
|
render () { |
|
|
|
const { preview, src, width, height, startTime, onOpenVideo, onCloseVideo, intl, alt } = this.props; |
|
|
|
const { preview, src, width, height, startTime, onOpenVideo, onCloseVideo, intl, alt, detailed } = this.props; |
|
|
|
const { progress, buffer, dragging, paused, fullscreen, hovered, muted, revealed } = this.state; |
|
|
|
const { currentTime, duration, buffer, dragging, paused, fullscreen, hovered, muted, revealed } = this.state; |
|
|
|
|
|
|
|
const progress = (currentTime / duration) * 100; |
|
|
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
return ( |
|
|
|
<div className={classNames('video-player', { inactive: !revealed, inline: width && height && !fullscreen, fullscreen })} style={{ width, height }} ref={this.setPlayerRef} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}> |
|
|
|
<div className={classNames('video-player', { inactive: !revealed, detailed, inline: width && height && !fullscreen, fullscreen })} style={{ width, height }} ref={this.setPlayerRef} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}> |
|
|
|
<video |
|
|
|
<video |
|
|
|
ref={this.setVideoRef} |
|
|
|
ref={this.setVideoRef} |
|
|
|
src={src} |
|
|
|
src={src} |
|
|
@ -267,16 +287,27 @@ export default class Video extends React.PureComponent { |
|
|
|
/> |
|
|
|
/> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
<div className='video-player__buttons left'> |
|
|
|
<div className='video-player__buttons-bar'> |
|
|
|
<button aria-label={intl.formatMessage(paused ? messages.play : messages.pause)} onClick={this.togglePlay}><i className={classNames('fa fa-fw', { 'fa-play': paused, 'fa-pause': !paused })} /></button> |
|
|
|
<div className='video-player__buttons left'> |
|
|
|
<button aria-label={intl.formatMessage(muted ? messages.unmute : messages.mute)} onClick={this.toggleMute}><i className={classNames('fa fa-fw', { 'fa-volume-off': muted, 'fa-volume-up': !muted })} /></button> |
|
|
|
<button aria-label={intl.formatMessage(paused ? messages.play : messages.pause)} onClick={this.togglePlay}><i className={classNames('fa fa-fw', { 'fa-play': paused, 'fa-pause': !paused })} /></button> |
|
|
|
{!onCloseVideo && <button aria-label={intl.formatMessage(messages.hide)} onClick={this.toggleReveal}><i className='fa fa-fw fa-eye' /></button>} |
|
|
|
<button aria-label={intl.formatMessage(muted ? messages.unmute : messages.mute)} onClick={this.toggleMute}><i className={classNames('fa fa-fw', { 'fa-volume-off': muted, 'fa-volume-up': !muted })} /></button> |
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
{!onCloseVideo && <button aria-label={intl.formatMessage(messages.hide)} onClick={this.toggleReveal}><i className='fa fa-fw fa-eye' /></button>} |
|
|
|
<div className='video-player__buttons right'> |
|
|
|
|
|
|
|
{(!fullscreen && onOpenVideo) && <button aria-label={intl.formatMessage(messages.expand)} onClick={this.handleOpenVideo}><i className='fa fa-fw fa-expand' /></button>} |
|
|
|
{(detailed || fullscreen) && |
|
|
|
{onCloseVideo && <button aria-label={intl.formatMessage(messages.close)} onClick={this.handleCloseVideo}><i className='fa fa-fw fa-times' /></button>} |
|
|
|
<span> |
|
|
|
<button aria-label={intl.formatMessage(fullscreen ? messages.exit_fullscreen : messages.fullscreen)} onClick={this.toggleFullscreen}><i className={classNames('fa fa-fw', { 'fa-arrows-alt': !fullscreen, 'fa-compress': fullscreen })} /></button> |
|
|
|
<span className='video-player__time-current'>{formatTime(currentTime)}</span> |
|
|
|
|
|
|
|
<span className='video-player__time-sep'>/</span> |
|
|
|
|
|
|
|
<span className='video-player__time-total'>{formatTime(duration)}</span> |
|
|
|
|
|
|
|
</span> |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<div className='video-player__buttons right'> |
|
|
|
|
|
|
|
{(!fullscreen && onOpenVideo) && <button aria-label={intl.formatMessage(messages.expand)} onClick={this.handleOpenVideo}><i className='fa fa-fw fa-expand' /></button>} |
|
|
|
|
|
|
|
{onCloseVideo && <button aria-label={intl.formatMessage(messages.close)} onClick={this.handleCloseVideo}><i className='fa fa-fw fa-compress' /></button>} |
|
|
|
|
|
|
|
<button aria-label={intl.formatMessage(fullscreen ? messages.exit_fullscreen : messages.fullscreen)} onClick={this.toggleFullscreen}><i className={classNames('fa fa-fw', { 'fa-arrows-alt': !fullscreen, 'fa-compress': fullscreen })} /></button> |
|
|
|
|
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|
</div> |
|
|
|