mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-23 23:58:02 -05:00
Updated Hour of Code visitor counting.
This commit is contained in:
parent
b5c7a4e0f2
commit
2d2a9ad681
12 changed files with 98 additions and 63 deletions
|
@ -15,8 +15,7 @@ module.exports = class CocoRouter extends Backbone.Router
|
|||
@initializeSocialMediaServices = _.once @initializeSocialMediaServices
|
||||
|
||||
routes:
|
||||
'': go('HomeView') # This will go somewhere deprecated when FrontView is done.
|
||||
'front': go('FrontView') # This will become '' when it is done.
|
||||
'': go('HomeView')
|
||||
|
||||
'about': go('AboutView')
|
||||
|
||||
|
@ -85,7 +84,6 @@ module.exports = class CocoRouter extends Backbone.Router
|
|||
|
||||
'play-old': go('play/MainPlayView') # This used to be 'play'.
|
||||
'play': go('play/WorldMapView')
|
||||
'play-hero': go('play/WorldMapView') # Legacy URL for /play; leave up until start of 2015, I guess.
|
||||
'play/ladder/:levelID': go('play/ladder/LadderView')
|
||||
'play/ladder': go('play/ladder/MainLadderView')
|
||||
'play/level/:levelID': go('play/level/PlayLevelView')
|
||||
|
|
|
@ -70,3 +70,15 @@
|
|||
.alert
|
||||
top: 213px
|
||||
border: 5px solid darkred
|
||||
|
||||
&.hour-of-code
|
||||
#site-footer
|
||||
background-color: rgb(70, 58, 44)
|
||||
height: 185px
|
||||
|
||||
.hour-of-code-explanation
|
||||
color: #9e8777
|
||||
text-align: center
|
||||
|
||||
a
|
||||
color: lighten(#0b63bc, 10%)
|
||||
|
|
|
@ -231,6 +231,23 @@
|
|||
width: calc(33.333333% - 10px)
|
||||
margin: 5px
|
||||
|
||||
.hour-of-code-done
|
||||
clear: both
|
||||
padding-top: 10px
|
||||
|
||||
strong
|
||||
color: white
|
||||
display: block
|
||||
margin-bottom: 10px
|
||||
font-weight: normal
|
||||
|
||||
.image-link
|
||||
float: right
|
||||
margin-left: 10px
|
||||
|
||||
.text-link
|
||||
color: lighten(#0b63bc, 10%)
|
||||
|
||||
|
||||
html.no-borderimage
|
||||
#hero-victory-modal
|
||||
|
|
|
@ -86,3 +86,5 @@ block footer
|
|||
a(href="http://www.fullyillustrated.com/") Fully Illustrated
|
||||
a.firebase-bade(href="https://www.firebase.com/")
|
||||
img(src="/images/pages/base/firebase.png", alt="Powered by Firebase")
|
||||
|
||||
block extra_footer_content
|
||||
|
|
|
@ -22,4 +22,13 @@ block outer_content
|
|||
strong(data-i18n="home.old_browser") Uh oh, your browser is too old to run CodeCombat. Sorry!
|
||||
br
|
||||
span(data-i18n="home.old_browser_suffix") You can try anyway, but it probably won't work.
|
||||
|
||||
|
||||
block extra_footer_content
|
||||
if true || explainHourOfCode
|
||||
// Does not show up unless lang is en-US.
|
||||
div.hour-of-code-explanation
|
||||
| The 'Hour of Code' is a nationwide initiative by
|
||||
a(href="http://csedweek.org") Computer Science Education Week
|
||||
| and
|
||||
a(href="http://code.org") Code.org
|
||||
| to introduce millions of students to one hour of computer science and computer programming.
|
|
@ -37,11 +37,3 @@
|
|||
#play-footer
|
||||
p(class='footer-link-text')
|
||||
a(title='Send CodeCombat a message', tabindex=-1, data-toggle="coco-modal", data-target="modal/ContactModal", data-i18n="nav.contact") Contact
|
||||
if explainHourOfCode
|
||||
// Does not show up unless lang is en-US.
|
||||
div.hour-of-code-explanation
|
||||
| The 'Hour of Code' is a nationwide initiative by
|
||||
a(href="http://csedweek.org") Computer Science Education Week
|
||||
| and
|
||||
a(href="http://code.org") Code.org
|
||||
| to introduce millions of students to one hour of computer science and computer programming.
|
|
@ -69,3 +69,12 @@ block modal-footer-content
|
|||
button.btn.btn-primary.return-to-ladder-button(data-href="/play/ladder/#{level.get('slug')}#my-matches", data-dismiss="modal", data-i18n="play_level.victory_return_to_ladder") Return to Ladder
|
||||
else
|
||||
button.btn.btn-success.world-map-button.next-level-button.hide#continue-button(data-i18n="play_level.victory_play_continue") Continue
|
||||
|
||||
if showHourOfCodeDoneButton
|
||||
.hour-of-code-done
|
||||
hr
|
||||
a.image-link(href="http://code.org/api/hour/finish")
|
||||
img(src="/images/level/csedweek-logo-final-small.jpg", alt="CS Ed Week Hour of Code", title="I'm finished with my Hour of Code", width=80)
|
||||
strong(data-i18n="play_level.victory_hour_of_code_done") Are You Done?
|
||||
a.text-link(href="http://code.org/api/hour/finish")
|
||||
span(data-i18n="play_level.victory_hour_of_code_done_yes") Yes, I'm finished with my Hour of Code!
|
||||
|
|
|
@ -1,34 +0,0 @@
|
|||
RootView = require 'views/kinds/RootView'
|
||||
template = require 'templates/front-view'
|
||||
{me} = require '/lib/auth'
|
||||
ModalView = require 'views/kinds/ModalView'
|
||||
|
||||
module.exports = class FrontView extends RootView
|
||||
id: 'front-view'
|
||||
template: template
|
||||
|
||||
events:
|
||||
'click .platform-ios a': 'onIOSClicked'
|
||||
|
||||
getRenderData: ->
|
||||
c = super()
|
||||
if $.browser
|
||||
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 < 6
|
||||
else
|
||||
console.warn 'no more jquery browser version...'
|
||||
c
|
||||
|
||||
afterRender: ->
|
||||
super()
|
||||
|
||||
onIOSClicked: (e) ->
|
||||
header = 'Sorry, the iPad app isn\'t ready yet'
|
||||
body = '''
|
||||
<p class="lead">We are working on it!</p>
|
||||
<p>For now, try playing on the web, and totally sign up (with emails enabled) so you can be the first to hear when it is ready.</p>
|
||||
'''
|
||||
notImplementedModal = new ModalView headerContent: header, bodyContent: body
|
||||
@openModalView notImplementedModal
|
|
@ -16,6 +16,12 @@ module.exports = class HomeView extends RootView
|
|||
constructor: ->
|
||||
super()
|
||||
window.tracker?.trackEvent 'Homepage', Action: 'Loaded'
|
||||
if not me.get('hourOfCode') and @getQueryVariable 'hour_of_code'
|
||||
@setUpHourOfCode()
|
||||
elapsed = (new Date() - new Date(me.get('dateCreated')))
|
||||
if me.get('hourOfCode') and elapsed < 86400 * 1000 and me.get('preferredLanguage', true) is 'en-US'
|
||||
# Show the Hour of Code footer explanation in English until it's been more than a day
|
||||
@explainsHourOfCode = true
|
||||
|
||||
getRenderData: ->
|
||||
c = super()
|
||||
|
@ -28,6 +34,7 @@ module.exports = class HomeView extends RootView
|
|||
console.warn 'no more jquery browser version...'
|
||||
c.isEnglish = (me.get('preferredLanguage') or 'en').startsWith 'en'
|
||||
c.languageName = me.get('preferredLanguage')
|
||||
c.explainsHourOfCode = @explainsHourOfCode
|
||||
c
|
||||
|
||||
onClickBeginnerCampaign: (e) ->
|
||||
|
@ -39,7 +46,17 @@ module.exports = class HomeView extends RootView
|
|||
|
||||
afterInsert: ->
|
||||
super(arguments...)
|
||||
@$el.addClass 'hour-of-code' if @explainsHourOfCode
|
||||
if me.isAdmin() and me.get('slug') is 'nick'
|
||||
LevelSetupManager = require 'lib/LevelSetupManager'
|
||||
setupManager = new LevelSetupManager levelID: 'dungeons-of-kithgard', hadEverChosenHero: true, parent: @
|
||||
setupManager.open()
|
||||
|
||||
setUpHourOfCode: ->
|
||||
elapsed = (new Date() - new Date(me.get('dateCreated')))
|
||||
if elapsed < 5 * 60 * 1000
|
||||
me.set 'hourOfCode', true
|
||||
me.patch()
|
||||
# We may also insert the tracking pixel for everyone on the WorldMapView so as to count directly-linked visitors.
|
||||
$('body').append($('<img src="http://code.org/api/hour/begin_codecombat.png" style="visibility: hidden;">'))
|
||||
application.tracker?.trackEvent 'Hour of Code Begin', {}
|
||||
|
|
|
@ -10,6 +10,8 @@ MusicPlayer = require 'lib/surface/MusicPlayer'
|
|||
storage = require 'lib/storage'
|
||||
AuthModal = require 'views/modal/AuthModal'
|
||||
|
||||
trackedHourOfCode = false
|
||||
|
||||
class LevelSessionsCollection extends CocoCollection
|
||||
url: ''
|
||||
model: LevelSession
|
||||
|
@ -70,6 +72,12 @@ module.exports = class WorldMapView extends RootView
|
|||
@listenTo me, 'change:spent', -> @renderSelectors('#gems-count')
|
||||
window.tracker?.trackEvent 'World Map', Action: 'Loaded', ['Google Analytics']
|
||||
|
||||
# If it's a new player who didn't appear to come from Hour of Code, we register her here without setting the hourOfCode property.
|
||||
elapsed = (new Date() - new Date(me.get('dateCreated')))
|
||||
if not trackedHourOfCode and not me.get('hourOfCode') and elapsed < 5 * 60 * 1000
|
||||
$('body').append($('<img src="http://code.org/api/hour/begin_codecombat.png" style="visibility: hidden;">'))
|
||||
trackedHourOfCode = true
|
||||
|
||||
destroy: ->
|
||||
@setupManager?.destroy()
|
||||
$(window).off 'resize', @onWindowResize
|
||||
|
|
|
@ -93,8 +93,6 @@ module.exports = class PlayLevelView extends RootView
|
|||
constructor: (options, @levelID) ->
|
||||
console.profile?() if PROFILE_ME
|
||||
super options
|
||||
if not me.get('hourOfCode') and @getQueryVariable 'hour_of_code'
|
||||
@setUpHourOfCode()
|
||||
|
||||
@isEditorPreview = @getQueryVariable 'dev'
|
||||
@sessionID = @getQueryVariable 'session'
|
||||
|
@ -114,12 +112,6 @@ module.exports = class PlayLevelView extends RootView
|
|||
@load()
|
||||
application.tracker?.trackEvent 'Started Level Load', level: @levelID, label: @levelID, ['Google Analytics']
|
||||
|
||||
setUpHourOfCode: ->
|
||||
me.set 'hourOfCode', true
|
||||
me.patch()
|
||||
$('body').append($('<img src="http://code.org/api/hour/begin_codecombat.png" style="visibility: hidden;">'))
|
||||
application.tracker?.trackEvent 'Hour of Code Begin', {}
|
||||
|
||||
setLevel: (@level, givenSupermodel) ->
|
||||
@supermodel.models = givenSupermodel.models
|
||||
@supermodel.collections = givenSupermodel.collections
|
||||
|
@ -152,10 +144,6 @@ module.exports = class PlayLevelView extends RootView
|
|||
getRenderData: ->
|
||||
c = super()
|
||||
c.world = @world
|
||||
if me.get('hourOfCode') and me.get('preferredLanguage', true) is 'en-US'
|
||||
# Show the Hour of Code footer explanation until it's been more than a day
|
||||
elapsed = (new Date() - new Date(me.get('dateCreated')))
|
||||
c.explainHourOfCode = elapsed < 86400 * 1000
|
||||
c
|
||||
|
||||
afterRender: ->
|
||||
|
@ -606,7 +594,7 @@ module.exports = class PlayLevelView extends RootView
|
|||
# Current real-time multiplayer session
|
||||
# Internal multiplayer create/joined/left events
|
||||
#
|
||||
# Real-time state variables.
|
||||
# Real-time state variables.
|
||||
# Each Ref is Firebase reference, and may have a matching Data suffixed variable with the latest data received.
|
||||
# @realTimePlayerRef - User's real-time multiplayer player for this level
|
||||
# @realTimePlayerGameRef - User's current real-time multiplayer player game session
|
||||
|
@ -727,7 +715,7 @@ module.exports = class PlayLevelView extends RootView
|
|||
|
||||
@realTimeSessionRef = new Firebase "#{@multiplayerFireHost}multiplayer_level_sessions/#{@levelID}/#{e.realTimeSessionID}"
|
||||
@realTimePlayersRef = @realTimeSessionRef.child 'players'
|
||||
|
||||
|
||||
# Look for opponent
|
||||
@realTimeSessionRef.once 'value', (multiplayerSessionSnapshot) =>
|
||||
if @realTimeSessionData = multiplayerSessionSnapshot.val()
|
||||
|
@ -751,7 +739,7 @@ module.exports = class PlayLevelView extends RootView
|
|||
console.error 'Could not lookup multiplayer session data.'
|
||||
@realTimeSessionRef.on 'value', @onRealTimeSessionChanged
|
||||
|
||||
@realTimePlayerGameRef = @realTimeSessionRef.child "players/#{me.id}"
|
||||
@realTimePlayerGameRef = @realTimeSessionRef.child "players/#{me.id}"
|
||||
|
||||
# TODO: Follow up in MultiplayerView to see if double joins can be avoided
|
||||
# else
|
||||
|
@ -817,7 +805,7 @@ module.exports = class PlayLevelView extends RootView
|
|||
unless @realTimeSessionRef?
|
||||
console.error 'Real-time multiplayer cast without multiplayer session.'
|
||||
return
|
||||
unless @realTimeSessionData?
|
||||
unless @realTimeSessionData?
|
||||
console.error 'Real-time multiplayer cast without multiplayer data.'
|
||||
return
|
||||
unless @realTimePlayersData?
|
||||
|
|
|
@ -80,7 +80,7 @@ module.exports = class HeroVictoryModal extends ModalView
|
|||
@readyToContinue = true
|
||||
@updateSavingProgressStatus()
|
||||
me.fetch() unless me.loading
|
||||
|
||||
|
||||
@readyToContinue = true if not @achievements.models.length
|
||||
|
||||
getRenderData: ->
|
||||
|
@ -117,6 +117,23 @@ module.exports = class HeroVictoryModal extends ModalView
|
|||
{key: 'continue', link: @continueLevelLink, 'choice-explicit': 'next_level', 'choice-implicit': 'just_right'}
|
||||
{key: 'more_practice', link: @morePracticeLevelLink, 'choice-explicit': 'more_practice', 'choice-implicit': 'too_hard'}
|
||||
]
|
||||
|
||||
elapsed = (new Date() - new Date(me.get('dateCreated')))
|
||||
isHourOfCode = me.get('hourOfCode') or elapsed < 120 * 60 * 1000
|
||||
# Later we should only check me.get('hourOfCode'), but for now so much traffic comes in that we just assume it.
|
||||
if isHourOfCode
|
||||
# Show the Hour of Code "I'm Done" tracking pixel after they played for 20 minutes
|
||||
enough = elapsed >= 20 * 60 * 1000
|
||||
tooMuch = elapsed > 120 * 60 * 1000
|
||||
showDone = elapsed >= 30 * 60 * 1000 and not tooMuch
|
||||
if enough and not tooMuch and not me.get('hourOfCodeComplete')
|
||||
$('body').append($('<img src="http://code.org/api/hour/finish_codecombat.png" style="visibility: hidden;">'))
|
||||
me.set 'hourOfCodeComplete', true # Note that this will track even for players who don't have hourOfCode set.
|
||||
me.patch()
|
||||
window.tracker?.trackEvent 'Hour of Code Finish', {}
|
||||
# Show the "I'm done" button between 30 - 120 minutes if they definitely came from Hour of Code
|
||||
c.showHourOfCodeDoneButton = me.get('hourOfCode') and showDone
|
||||
|
||||
return c
|
||||
|
||||
afterRender: ->
|
||||
|
|
Loading…
Reference in a new issue