Skip to content

Instantly share code, notes, and snippets.

@kaneel
Last active January 11, 2019 10:33
Show Gist options
  • Save kaneel/7df4c1dadff93d97f341 to your computer and use it in GitHub Desktop.
Save kaneel/7df4c1dadff93d97f341 to your computer and use it in GitHub Desktop.
Video.js

#TL;DR

/!\ Still a stub, things may change

Module that have bunch of video related objects. Every component is broken into pieces. There is a view for controls, one for poster frames, one for the youtube player and a final one for containing all of them.

The goal is to have the possiblity to create video players with or without controls or poster frames.

Quick access

#Main script

Scrip is located in js/src/commons/video.js Get all video container nodes following this query

var videoContainers = document.querySelectorAll(".rt_video_container")

It will check for data- attributes in order to get locales and other things (like the poster frame src)

<div class="rt_video_container"
  data-player-options="videoId=videoid"
  data-poster-options="src=imagesrc"
  data-controls-options="play=play&amp;stop=stop&amp;mute=mute&amp;unmute=unmute&amp;pause=pause">
  <!-- Et ici, on peut mettre des liens, des images… SEO all the thing… -->
</div>

It's relying heavily on bus events… so the controls will dispatch play/stop/pause/seek events, passing the right video id and video.js links events to behaviours. This way, most of the video components are self-aware and don't need other bits of components in order to work.

Example:

eventBus.addEventListener('video:unmute', function(e) {
  chooseVideo(e.detail.id, function(video) {
    video.player.isMuted = false
    if (typeof video.controls != 'undefined')
      video.controls.toggleSound(true)
  })
})

#YTPLAYER

This is trying to act like a façade and is a ZView.

var player = new YTPlayerZView({
  videoId: videoId
  playerVars: {}
})

##Properties

Some of the following properties are declared with getters/setters… meaning that when changing the volume it will also execute an other function. This is perfect for avoiding API differences.

  • _isPlaying: boolean
  • isMuted: get / set. setter takes a boolean and will mute/unmute
  • currentTime: number
  • duration: number, will check once for the video duration then return the saved value.
  • volume: number. get/set. setter takes a number and will set the video volume using YT API
  • fullscreen: methods that will change iframe size. Not the best™ yet.
  • ready: promise that is resolved when the player is ready.

##Methods

  • play
  • pause
  • stop
  • seek: Takes percent number and seekAheadBool boolean
  • kill: will destroy the YT player and purge the object

##Events

The façade also takes care of the state-change events of the YT API, dispatching them through "player:state-changed" but for some ease of use, it's also emitting these events

  • video:has-started
  • video:has-ended
  • video:is-paused
  • video:is-playing

Poster frame

A ZView for creating a poster frame. It's basically a ZView dispatching events when clicked and toggling its visibility.

this.root.addEventListener('click', this._clickhandler = function() {
  eventBus.dispatchEvent('video:start', {id: locales.videoId})
}.bind(this))

Controls

A ZView for creating controls. Probably the messiest ZView due to its complexity. Declare a lot of DOM events for tracking mousemove, enter and leave.

The same as the poster frame, it will dispatch video events.

this.stopButton.addEventListener('click', function() {
  eventBus.dispatchEvent('video:stop', {id: this.model.getItem('videoId')})
}.bind(this))

Controls properties

  • active: returns true|false
  • visibility: returns true|false

Controls methods

  • setActive: true|false, sets the controls as active or not (different as visible or not)
  • setVisibility: true|false, show/hide controls
  • togglePlay: true|false, will toggle button text and action
  • toggleSound: true|false, will toggle button text and action
  • update: Takes time in seconds, duration in seconds; update the timeline
  • show: self-explanatory
  • hide: self-explanatory
  • kill: self-explanatory

PF Properties

More like "property"

  • visibility: returns either true or false.

PF Methods

  • show: returns a promise
  • hide: returns a promise
  • kill

