A/B Test video tutorial styles
This commit is contained in:
parent
d494dc9c79
commit
9d4c3cc163
4 changed files with 65 additions and 31 deletions
app
|
@ -313,6 +313,8 @@
|
||||||
save_load_tab: "Save/Load"
|
save_load_tab: "Save/Load"
|
||||||
options_tab: "Options"
|
options_tab: "Options"
|
||||||
guide_tab: "Guide"
|
guide_tab: "Guide"
|
||||||
|
guide_video_tutorial: "Video Tutorial"
|
||||||
|
guide_tips: "Tips"
|
||||||
multiplayer_tab: "Multiplayer"
|
multiplayer_tab: "Multiplayer"
|
||||||
auth_tab: "Sign Up"
|
auth_tab: "Sign Up"
|
||||||
inventory_caption: "Equip your hero"
|
inventory_caption: "Equip your hero"
|
||||||
|
|
|
@ -139,6 +139,13 @@ module.exports = class User extends CocoModel
|
||||||
else
|
else
|
||||||
@subscribeCopyGroup = 'original'
|
@subscribeCopyGroup = 'original'
|
||||||
@subscribeCopyGroup
|
@subscribeCopyGroup
|
||||||
|
|
||||||
|
getVideoTutorialStylesIndex: (numVideos=0)->
|
||||||
|
# A/B Testing video tutorial styles
|
||||||
|
# Not a constant number of videos available (e.g. could be 0, 1, 3, or 4 currently)
|
||||||
|
# TODO: Do we need to call identify() still? trackEvent will have a style property.
|
||||||
|
return 0 unless numVideos > 0
|
||||||
|
return me.get('testGroupNumber') % numVideos
|
||||||
|
|
||||||
isPremium: ->
|
isPremium: ->
|
||||||
return false unless stripe = @get('stripe')
|
return false unless stripe = @get('stripe')
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
if docs.length === 1
|
if docs.length === 1
|
||||||
if showVideo
|
if showVideo
|
||||||
h3 Video Tutorial
|
h3(id='help-video-heading', data-i18n="game_menu.guide_video_tutorial")
|
||||||
div(id="help-video-player")
|
div(id="help-video-player")
|
||||||
h3 Tips
|
h3(data-i18n="game_menu.guide_tips")
|
||||||
div
|
div
|
||||||
!= docs[0].html
|
!= docs[0].html
|
||||||
else
|
else
|
||||||
|
|
|
@ -17,6 +17,10 @@ module.exports = class LevelGuideView extends CocoView
|
||||||
@levelID = options.level.get('slug')
|
@levelID = options.level.get('slug')
|
||||||
@helpVideos = LevelOptions[@levelID]?.helpVideos ? []
|
@helpVideos = LevelOptions[@levelID]?.helpVideos ? []
|
||||||
@trackedHelpVideoStart = @trackedHelpVideoFinish = false
|
@trackedHelpVideoStart = @trackedHelpVideoFinish = false
|
||||||
|
|
||||||
|
# A/B Testing video tutorial styles
|
||||||
|
@helpVideosIndex = me.getVideoTutorialStylesIndex(@helpVideos.length)
|
||||||
|
|
||||||
@firstOnly = options.firstOnly
|
@firstOnly = options.firstOnly
|
||||||
@docs = options?.docs ? options.level.get('documentation') ? {}
|
@docs = options?.docs ? options.level.get('documentation') ? {}
|
||||||
general = @docs.generalArticles or []
|
general = @docs.generalArticles or []
|
||||||
|
@ -36,6 +40,16 @@ module.exports = class LevelGuideView extends CocoView
|
||||||
doc.slug = _.string.slugify(doc.name) for doc in @docs
|
doc.slug = _.string.slugify(doc.name) for doc in @docs
|
||||||
super()
|
super()
|
||||||
|
|
||||||
|
destroy: ->
|
||||||
|
if @vimeoListenerAttached
|
||||||
|
if window.addEventListener
|
||||||
|
window.removeEventListener('message', @onMessageReceived, false)
|
||||||
|
else
|
||||||
|
window.detachEvent('onmessage', @onMessageReceived, false)
|
||||||
|
if window.onYouTubeIframeAPIReady
|
||||||
|
window.onYouTubeIframeAPIReady = null
|
||||||
|
super()
|
||||||
|
|
||||||
getRenderData: ->
|
getRenderData: ->
|
||||||
c = super()
|
c = super()
|
||||||
c.docs = @docs
|
c.docs = @docs
|
||||||
|
@ -70,12 +84,22 @@ module.exports = class LevelGuideView extends CocoView
|
||||||
@volume ?= me.get('volume') ? 1.0
|
@volume ?= me.get('volume') ? 1.0
|
||||||
createjs?.Sound?.setVolume(0.0)
|
createjs?.Sound?.setVolume(0.0)
|
||||||
|
|
||||||
|
onStartHelpVideo: ->
|
||||||
|
unless @trackedHelpVideoStart
|
||||||
|
window.tracker?.trackEvent 'Start help video', level: @levelID, style: @helpVideos[@helpVideosIndex].style
|
||||||
|
@trackedHelpVideoStart = true
|
||||||
|
|
||||||
|
onFinishHelpVideo: ->
|
||||||
|
unless @trackedHelpVideoFinish
|
||||||
|
window.tracker?.trackEvent 'Finish help video', level: @levelID, style: @helpVideos[@helpVideosIndex].style
|
||||||
|
@trackedHelpVideoFinish = true
|
||||||
|
|
||||||
setupVideoPlayer: () ->
|
setupVideoPlayer: () ->
|
||||||
return unless @helpVideos.length > 0
|
return unless @helpVideos.length > 0
|
||||||
|
|
||||||
# TODO: run A/B test for different video styles
|
# TODO: run A/B test for different video styles
|
||||||
|
|
||||||
helpVideoURL = @helpVideos[0].URL
|
helpVideoURL = @helpVideos[@helpVideosIndex].URL
|
||||||
if helpVideoURL.toLowerCase().indexOf('youtube') >= 0
|
if helpVideoURL.toLowerCase().indexOf('youtube') >= 0
|
||||||
@setupYouTubeVideoPlayer helpVideoURL
|
@setupYouTubeVideoPlayer helpVideoURL
|
||||||
else if helpVideoURL.toLowerCase().indexOf('vimeo') >= 0
|
else if helpVideoURL.toLowerCase().indexOf('vimeo') >= 0
|
||||||
|
@ -84,16 +108,24 @@ module.exports = class LevelGuideView extends CocoView
|
||||||
setupYouTubeVideoPlayer: (helpVideoURL) ->
|
setupYouTubeVideoPlayer: (helpVideoURL) ->
|
||||||
# Setup YouTube iframe player
|
# Setup YouTube iframe player
|
||||||
# https://developers.google.com/youtube/iframe_api_reference
|
# https://developers.google.com/youtube/iframe_api_reference
|
||||||
|
# TODO: Can't load a YouTube video twice in one level
|
||||||
|
# TODO: window.onYouTubeIframeAPIReady is only called once
|
||||||
|
|
||||||
onPlayerStateChange = (e) =>
|
onPlayerStateChange = (e) =>
|
||||||
if e.data is 1
|
if e.data is 1
|
||||||
unless @trackedHelpVideoStart
|
@onStartHelpVideo()
|
||||||
window.tracker?.trackEvent 'Start help video', level: @levelID
|
|
||||||
@trackedHelpVideoStart = true
|
|
||||||
else if e.data is 0
|
else if e.data is 0
|
||||||
unless @trackedHelpVideoFinish
|
@onFinishHelpVideo()
|
||||||
window.tracker?.trackEvent 'Finish help video', level: @levelID
|
|
||||||
@trackedHelpVideoFinish = true
|
createPlayer = =>
|
||||||
|
new YT.Player 'help-video-player', {
|
||||||
|
height: @helpVideoHeight,
|
||||||
|
width: @helpVideoWidth,
|
||||||
|
videoId: videoID,
|
||||||
|
events: {
|
||||||
|
'onStateChange': onPlayerStateChange
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if matchVideoID = helpVideoURL.match /www\.youtube\.com\/embed\/(bHaeKdMPZrA)/
|
if matchVideoID = helpVideoURL.match /www\.youtube\.com\/embed\/(bHaeKdMPZrA)/
|
||||||
videoID = matchVideoID[1]
|
videoID = matchVideoID[1]
|
||||||
|
@ -104,19 +136,15 @@ module.exports = class LevelGuideView extends CocoView
|
||||||
|
|
||||||
# Add method that will be called by YouTube iframe player when ready
|
# Add method that will be called by YouTube iframe player when ready
|
||||||
window.onYouTubeIframeAPIReady = =>
|
window.onYouTubeIframeAPIReady = =>
|
||||||
new YT.Player 'help-video-player', {
|
createPlayer()
|
||||||
height: @helpVideoHeight,
|
|
||||||
width: @helpVideoWidth,
|
|
||||||
videoId: videoID,
|
|
||||||
events: {
|
|
||||||
'onStateChange': onPlayerStateChange
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Add YouTube video player
|
# Add YouTube video player iframe script if necessary
|
||||||
tag = document.createElement('script')
|
if YT?.Player?
|
||||||
tag.src = "https://www.youtube.com/iframe_api"
|
createPlayer()
|
||||||
@$el.find('#help-video-player').before(tag)
|
else
|
||||||
|
tag = document.createElement('script')
|
||||||
|
tag.src = "https://www.youtube.com/iframe_api"
|
||||||
|
@$el.find('#help-video-heading').after(tag)
|
||||||
|
|
||||||
setupVimeoVideoPlayer: (helpVideoURL) ->
|
setupVimeoVideoPlayer: (helpVideoURL) ->
|
||||||
# Setup Vimeo player
|
# Setup Vimeo player
|
||||||
|
@ -131,7 +159,7 @@ module.exports = class LevelGuideView extends CocoView
|
||||||
tag.frameborder = '0'
|
tag.frameborder = '0'
|
||||||
@$el.find('#help-video-player').replaceWith(tag)
|
@$el.find('#help-video-player').replaceWith(tag)
|
||||||
|
|
||||||
onMessageReceived = (e) =>
|
@onMessageReceived = (e) =>
|
||||||
data = JSON.parse(e.data)
|
data = JSON.parse(e.data)
|
||||||
if data.event is 'ready'
|
if data.event is 'ready'
|
||||||
# Vimeo player is ready, can now hook up other events
|
# Vimeo player is ready, can now hook up other events
|
||||||
|
@ -141,16 +169,13 @@ module.exports = class LevelGuideView extends CocoView
|
||||||
player.contentWindow.postMessage JSON.stringify(method: 'addEventListener', value: 'play'), helpVideoURL
|
player.contentWindow.postMessage JSON.stringify(method: 'addEventListener', value: 'play'), helpVideoURL
|
||||||
player.contentWindow.postMessage JSON.stringify(method: 'addEventListener', value: 'finish'), helpVideoURL
|
player.contentWindow.postMessage JSON.stringify(method: 'addEventListener', value: 'finish'), helpVideoURL
|
||||||
else if data.event is 'play'
|
else if data.event is 'play'
|
||||||
unless @trackedHelpVideoStart
|
@onStartHelpVideo?()
|
||||||
window.tracker?.trackEvent 'Start help video', level: @levelID
|
|
||||||
@trackedHelpVideoStart = true
|
|
||||||
else if data.event is 'finish'
|
else if data.event is 'finish'
|
||||||
unless @trackedHelpVideoFinish
|
@onFinishHelpVideo?()
|
||||||
window.tracker?.trackEvent 'Finish help video', level: @levelID
|
|
||||||
@trackedHelpVideoFinish = true
|
|
||||||
|
|
||||||
# Listen for Vimeo player 'ready'
|
# Listen for Vimeo player 'ready'
|
||||||
if window.addEventListener
|
if window.addEventListener
|
||||||
window.addEventListener('message', onMessageReceived, false)
|
window.addEventListener('message', @onMessageReceived, false)
|
||||||
else
|
else
|
||||||
window.attachEvent('onmessage', onMessageReceived, false)
|
window.attachEvent('onmessage', @onMessageReceived, false)
|
||||||
|
@vimeoListenerAttached = true
|
||||||
|
|
Reference in a new issue