From 8aa36178af5235f92548f630d18162114e19f97a Mon Sep 17 00:00:00 2001 From: Nick Winter Date: Sun, 13 Apr 2014 20:31:23 -0700 Subject: [PATCH] Fixed #769. Added some analytics timing tracking. Added replacement for $.browser. --- app/lib/Tracker.coffee | 16 ++++++-- app/styles/home.sass | 5 +++ app/templates/home.jade | 38 +++++++++++-------- app/views/home_view.coffee | 9 ++++- .../play/level/level_loading_view.coffee | 2 +- app/views/play/level_view.coffee | 20 ++++++++-- app/views/play/spectate_view.coffee | 5 ++- bower.json | 9 ++++- 8 files changed, 74 insertions(+), 30 deletions(-) diff --git a/app/lib/Tracker.coffee b/app/lib/Tracker.coffee index 6f585e473..a21a7820c 100644 --- a/app/lib/Tracker.coffee +++ b/app/lib/Tracker.coffee @@ -1,5 +1,7 @@ {me} = require 'lib/auth' +debugAnalytics = false + module.exports = class Tracker constructor: -> if window.tracker @@ -10,7 +12,7 @@ module.exports = class Tracker @updateOlark() identify: (traits) -> - #console.log "Would identify", traits + console.log "Would identify", traits if debugAnalytics return unless me and @isProduction and analytics? # https://segment.io/docs/methods/identify traits ?= {} @@ -39,13 +41,13 @@ module.exports = class Tracker trackPageView: -> return unless @isProduction and analytics? 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}" 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? - #console.log "Going to track analytics event:", event, properties + console.log "Going to track analytics event:", event, properties if debugAnalytics properties = properties or {} context = {} if includeProviders @@ -54,3 +56,9 @@ module.exports = class Tracker context.providers[provider] = true event.label = properties.label if properties.label 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] diff --git a/app/styles/home.sass b/app/styles/home.sass index e2ba1fdb0..2c49541c7 100644 --- a/app/styles/home.sass +++ b/app/styles/home.sass @@ -7,6 +7,9 @@ text-align: center margin-top: 0 + #front-screenshot + margin: 15px 0 40px 150px + #trailer-wrapper position: relative margin: 0 auto 40px @@ -101,6 +104,8 @@ font-size: 30px #trailer-wrapper display: none + #front-screenshot + display: none #mobile-trailer-wrapper display: inline-block diff --git a/app/templates/home.jade b/app/templates/home.jade index dfd523f0c..0fa7022e5 100644 --- a/app/templates/home.jade +++ b/app/templates/home.jade @@ -4,21 +4,29 @@ block content 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. - //- otherwise, we use youtube. - if languageName == "zh-HANS" - #trailer-wrapper - - img(src="/images/pages/home/video_border.png") - #mobile-trailer-wrapper - - else - #trailer-wrapper - - img(src="/images/pages/home/video_border.png") - #mobile-trailer-wrapper - - hr + if frontPageContent == 'video' + //- if language is Chinese, we use youku, because China can't visit youtube. + //- otherwise, we use youtube. + if languageName == "zh-HANS" + #trailer-wrapper + + img(src="/images/pages/home/video_border.png") + #mobile-trailer-wrapper + + else + #trailer-wrapper + + img(src="/images/pages/home/video_border.png") + #mobile-trailer-wrapper + + 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 strong(data-i18n="home.no_ie") CodeCombat does not run in Internet Explorer 9 or older. Sorry! diff --git a/app/views/home_view.coffee b/app/views/home_view.coffee index d3f5494a9..60fe75439 100644 --- a/app/views/home_view.coffee +++ b/app/views/home_view.coffee @@ -4,6 +4,7 @@ WizardSprite = require 'lib/surface/WizardSprite' ThangType = require 'models/ThangType' Simulator = require 'lib/simulator/Simulator' {me} = require '/lib/auth' +application = require 'application' module.exports = class HomeView extends View id: 'home-view' @@ -16,7 +17,7 @@ module.exports = class HomeView extends View getRenderData: -> c = super() if $.browser - majorVersion = parseInt($.browser.version.split('.')[0]) + majorVersion = $.browser.versionNumber c.isOldBrowser = true if $.browser.mozilla && majorVersion < 21 c.isOldBrowser = true if $.browser.chrome && majorVersion < 17 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...' c.isEnglish = (me.get('preferredLanguage') or 'en').startsWith 'en' 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 afterRender: -> @@ -40,4 +45,4 @@ module.exports = class HomeView extends View href = playLink.attr("href").split("/") href[href.length-1] = lastLevel if href.length isnt 0 href = href.join("/") - playLink.attr("href", href) \ No newline at end of file + playLink.attr("href", href) diff --git a/app/views/play/level/level_loading_view.coffee b/app/views/play/level/level_loading_view.coffee index 8035c5d14..f242acec3 100644 --- a/app/views/play/level/level_loading_view.coffee +++ b/app/views/play/level/level_loading_view.coffee @@ -44,4 +44,4 @@ module.exports = class LevelLoadingView extends View onUnveilEnded: => return if @destroyed - Backbone.Mediator.publish 'onLoadingViewUnveiled', view: @ + Backbone.Mediator.publish 'level:loading-view-unveiled', view: @ diff --git a/app/views/play/level_view.coffee b/app/views/play/level_view.coffee index 63d4507eb..56a9607e2 100644 --- a/app/views/play/level_view.coffee +++ b/app/views/play/level_view.coffee @@ -77,7 +77,7 @@ module.exports = class PlayLevelView extends View me.set 'hourOfCode', true me.save() $('body').append($("")) - window.tracker?.trackEvent 'Hour of Code Begin', {} + application.tracker?.trackEvent 'Hour of Code Begin', {} @isEditorPreview = @getQueryVariable 'dev' @sessionID = @getQueryVariable 'session' @@ -94,6 +94,7 @@ module.exports = class PlayLevelView extends View setTimeout f, 100 else @load() + application.tracker?.trackEvent 'Started Level Load', level: @levelID, label: @levelID onLevelLoadError: (e) -> application.router.navigate "/play?not_found=#{@levelID}", {trigger: true} @@ -107,6 +108,7 @@ module.exports = class PlayLevelView extends View @load() load: -> + @loadStartTime = new Date() @levelLoader = new LevelLoader supermodel: @supermodel, levelID: @levelID, sessionID: @sessionID, opponentSessionID: @getQueryVariable('opponent'), team: @getQueryVariable("team") @listenToOnce(@levelLoader, 'loaded-all', @onLevelLoaderLoaded) @listenTo(@levelLoader, 'progress', @onLevelLoaderProgressChanged) @@ -210,6 +212,11 @@ module.exports = class PlayLevelView extends View onLoadingViewUnveiled: (e) -> @removeSubView @loadingView @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: => @modelsLoaded ?= 0 @@ -273,12 +280,17 @@ module.exports = class PlayLevelView extends View $('#level-done-button').show() @showVictory() if e.showModal 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: -> options = {level: @level, supermodel: @supermodel, session: @session} docs = new VictoryModal(options) @openModalView(docs) - window.tracker?.trackEvent 'Saw Victory', level: @world.name, label: @world.name if me.get('anonymous') window.nextLevelURL = @getNextLevelID() # Signup will go here on completion instead of reloading. @@ -286,7 +298,7 @@ module.exports = class PlayLevelView extends View @tome.reloadAllCode() Backbone.Mediator.publish 'level:restarted' $('#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) -> @world = e.world @@ -294,7 +306,7 @@ module.exports = class PlayLevelView extends View onInfiniteLoop: (e) -> return unless e.firstWorld @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: -> nextLevelID = @getNextLevelID() diff --git a/app/views/play/spectate_view.coffee b/app/views/play/spectate_view.coffee index 7a3058212..93db38908 100644 --- a/app/views/play/spectate_view.coffee +++ b/app/views/play/spectate_view.coffee @@ -208,8 +208,9 @@ module.exports = class SpectateLevelView extends View @loadingView?.unveil() onLoadingViewUnveiled: (e) -> - @removeSubView @loadingView - @loadingView = null + # Don't remove it; we want its decoration around on large screens. + #@removeSubView @loadingView + #@loadingView = null onSupermodelLoadedOne: => @modelsLoaded ?= 0 diff --git a/bower.json b/bower.json index 2c7d15146..24a139f6d 100644 --- a/bower.json +++ b/bower.json @@ -42,7 +42,8 @@ "jquery.tablesorter": "~2.15.13", "treema": ">=0.0.1", "bootstrap": "~3.1.1", - "validated-backbone-mediator": "~0.1.3" + "validated-backbone-mediator": "~0.1.3", + "jquery.browser": "~0.0.6" }, "overrides": { "backbone": { @@ -58,7 +59,11 @@ "main": "lib/underscore.string.js" }, "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": { "main": [