#Container

This is the video container. It's used to hold every into a single wrapper. It is used to hook some views together. Basically, on player.ready, it will check if sound is muted or not, in order to toggle the controls, and will throw a timer for the control timeline view to be updated frequently.

It also created an overlay view and wait for player.ready to be resolved to hide it and remove it from the document. This way, you ensure the video is really ready before letting the user interact with the poster frame.

##Constructor

This one is slightly different that the other ones… so far, it takes the locales({}) and three other arguments: player, controls and poster. It also register an event on fullscreenchange events.

Methods

  • fullscreen: will toggle fullscreen mode on container.
  • toggle: to toggle poster / controls
  • kill: kill all subviews.
'use strict'
var Serializer = require('korbutJS/src/Serializer').Serializer
var requestAnimationFrame = require("korbutJS/src/dom-utils/requestAnimationFrame").requestAnimationFrame
var LibVid = require('../lib/Video')
var YTPlayerZView = LibVid.YTPlayerZView
var VideoControlsZView = LibVid.VideoControlsZView
var PosterFrameZView = LibVid.PosterFrameZView
var YTVideoContainerZView = LibVid.YTVideoContainerZView
var eventBus = new (require('../lib/SEventBus').SEventBus)
var _ = require('../lib/utils')
var device = require('../globals').device
var videoContainers = document.querySelectorAll(".rt_video_container")
var videos = {}
for (var i = videoContainers.length; i--; ) void function(videoContainer, playerOptions, playerVars, controlsOptions, posterOptions, container, player, controls, poster) {
playerOptions = videoContainer.getAttribute('data-player-options')||false
playerVars = videoContainer.getAttribute('data-player-vars')||false
controlsOptions = videoContainer.getAttribute('data-controls-options')||false
posterOptions = videoContainer.getAttribute('data-poster-options')||false
if (playerOptions) {
playerOptions = playerOptions ? Serializer.objectify(playerOptions) : {}
playerVars = playerVars ? Serializer.objectify(playerVars) : {}
if (device.md.mobile())
playerOptions.playerVars = jQuery.extend({controls: 0, modestbranding:1, allowfullscreen: 'true', wmode: 'opaque', showinfo:0, iv_load_policy: 3}, playerVars)
else
playerOptions.playerVars = jQuery.extend({controls: 0, modestbranding:1, wmode: 'opaque', showinfo:0, iv_load_policy: 3}, playerVars)
player = new YTPlayerZView(playerOptions)
// check for controls
if (controlsOptions && !device.md.mobile()) {
controlsOptions = controlsOptions ? Serializer.objectify(controlsOptions) : {}
controls = new VideoControlsZView(controlsOptions)
controls.model.setItem('videoID', player.uid)
}
// check for poster frame
if(posterOptions && !device.md.mobile()) {
posterOptions = posterOptions ? Serializer.objectify(posterOptions) : {}
poster = new PosterFrameZView(posterOptions)
poster.model.setItem('videoID', player.uid)
}
// create container
container = new YTVideoContainerZView({}, player, controls||false, poster||false)
videos[player._uid] = container
// and append
videoContainer.parentNode.replaceChild(container.root, videoContainer)
} else {
console.log(new Error('videos: no player options'), videoContainer)
}
}(videoContainers[i])
jQuery(document).on('webkitfullscreenchange mozfullscreenchange fullscreenchange MSFullscreenChange', function(e, fullScreen, fullscreenEl) {
fullScreen = _.fullscreenEnabled()
fullscreenEl = _.fullscreenElement()
// iterate over videos
eachVideos(function(item) {
// check if fullscreen mode and if the video.root is the fullscreen element.
if (fullScreen && item.root == fullscreenEl) {
requestAnimationFrame(function() {
// add class for fullscreen mode
item.root.className += YTVideoContainerZView._FS_CLASS
// change width and height of video
item.player.fullscreen(fullScreen)
// toggle fullscreen button
item.controls.toggleFS(false)
this._fullscreen = true
})
} else if (!fullScreen && item.fullscreen) {
requestAnimationFrame(function() {
item.player.fullscreen(fullScreen)
item.root.className = item.root.className.replace(YTVideoContainerZView._FS_CLASS, '')
item.controls.toggleFS(true)
window.scrollTo(0, item.savedScroll)
item._fullscreen = false
})
}
})
})
eventBus.addEventListener('video:play', function(e) {
chooseVideo(e.detail.id, function(video) {
video.player.play()
})
})
eventBus.addEventListener('video:fullscreen-enter', function(e) {
chooseVideo(e.detail.id, function(video) {
video.fullscreen = true
})
})
eventBus.addEventListener('video:fullscreen-exit', function(e) {
chooseVideo(e.detail.id, function(video) {
video.fullscreen = false
})
})
eventBus.addEventListener('video:is-playing', function(e) {
chooseVideo(e.detail.id, function(video) {
video.toggle(true, false)
})
})
eventBus.addEventListener('video:stop', function(e) {
chooseVideo(e.detail.id, function(video) {
video.player.stop()
video.toggle(false)
})
})
eventBus.addEventListener('video:start', function(e) {
chooseVideo(e.detail.id, function(video) {
video.player.play()
video.toggle(true)
})
})
eventBus.addEventListener('video:end', function(e) {
chooseVideo(e.detail.id, function(video) {
video.toggle(false)
})
})
eventBus.addEventListener('video:pause', function(e) {
chooseVideo(e.detail.id, function(video) {
video.player.pause()
})
})
eventBus.addEventListener('video:mute', function(e) {
chooseVideo(e.detail.id, function(video) {
video.player.isMuted = true
if (typeof video.controls != 'undefined')
video.controls.toggleSound(false)
})
})
eventBus.addEventListener('video:unmute', function(e) {
chooseVideo(e.detail.id, function(video) {
video.player.isMuted = false
if (typeof video.controls != 'undefined')
video.controls.toggleSound(true)
})
})
// bind seek
eventBus.addEventListener('video:seek', function(e) {
chooseVideo(e.detail.id, function(video) {
video.player.seek(e.detail.time, true)
})
}.bind(this))
function chooseVideo(id, cb) {
if (typeof videos[id] != "undefined") {
cb(videos[id])
}
}
function eachVideos(cb) {
var i = 0
for (var k in videos) if (videos.hasOwnProperty(k)) {
cb(videos[k], i, videos)
}
}
'use strict'
var Promise = require('korbutJS/src/Promise').Promise
var klass = require('korbutJS/src/ZView').class
var ZView = require('korbutJS/src/ZView').ZView
var Transition = require('korbutJS/src/Transition').Transition
var ClientRect = require('korbutJS/src/ClientRect').ClientRect
var requestAnimationFrame = require("korbutJS/src/dom-utils/requestAnimationFrame").requestAnimationFrame
var _ = require('./utils')
var eventBus = new (require('./SEventBus').SEventBus)
var YTAPI = require('../globals').YTAPI
var Button = ZView.extend(function(statics) {
return {
constructor: function(locales) {
ZView.apply(this, arguments)
this.query('button').addEventListener('click', this._clickhandler = function() {
this.dispatchEvent('click')
}.bind(this))
}
, _template: 'button@button>span{$text}'
, kill: { enumerable: true,
value: function() {
this.query('button').removeEventListener('click', this._clickhandler)
this.purge(true)
}
}
}
})
var Timeline = ZView.extend(function(statics) {
return {
constructor: function() {
ZView.apply(this, arguments)
}
, _template: '.rt_video_player__progress'
, update: { enumerable: true,
value: function(v) {
this.root.style.width = v+"%"
}
}
, kill: { enumerable: true,
value: function() {
this.purge(true)
}
}
}
})
var Overlay = ZView.extend(function(statics) {
return {
constructor: function() {
ZView.apply(this, arguments)
this.transition = new Transition(this.root, {opacity: '800ms ease-out'})
}
, _template: '.rt_video_overlay'
, hide: { enumerable: true,
value: function() {
return this.transition.animate({opacity: 0}).then(function() {
return new Promise(function(resolve) {
requestAnimationFrame(function() {
resolve()
})
})
})
}
}
, kill: { enumerable:true,
value: function() {
// purge transition
this.transition.purge()
this.purge(true)
}
}
}
})
module.exports.YTPlayerZView = ZView.extend(function(statics) {
statics._NOT_STARTED = -1
statics._ENDED = 0
statics._PLAYING = 1
statics._PAUSED = 2
statics._BUFFERING = 3
statics._CUED = 5
return {
constructor: function(locales) {
if (typeof locales.videoId == 'undefined') return new Error('Video: Id not given')
ZView.apply(this, arguments)
this.addEventListener('player:state-changed', this._onstatechangedhandler = function(e, YTE) {
YTE = e.detail.YTEvent
if (YTE.data == module.exports.YTPlayerZView._ENDED) {
eventBus.dispatchEvent('video:has-ended', {id: this.uid})
}
if (YTE.data == module.exports.YTPlayerZView._NOT_STARTED) {
eventBus.dispatchEvent('video:has-started', {id: this.uid})
}
if (YTE.data == module.exports.YTPlayerZView._PAUSE) {
eventBus.dispatchEvent('video:is-paused', {id: this.uid})
}
if (YTE.data == module.exports.YTPlayerZView._PLAYING) {
eventBus.dispatchEvent('video:is-playing', {id: this.uid})
}
if (YTE.data == module.exports.YTPlayerZView._NOT_STARTED || YTE.data == module.exports.YTPlayerZView._ENDED || YTE.data == module.exports.YTPlayerZView._PAUSED) {
this.isPlaying = false
} else if (YTE.data == module.exports.YTPlayerZView._PLAYING) {
this.isPlaying = true
}
}.bind(this))
if (!locales.height) this.model.setItem('height', 390)
if (!locales.width) this.model.setItem('width', 640)
// add readyness
this.ready = new Promise(function(resolve, reject) {
// check if API is loaded
YTAPI.load().then(function(YT) {
// on player:ready, resolve ready promise
this.addEventListener('player:ready', this._onreadyhandler = function() { resolve() })
// instantiate player
this._YTPLAYER = new YT.Player(this.root, {
height: this.model.getItem('height')
, width: this.model.getItem('width')
, videoId: locales.videoId
, playerVars: locales.playerVars||{}
, events: {
'onReady': this._playerReady.bind(this),
'onStateChange': this._stateChanged.bind(this)
}
})
}.bind(this))
}.bind(this))
}
, _template: '.rt_video_player'
, isPlaying: {enumerable: true,
get: function() {
return this._isPlaying || (this._isPlaying = false)
}
, set: function(v) {
this._isPlaying = v
}
}
, isMuted: { enumerable: true,
get: function() {
return this._isMuted
}
, set: function(v) {
if (v && this._isMuted != v)
this._isMuted = v, this._YTPLAYER.mute()
else if (!v && this._isMuted != v)
this._isMuted = v, this._YTPLAYER.unMute()
}
}
, currentTime: { enumerable: true,
get: function(currTime) {
currTime = this.currentTime = this._YTPLAYER.getCurrentTime()
return currTime
}
, set: function(v) {
this._currentTime = v
}
}
, duration: { enumerable: true
, get: function() {
return this._duration || (this._duration = this._YTPLAYER.getDuration())
}
}
, volume: { enumerable: true
, get: function() {
return this._YTPLAYER.getVolume(v)
}
, set: function(v) {
return this._YTPLAYER.setVolume(v)
}
}
, _playerReady: { enumerable: true,
value: function(e) {
this.dispatchEvent('player:ready', {YTEvent:e})
}
}
, _stateChanged: { enumerable: true,
value: function(e) {
this.dispatchEvent('player:state-changed', {YTEvent:e})
}
}
, play: { enumerable: true,
value: function() {
this._YTPLAYER.playVideo()
}
}
, pause: { enumerable: true,
value: function() {
this._YTPLAYER.pauseVideo()
}
}
, stop: { enumerable: true,
value: function() {
this._YTPLAYER.stopVideo()
}
}
, seek: { enumerable: true,
value: function(percent, seekAheadBool) {
this._YTPLAYER.seekTo(this.duration*percent, seekAheadBool||false)
}
}
, fullscreen: { enumerable: true,
value: function(bool) {
var i, w, h
i = this._YTPLAYER.getIframe()
if (bool) {
i.width = '100%'
i.height = '100%'
} else {
i.width = this.model.getItem('width')
i.height = this.model.getItem('height')
}
}
}
, kill: { enumerable: true,
value: function() {
this.purge(true)
}
}
}
})
module.exports.PosterFrameZView = ZView.extend(function(statics) {
statics._CLASS_VISIBLE = ' rt_video_poster--visible'
statics._HIDDEN = {opacity:0}
statics._VISIBLE = {opacity:1}
return {
constructor: function(locales) {
ZView.apply(this, arguments)
this.transition = new Transition(this.root, {opacity: '800ms ease-out'})
this.root.addEventListener('click', this._clickhandler = function() {
eventBus.dispatchEvent('video:start', {id: this.model.getItem('videoID')})
}.bind(this))
this._visibility = false
}
, _template: '.rt_video_poster>figure.rt_video_poster__figure>img.rt_video_poster__img[src=$src][alt=]'
, visibility: { enumerable: true,
get: function() {
return this._visibility
}
}
, show: { enumerable: true,
value: function(p) {
return this.transition.animate( module.exports.VideoControlsZView._VISIBLE ).then(function() {
this.root.className += module.exports.PosterFrameZView._CLASS_VISIBLE
this._visibility = true
return new Promise(function(resolve) {
requestAnimationFrame(function() { resolve() })
})
}.bind(this))
}
}
, hide: { enumerable: true,
value: function(p) {
return this.transition.animate( module.exports.VideoControlsZView._HIDDEN ).then(function() {
this._visibility = false
this.root.className = this.root.className.replace(module.exports.PosterFrameZView._CLASS_VISIBLE, '')
return new Promise(function(resolve) {
requestAnimationFrame(function() { resolve() })
})
}.bind(this))
}
}
, kill: { enumerable: true,
value: function() {
this.root.removeEventListener('click', this._clickhandler)
// purge transition
this.transition.purge()
this.purge(true)
}
}
}
})
module.exports.VideoControlsZView = ZView.extend(function(statics) {
statics._CLASS_VISIBLE = ' rt_video_controls--visible'
statics._CLASS_ACTIVE = ' rt_video_controls--active'
statics._CLASS_PAUSE = ' rt_video_controls__play--pause'
statics._CLASS_UNMUTE = ' rt_video_controls__mute--unmute'
statics._CLASS_ENTERFS = ' rt_video_controls__mute--enter-fullscreen'
statics._TIMER_MS = 2000
statics._HIDDEN = {opacity:0}
statics._VISIBLE = {opacity:1}
function setTimer() {
this._visibilityTimer = setTimeout(function() {
this.setVisibility(false)
}.bind(this), module.exports.VideoControlsZView._TIMER_MS)
}
return {
constructor: function(locales) {
ZView.apply(this, arguments)
this.transition = new Transition(this.root, {opacity: '.4s ease-out'})
// define button
this.togglePlayButton = new Button({text: this.model.getItem('play')})
this.toggleSoundButton = new Button({text: this.model.getItem('mute')})
this.stopButton = new Button({text: this.model.getItem('stop')})
this.fsButton = new Button({text: this.model.getItem('fullscreen')})
this.timeline = new Timeline
this.fsButton.addEventListener('click', function() {
eventBus.dispatchEvent('video:fullscreen-'+this.fsButton.model.getItem('action'), {id: this.model.getItem('videoID')})
}.bind(this))
this.togglePlayButton.addEventListener('click', function() {
eventBus.dispatchEvent('video:'+this.togglePlayButton.model.getItem('action'), {id: this.model.getItem('videoID')})
}.bind(this))
this.toggleSoundButton.addEventListener('click', function() {
eventBus.dispatchEvent('video:'+this.toggleSoundButton.model.getItem('action'), {id: this.model.getItem('videoID')})
}.bind(this))
this.stopButton.addEventListener('click', function() {
eventBus.dispatchEvent('video:stop', {id: this.model.getItem('videoID')})
}.bind(this))
this.query('timeline').addEventListener('click', this._timelinehandler = function(e, cR) {
cR = new ClientRect({node: this.query('timeline')})
cR.compute(e, function(err, matrix) {
eventBus.dispatchEvent('video:seek', {id: this.model.getItem('videoID'), time: Math.abs(matrix.W.x)/matrix.width})
}.bind(this))
}.bind(this))
this.root.addEventListener('click', this._wholeclickhandler = function(e) {
if (e.target == this.root) {
eventBus.dispatchEvent('video:'+this.togglePlayButton.model.getItem('action'), {id: this.model.getItem('videoID')})
}
}.bind(this))
this.root.addEventListener('mousemove', this._mousemovehandler = function() {
clearTimeout(this._visibilityTimer||null)
clearTimeout(this._moveTimer||null)
if (!this.visibility && this.active && !this._keepoverlay) {
this.setVisibility(true)
} else if (this.active && !this._keepoverlay) {
this._moveTimer = setTimeout(function() {
setTimer.call(this)
}.bind(this), 500)
}
}.bind(this))
jQuery(this.query('controlwrapper')).on('mouseenter, mouseover', 'button', this._buttonenterhandler = function() {
this._keepoverlay = true
}.bind(this))
jQuery(this.query('controlwrapper')).on('mouseleave', 'button', this._buttonleavehandler = function() {
this._keepoverlay = false
}.bind(this))
this.query('controlwrapper').addEventListener('click', this._wholeclickhandlercontrols = function(e) {
if (e.target == this.query('controlwrapper')) {
eventBus.dispatchEvent('video:'+this.togglePlayButton.model.getItem('action'), {id: this.model.getItem('videoID')})
}
}.bind(this))
this.root.addEventListener('mouseenter', this._mouseenterhandler = function() {
if (!this.visibility && this.active) {
clearTimeout(this._visibilityTimer||null)
clearTimeout(this._moveTimer||null)
this.setVisibility(true)
}
}.bind(this))
this.root.addEventListener('mouseleave', this._mouseouthandler = function() {
if (this.visibility && this.active) {
clearTimeout(this._visibilityTimer||null)
clearTimeout(this._moveTimer||null)
this.setVisibility(false)
}
}.bind(this))
this.togglePlay(true)
this.toggleFS(true)
this._keepoverlay = false
this.setVisibility(false)
this.setActive(false)
// append buttons
this.query('togglePlayButton').appendChild(this.togglePlayButton.root)
this.query('toggleSoundButton').appendChild(this.toggleSoundButton.root)
this.query('stopButton').appendChild(this.stopButton.root)
this.query('fsButton').appendChild(this.fsButton.root)
this.query('timeline').appendChild(this.timeline.root)
}
, _template: '.rt_video_controls@controls>\
(.rt_video_controls__wrapper@controlwrapper > \
.rt_video_controls__button-container@togglePlayButton\
+ .rt_video_controls__button-container@toggleSoundButton\
+ .rt_video_controls__button-container@fsButton\
+ .rt_video_controls__button-container@stopButton)\
+ (div.rt_video_player__timeline@timeline)'
, active: { enumerable: true,
get: function() {
return this._active || (this._active = false)
}
}
, visibility: { enumerable: true,
get: function() {
return this._visibility || null
}
}
, setActive: { enumerable: true,
value: function(v, v2) {
this._active = v
if (v) {
this.root.className += module.exports.VideoControlsZView._CLASS_ACTIVE
if (!v2)
return this.setVisibility(true)
else
return new Promise(function(resolve) {resolve()})
} else {
this.root.className = this.root.className.replace(module.exports.VideoControlsZView._CLASS_ACTIVE, '')
return this.setVisibility(false)
}
}
}
, setVisibility: { enumerable: true,
value: function(v) {
if (v)
return this.show()
else
return this.hide()
}
}
, togglePlay: { enumerable: true,
value: function(playBool, button) {
button = this.togglePlayButton
if (playBool) {
button.model.setItem('action','play')
button.model.setItem('text', this.model.getItem('play'))
button.query("button").className =
button.query("button").className.replace(module.exports.VideoControlsZView._CLASS_PAUSE,'')
} else {
button.model.setItem('action','pause')
button.model.setItem('text', this.model.getItem('pause'))
button.query("button").className += module.exports.VideoControlsZView._CLASS_PAUSE
}
}
}
, toggleFS: { enumerable: true,
value: function(playBool, button) {
button = this.fsButton
if (playBool) {
button.model.setItem('action','enter')
button.model.setItem('text', this.model.getItem('enter-fs'))
button.query("button").className =
button.query("button").className.replace(module.exports.VideoControlsZView._CLASS_ENTERFS,'')
} else {
button.model.setItem('action','exit')
button.model.setItem('text', this.model.getItem('exit-fs'))
button.query("button").className += module.exports.VideoControlsZView._CLASS_ENTERFS
}
}
}
, toggleSound: { enumerable: true,
value: function(soundBool, button) {
button = this.toggleSoundButton
if (soundBool) {
button.model.setItem('action','mute')
button.model.setItem('text', this.model.getItem('mute'))
button.query("button").className =
button.query("button").className.replace(module.exports.VideoControlsZView._CLASS_UNMUTE,'')
} else {
button.model.setItem('action','unmute')
button.model.setItem('text', this.model.getItem('unmute'))
button.query("button").className += module.exports.VideoControlsZView._CLASS_UNMUTE
}
}
}
, update: { enumerable: true,
value: function(time, durr) {
this.timeline.update((time/durr)*100)
}
}
, show: { enumerable: true,
value: function() {
this.root.className += module.exports.VideoControlsZView._CLASS_VISIBLE
this._visibility = true
return this.transition.animate( module.exports.VideoControlsZView._VISIBLE ).then(function() {
setTimer.call(this)
return new Promise(function(resolve) {
requestAnimationFrame(function() { resolve() })
})
}.bind(this))
}
}
, hide: { enumerable: true,
value: function() {
if (this._visibility)
return this.transition.animate( module.exports.VideoControlsZView._HIDDEN ).then(function() {
this.root.className = this.root.className.replace(module.exports.VideoControlsZView._CLASS_VISIBLE, '')
this._visibility = false
return new Promise(function(resolve) {
requestAnimationFrame(function() { resolve() })
})
}.bind(this))
else return new Promise(function(resolve) {resolve()})
}
}
, kill: { enumerable: true,
value: function() {
this.root.removeEventListener('mousemove', this._mousemovehandler)
this.root.removeEventListener('mouseenter', this._mousemovehandler)
this.root.removeEventListener('mouseout', this._mousemovehandler)
this.root.removeEventListener('click', this._wholeclickhandler)
this.query('timeline').removeEventListener('click', this._timelinehandler)
this.query('controlwrapper').addEventListener('click', this._wholeclickhandlercontrols)
// THESE TWO JQUERY EVENTS
jQuery(this.query('controlwrapper')).off('mouseenter, mouseover', 'button', this._buttonenterhandler)
jQuery(this.query('controlwrapper')).off('mouseleave', 'button', this._buttonleavehandler)
// kill sub views
this.timeline.kill()
this.togglePlayButton.kill()
this.toggleSoundButton.kill()
this.stopButton.kill()
// purge transition
this.transition.purge()
// purge view
this.purge(true)
}
}
}
})
module.exports.YTVideoContainerZView = ZView.extend(function(statics) {
statics._READY_CLASS = ' rt_video_container--ready'
statics._FS_CLASS = ' rt_video_container--fs'
return {
constructor: function(locales, player, controls, poster) {
ZView.apply(this, arguments)
this.player = player
this.overlay = new Overlay
player.ready.then(function() {
if (typeof controls == 'object') {
// set the toggleSound as the right value
if (player.isMuted) {
controls.toggleSound(false)
} else {
controls.toggleSound(true)
}
player.addEventListener('player:state-changed', this._onstatechangedhandler = function(e, YTE) {
YTE = e.detail.YTEvent
// if player hasn't started, has ended, or is paused
if (YTE.data == module.exports.YTPlayerZView._NOT_STARTED || YTE.data == module.exports.YTPlayerZView._ENDED || YTE.data == module.exports.YTPlayerZView._PAUSED) {
// switch togglePlay button text
controls.togglePlay(true)
// clear setTimeout
clearTimeout(this._controlsUpdateSTO||null);
} else if (YTE.data == module.exports.YTPlayerZView._PLAYING) {
// set right text for togglePlay
controls.togglePlay(false)
// STO every 500ms to get the actual time of the video, will update approx every seconds.
this._controlsUpdateSTO = setTimeout(function upd() {
// update controls timeline
controls.update(player.currentTime, player.duration)
this._controlsUpdateSTO = setTimeout(upd.bind(this))
}.bind(this), 500)
}
}.bind(this))
}
if (typeof controls == 'object') {
this.controls = controls
this.root.appendChild(controls.root)
}
this.overlay.hide()
// in waiting for a fix on Transition :)
setTimeout(function() {
this.overlay.kill()
}.bind(this), 800)
this.root.className += ' '+module.exports.YTVideoContainerZView._READY_CLASS
}.bind(this))
this.root.appendChild(this.overlay.root)
if (typeof poster == 'object') {
this.poster = poster
this.root.appendChild(poster.root)
}
this.root.appendChild(player.root)
}
, _template: '.rt_video_container'
, toggle: { enumerable: true,
value: function(boolControls, boolVisibileControls) {
if (boolControls) {
if (typeof this.poster != "undefined") {
return this.poster.hide().then(function() {
if (typeof this.controls != "undefined")
return this.controls.setActive(true, !!boolVisibileControls)
}.bind(this))
} else if (typeof this.controls != "undefined") {
return this.controls.setActive(true, !!boolVisibileControls)
}
} else {
if (typeof this.controls != 'undefined') {
return this.controls.setActive(false).then(function() {
if (typeof this.poster != "undefined") {
return this.poster.show()
}
}.bind(this))
} else if (typeof this.poster != "undefined") {
return this.poster.show()
}
}
}
}
, fullscreen: { enumerable: true,
get: function() {
return this._fullscreen || (this._fullscreen = false)
}
, set: function(v, element) {
element = element||this.root
if (v) {
this.savedScroll = window.pageYOffset || window.scrollY || document.documentElement.scrollTop || document.body.scrollTop || 0
_.requestFullscreen(element)
} else {
_.exitFullscreen()
}
}
}
, kill: { enumerable: true,
value: function() {
this.player.kill()
if (typeof this.controls != 'undefined')
this.controls.kill()
if (typeof this.poster != 'undefined')
this.poster.kill()
this.purge(true)
}
}
}
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment