mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-27 09:35:39 -05:00
Fixed #769. Added some analytics timing tracking. Added replacement for $.browser.
This commit is contained in:
parent
fbc8b6ac35
commit
8aa36178af
8 changed files with 74 additions and 30 deletions
|
@ -1,5 +1,7 @@
|
||||||
{me} = require 'lib/auth'
|
{me} = require 'lib/auth'
|
||||||
|
|
||||||
|
debugAnalytics = false
|
||||||
|
|
||||||
module.exports = class Tracker
|
module.exports = class Tracker
|
||||||
constructor: ->
|
constructor: ->
|
||||||
if window.tracker
|
if window.tracker
|
||||||
|
@ -10,7 +12,7 @@ module.exports = class Tracker
|
||||||
@updateOlark()
|
@updateOlark()
|
||||||
|
|
||||||
identify: (traits) ->
|
identify: (traits) ->
|
||||||
#console.log "Would identify", traits
|
console.log "Would identify", traits if debugAnalytics
|
||||||
return unless me and @isProduction and analytics?
|
return unless me and @isProduction and analytics?
|
||||||
# https://segment.io/docs/methods/identify
|
# https://segment.io/docs/methods/identify
|
||||||
traits ?= {}
|
traits ?= {}
|
||||||
|
@ -39,13 +41,13 @@ module.exports = class Tracker
|
||||||
trackPageView: ->
|
trackPageView: ->
|
||||||
return unless @isProduction and analytics?
|
return unless @isProduction and analytics?
|
||||||
url = Backbone.history.getFragment()
|
url = Backbone.history.getFragment()
|
||||||
#console.log "Going to track visit for", "/#{url}"
|
console.log "Going to track visit for", "/#{url}" if debugAnalytics
|
||||||
analytics.pageview "/#{url}"
|
analytics.pageview "/#{url}"
|
||||||
|
|
||||||
trackEvent: (event, properties, includeProviders=null) =>
|
trackEvent: (event, properties, includeProviders=null) =>
|
||||||
#console.log "Would track analytics event:", event, properties
|
console.log "Would track analytics event:", event, properties if debugAnalytics
|
||||||
return unless me and @isProduction and analytics?
|
return unless me and @isProduction and analytics?
|
||||||
#console.log "Going to track analytics event:", event, properties
|
console.log "Going to track analytics event:", event, properties if debugAnalytics
|
||||||
properties = properties or {}
|
properties = properties or {}
|
||||||
context = {}
|
context = {}
|
||||||
if includeProviders
|
if includeProviders
|
||||||
|
@ -54,3 +56,9 @@ module.exports = class Tracker
|
||||||
context.providers[provider] = true
|
context.providers[provider] = true
|
||||||
event.label = properties.label if properties.label
|
event.label = properties.label if properties.label
|
||||||
analytics?.track event, properties, context
|
analytics?.track event, properties, context
|
||||||
|
|
||||||
|
trackTiming: (duration, category, variable, label, samplePercentage=5) ->
|
||||||
|
# https://developers.google.com/analytics/devguides/collection/gajs/gaTrackingTiming
|
||||||
|
return console.warn "Duration #{duration} invalid for trackTiming call." unless duration >= 0 and duration < 60 * 60 * 1000
|
||||||
|
console.log "Would track timing event:", arguments if debugAnalytics
|
||||||
|
window._gaq?.push ['_trackTiming', category, variable, duration, label, samplePercentage]
|
||||||
|
|
|
@ -7,6 +7,9 @@
|
||||||
text-align: center
|
text-align: center
|
||||||
margin-top: 0
|
margin-top: 0
|
||||||
|
|
||||||
|
#front-screenshot
|
||||||
|
margin: 15px 0 40px 150px
|
||||||
|
|
||||||
#trailer-wrapper
|
#trailer-wrapper
|
||||||
position: relative
|
position: relative
|
||||||
margin: 0 auto 40px
|
margin: 0 auto 40px
|
||||||
|
@ -101,6 +104,8 @@
|
||||||
font-size: 30px
|
font-size: 30px
|
||||||
#trailer-wrapper
|
#trailer-wrapper
|
||||||
display: none
|
display: none
|
||||||
|
#front-screenshot
|
||||||
|
display: none
|
||||||
#mobile-trailer-wrapper
|
#mobile-trailer-wrapper
|
||||||
display: inline-block
|
display: inline-block
|
||||||
|
|
||||||
|
|
|
@ -4,21 +4,29 @@ block content
|
||||||
|
|
||||||
h1#site-slogan(data-i18n="home.slogan") Learn to Code JavaScript by Playing a Game
|
h1#site-slogan(data-i18n="home.slogan") Learn to Code JavaScript by Playing a Game
|
||||||
|
|
||||||
//- if language is Chinese, we use youku, because China can't visit youtube.
|
if frontPageContent == 'video'
|
||||||
//- otherwise, we use youtube.
|
//- if language is Chinese, we use youku, because China can't visit youtube.
|
||||||
if languageName == "zh-HANS"
|
//- otherwise, we use youtube.
|
||||||
#trailer-wrapper
|
if languageName == "zh-HANS"
|
||||||
<embed src="http://player.youku.com/player.php/sid/XNjk2Mzg5NjYw/v.swf" style="margin-left:15px; margin-top:8px;"allowFullScreen="true" quality="high" width="920" height="518" wmode="opaque"></embed>
|
#trailer-wrapper
|
||||||
img(src="/images/pages/home/video_border.png")
|
<embed src="http://player.youku.com/player.php/sid/XNjk2Mzg5NjYw/v.swf" style="margin-left:15px; margin-top:8px;"allowFullScreen="true" quality="high" width="920" height="518" wmode="opaque"></embed>
|
||||||
#mobile-trailer-wrapper
|
img(src="/images/pages/home/video_border.png")
|
||||||
<embed src="http://player.youku.com/player.php/sid/XNjk2Mzg5NjYw/v.swf" style="margin-left:15px; margin-top:8px;"allowFullScreen="true" quality="high" width="280" height="158" wmode="opaque"></embed>
|
#mobile-trailer-wrapper
|
||||||
else
|
<embed src="http://player.youku.com/player.php/sid/XNjk2Mzg5NjYw/v.swf" style="margin-left:15px; margin-top:8px;"allowFullScreen="true" quality="high" width="280" height="158" wmode="opaque"></embed>
|
||||||
#trailer-wrapper
|
else
|
||||||
<iframe width="920" height="518" src="//www.youtube.com/embed/1zjaA13k-dA?rel=0&controls=0&modestbranding=1&showinfo=0&iv_load_policy=3&vq=hd720&wmode=transparent" frameborder="0" wmode="opaque" allowfullscreen></iframe>
|
#trailer-wrapper
|
||||||
img(src="/images/pages/home/video_border.png")
|
<iframe width="920" height="518" src="//www.youtube.com/embed/1zjaA13k-dA?rel=0&controls=0&modestbranding=1&showinfo=0&iv_load_policy=3&vq=hd720&wmode=transparent" frameborder="0" wmode="opaque" allowfullscreen></iframe>
|
||||||
#mobile-trailer-wrapper
|
img(src="/images/pages/home/video_border.png")
|
||||||
<iframe src="//www.youtube.com/embed/1zjaA13k-dA" frameborder="0" width="280" height="158"></iframe>
|
#mobile-trailer-wrapper
|
||||||
hr
|
<iframe src="//www.youtube.com/embed/1zjaA13k-dA" frameborder="0" width="280" height="158"></iframe>
|
||||||
|
hr
|
||||||
|
|
||||||
|
else if frontPageContent == 'screenshot'
|
||||||
|
#front-screenshot
|
||||||
|
img(src="/images/pages/home/front_screenshot_01.png", alt="")
|
||||||
|
|
||||||
|
else if frontPageContent == 'nothing'
|
||||||
|
p
|
||||||
|
|
||||||
.alert.alert-danger.lt-ie10
|
.alert.alert-danger.lt-ie10
|
||||||
strong(data-i18n="home.no_ie") CodeCombat does not run in Internet Explorer 9 or older. Sorry!
|
strong(data-i18n="home.no_ie") CodeCombat does not run in Internet Explorer 9 or older. Sorry!
|
||||||
|
|
|
@ -4,6 +4,7 @@ WizardSprite = require 'lib/surface/WizardSprite'
|
||||||
ThangType = require 'models/ThangType'
|
ThangType = require 'models/ThangType'
|
||||||
Simulator = require 'lib/simulator/Simulator'
|
Simulator = require 'lib/simulator/Simulator'
|
||||||
{me} = require '/lib/auth'
|
{me} = require '/lib/auth'
|
||||||
|
application = require 'application'
|
||||||
|
|
||||||
module.exports = class HomeView extends View
|
module.exports = class HomeView extends View
|
||||||
id: 'home-view'
|
id: 'home-view'
|
||||||
|
@ -16,7 +17,7 @@ module.exports = class HomeView extends View
|
||||||
getRenderData: ->
|
getRenderData: ->
|
||||||
c = super()
|
c = super()
|
||||||
if $.browser
|
if $.browser
|
||||||
majorVersion = parseInt($.browser.version.split('.')[0])
|
majorVersion = $.browser.versionNumber
|
||||||
c.isOldBrowser = true if $.browser.mozilla && majorVersion < 21
|
c.isOldBrowser = true if $.browser.mozilla && majorVersion < 21
|
||||||
c.isOldBrowser = true if $.browser.chrome && majorVersion < 17
|
c.isOldBrowser = true if $.browser.chrome && majorVersion < 17
|
||||||
c.isOldBrowser = true if $.browser.safari && majorVersion < 536
|
c.isOldBrowser = true if $.browser.safari && majorVersion < 536
|
||||||
|
@ -24,6 +25,10 @@ module.exports = class HomeView extends View
|
||||||
console.warn 'no more jquery browser version...'
|
console.warn 'no more jquery browser version...'
|
||||||
c.isEnglish = (me.get('preferredLanguage') or 'en').startsWith 'en'
|
c.isEnglish = (me.get('preferredLanguage') or 'en').startsWith 'en'
|
||||||
c.languageName = me.get('preferredLanguage')
|
c.languageName = me.get('preferredLanguage')
|
||||||
|
# A/B test: https://github.com/codecombat/codecombat/issues/769
|
||||||
|
c.frontPageContent = {0: "video", 1: "screenshot", 2: "nothing"}[me.get('testGroupNumber') % 3]
|
||||||
|
application.tracker.identify frontPageContent: c.frontPageContent
|
||||||
|
application.tracker.trackEvent 'Front Page Content', frontPageContent: c.frontPageContent
|
||||||
c
|
c
|
||||||
|
|
||||||
afterRender: ->
|
afterRender: ->
|
||||||
|
@ -40,4 +45,4 @@ module.exports = class HomeView extends View
|
||||||
href = playLink.attr("href").split("/")
|
href = playLink.attr("href").split("/")
|
||||||
href[href.length-1] = lastLevel if href.length isnt 0
|
href[href.length-1] = lastLevel if href.length isnt 0
|
||||||
href = href.join("/")
|
href = href.join("/")
|
||||||
playLink.attr("href", href)
|
playLink.attr("href", href)
|
||||||
|
|
|
@ -44,4 +44,4 @@ module.exports = class LevelLoadingView extends View
|
||||||
|
|
||||||
onUnveilEnded: =>
|
onUnveilEnded: =>
|
||||||
return if @destroyed
|
return if @destroyed
|
||||||
Backbone.Mediator.publish 'onLoadingViewUnveiled', view: @
|
Backbone.Mediator.publish 'level:loading-view-unveiled', view: @
|
||||||
|
|
|
@ -77,7 +77,7 @@ module.exports = class PlayLevelView extends View
|
||||||
me.set 'hourOfCode', true
|
me.set 'hourOfCode', true
|
||||||
me.save()
|
me.save()
|
||||||
$('body').append($("<img src='http://code.org/api/hour/begin_codecombat.png' style='visibility: hidden;'>"))
|
$('body').append($("<img src='http://code.org/api/hour/begin_codecombat.png' style='visibility: hidden;'>"))
|
||||||
window.tracker?.trackEvent 'Hour of Code Begin', {}
|
application.tracker?.trackEvent 'Hour of Code Begin', {}
|
||||||
|
|
||||||
@isEditorPreview = @getQueryVariable 'dev'
|
@isEditorPreview = @getQueryVariable 'dev'
|
||||||
@sessionID = @getQueryVariable 'session'
|
@sessionID = @getQueryVariable 'session'
|
||||||
|
@ -94,6 +94,7 @@ module.exports = class PlayLevelView extends View
|
||||||
setTimeout f, 100
|
setTimeout f, 100
|
||||||
else
|
else
|
||||||
@load()
|
@load()
|
||||||
|
application.tracker?.trackEvent 'Started Level Load', level: @levelID, label: @levelID
|
||||||
|
|
||||||
onLevelLoadError: (e) ->
|
onLevelLoadError: (e) ->
|
||||||
application.router.navigate "/play?not_found=#{@levelID}", {trigger: true}
|
application.router.navigate "/play?not_found=#{@levelID}", {trigger: true}
|
||||||
|
@ -107,6 +108,7 @@ module.exports = class PlayLevelView extends View
|
||||||
@load()
|
@load()
|
||||||
|
|
||||||
load: ->
|
load: ->
|
||||||
|
@loadStartTime = new Date()
|
||||||
@levelLoader = new LevelLoader supermodel: @supermodel, levelID: @levelID, sessionID: @sessionID, opponentSessionID: @getQueryVariable('opponent'), team: @getQueryVariable("team")
|
@levelLoader = new LevelLoader supermodel: @supermodel, levelID: @levelID, sessionID: @sessionID, opponentSessionID: @getQueryVariable('opponent'), team: @getQueryVariable("team")
|
||||||
@listenToOnce(@levelLoader, 'loaded-all', @onLevelLoaderLoaded)
|
@listenToOnce(@levelLoader, 'loaded-all', @onLevelLoaderLoaded)
|
||||||
@listenTo(@levelLoader, 'progress', @onLevelLoaderProgressChanged)
|
@listenTo(@levelLoader, 'progress', @onLevelLoaderProgressChanged)
|
||||||
|
@ -210,6 +212,11 @@ module.exports = class PlayLevelView extends View
|
||||||
onLoadingViewUnveiled: (e) ->
|
onLoadingViewUnveiled: (e) ->
|
||||||
@removeSubView @loadingView
|
@removeSubView @loadingView
|
||||||
@loadingView = null
|
@loadingView = null
|
||||||
|
unless @isEditorPreview
|
||||||
|
@loadEndTime = new Date()
|
||||||
|
loadDuration = @loadEndTime - @loadStartTime
|
||||||
|
application.tracker?.trackEvent 'Finished Level Load', level: @levelID, label: @levelID, loadDuration: loadDuration
|
||||||
|
application.tracker?.trackTiming loadDuration, 'Level Load Time', @levelID, @levelID
|
||||||
|
|
||||||
onSupermodelLoadedOne: =>
|
onSupermodelLoadedOne: =>
|
||||||
@modelsLoaded ?= 0
|
@modelsLoaded ?= 0
|
||||||
|
@ -273,12 +280,17 @@ module.exports = class PlayLevelView extends View
|
||||||
$('#level-done-button').show()
|
$('#level-done-button').show()
|
||||||
@showVictory() if e.showModal
|
@showVictory() if e.showModal
|
||||||
setTimeout(@preloadNextLevel, 3000)
|
setTimeout(@preloadNextLevel, 3000)
|
||||||
|
return if @victorySeen
|
||||||
|
@victorySeen = true
|
||||||
|
victoryTime = (new Date()) - @loadEndTime
|
||||||
|
if victoryTime > 10 * 1000 # Don't track it if we're reloading an already-beaten level
|
||||||
|
application.tracker?.trackEvent 'Saw Victory', level: @world.name, label: @world.name
|
||||||
|
application.tracker?.trackTiming victoryTime, 'Level Victory Time', @levelID, @levelID, 100
|
||||||
|
|
||||||
showVictory: ->
|
showVictory: ->
|
||||||
options = {level: @level, supermodel: @supermodel, session: @session}
|
options = {level: @level, supermodel: @supermodel, session: @session}
|
||||||
docs = new VictoryModal(options)
|
docs = new VictoryModal(options)
|
||||||
@openModalView(docs)
|
@openModalView(docs)
|
||||||
window.tracker?.trackEvent 'Saw Victory', level: @world.name, label: @world.name
|
|
||||||
if me.get('anonymous')
|
if me.get('anonymous')
|
||||||
window.nextLevelURL = @getNextLevelID() # Signup will go here on completion instead of reloading.
|
window.nextLevelURL = @getNextLevelID() # Signup will go here on completion instead of reloading.
|
||||||
|
|
||||||
|
@ -286,7 +298,7 @@ module.exports = class PlayLevelView extends View
|
||||||
@tome.reloadAllCode()
|
@tome.reloadAllCode()
|
||||||
Backbone.Mediator.publish 'level:restarted'
|
Backbone.Mediator.publish 'level:restarted'
|
||||||
$('#level-done-button', @$el).hide()
|
$('#level-done-button', @$el).hide()
|
||||||
window.tracker?.trackEvent 'Confirmed Restart', level: @world.name, label: @world.name
|
application.tracker?.trackEvent 'Confirmed Restart', level: @world.name, label: @world.name
|
||||||
|
|
||||||
onNewWorld: (e) ->
|
onNewWorld: (e) ->
|
||||||
@world = e.world
|
@world = e.world
|
||||||
|
@ -294,7 +306,7 @@ module.exports = class PlayLevelView extends View
|
||||||
onInfiniteLoop: (e) ->
|
onInfiniteLoop: (e) ->
|
||||||
return unless e.firstWorld
|
return unless e.firstWorld
|
||||||
@openModalView new InfiniteLoopModal()
|
@openModalView new InfiniteLoopModal()
|
||||||
window.tracker?.trackEvent 'Saw Initial Infinite Loop', level: @world.name, label: @world.name
|
application.tracker?.trackEvent 'Saw Initial Infinite Loop', level: @world.name, label: @world.name
|
||||||
|
|
||||||
onPlayNextLevel: ->
|
onPlayNextLevel: ->
|
||||||
nextLevelID = @getNextLevelID()
|
nextLevelID = @getNextLevelID()
|
||||||
|
|
|
@ -208,8 +208,9 @@ module.exports = class SpectateLevelView extends View
|
||||||
@loadingView?.unveil()
|
@loadingView?.unveil()
|
||||||
|
|
||||||
onLoadingViewUnveiled: (e) ->
|
onLoadingViewUnveiled: (e) ->
|
||||||
@removeSubView @loadingView
|
# Don't remove it; we want its decoration around on large screens.
|
||||||
@loadingView = null
|
#@removeSubView @loadingView
|
||||||
|
#@loadingView = null
|
||||||
|
|
||||||
onSupermodelLoadedOne: =>
|
onSupermodelLoadedOne: =>
|
||||||
@modelsLoaded ?= 0
|
@modelsLoaded ?= 0
|
||||||
|
|
|
@ -42,7 +42,8 @@
|
||||||
"jquery.tablesorter": "~2.15.13",
|
"jquery.tablesorter": "~2.15.13",
|
||||||
"treema": ">=0.0.1",
|
"treema": ">=0.0.1",
|
||||||
"bootstrap": "~3.1.1",
|
"bootstrap": "~3.1.1",
|
||||||
"validated-backbone-mediator": "~0.1.3"
|
"validated-backbone-mediator": "~0.1.3",
|
||||||
|
"jquery.browser": "~0.0.6"
|
||||||
},
|
},
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"backbone": {
|
"backbone": {
|
||||||
|
@ -58,7 +59,11 @@
|
||||||
"main": "lib/underscore.string.js"
|
"main": "lib/underscore.string.js"
|
||||||
},
|
},
|
||||||
"jsondiffpatch": {
|
"jsondiffpatch": {
|
||||||
"main": ["build/bundle-full.js", "build/formatters.js", "src/formatters/html.css"]
|
"main": [
|
||||||
|
"build/bundle-full.js",
|
||||||
|
"build/formatters.js",
|
||||||
|
"src/formatters/html.css"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"jquery.tablesorter": {
|
"jquery.tablesorter": {
|
||||||
"main": [
|
"main": [
|
||||||
|
|
Loading…
Reference in a new issue