Merge remote-tracking branch 'codecombat/master' into translation

This commit is contained in:
AkaKaras 2015-10-13 11:20:16 -04:00
commit 1520c4e297
10 changed files with 73 additions and 17 deletions

View file

@ -1347,7 +1347,7 @@ module.exports = nativeDescription: "Português do Brasil", englishDescription:
no_changes: "Sem Alterações" no_changes: "Sem Alterações"
temp: temp:
ace_of_coders_tournament: "Novo: jogue no torneir Era dos Programadores agora!" ace_of_coders_tournament: "Novo: jogue no torneio Ás dos Programadores agora!"
multiplayer: multiplayer:
multiplayer_title: "Configurações de Multijogador" # We'll be changing this around significantly soon. Until then, it's not important to translate. multiplayer_title: "Configurações de Multijogador" # We'll be changing this around significantly soon. Until then, it's not important to translate.

View file

@ -1,5 +1,25 @@
#courses-view #courses-view
.logged_out
font-size: 24px
.signup-button
background: red
color: white
font-size: 18px
font-variant: small-caps
line-height: 27px
text-transform: uppercase
margin-right: 20px
.login-button
background: white
color: black
font-size: 18px
font-variant: small-caps
line-height: 27px
text-transform: uppercase
.center .center
text-align: center text-align: center

View file

@ -10,7 +10,9 @@ block content
if state === 'enrolling' if state === 'enrolling'
.alert.alert-info Enrolling in course.. .alert.alert-info Enrolling in course..
else if state === 'ppc_logged_out' else if state === 'ppc_logged_out'
.alert.alert-success Log in or create an account to join this course. .alert.alert-danger.logged_out Create account or log in to join this course.
button.btn.btn-sm.btn-primary.header-font.signup-button(data-i18n="login.sign_up")
button.btn.btn-sm.btn-default.header-font.login-button(data-i18n="login.log_in")
else else
if state === 'unknown_error' if state === 'unknown_error'
.alert.alert-danger.alert-dismissible= stateMessage .alert.alert-danger.alert-dismissible= stateMessage
@ -36,7 +38,7 @@ block content
- i++ - i++
mixin hoc-landing mixin hoc-landing
h1.center Welcome Hour of Code! h1.center Welcome to CodeCombat's Hour of Code!
br br
.container-fluid .container-fluid
.row .row
@ -51,7 +53,7 @@ mixin student-main
mixin teacher-hoc mixin teacher-hoc
button.btn.btn-warning.btn-student(data-i18n="courses.students_click") button.btn.btn-warning.btn-student(data-i18n="courses.students_click")
h1.center Welcome Hour of Code! h1.center Welcome to CodeCombat's Hour of Code!
p p
strong How to use CodeCombat with your students: strong How to use CodeCombat with your students:
ol ol

View file

@ -36,11 +36,11 @@ block outer_content
block extra_footer_content block extra_footer_content
if explainHourOfCode if explainsHourOfCode
// Does not show up unless lang is en-US. // Does not show up unless lang is en-US.
div.hour-of-code-explanation div.hour-of-code-explanation
| The 'Hour of Code' is a nationwide initiative by | The 'Hour of Code' is a nationwide initiative by
a(href="http://csedweek.org") Computer Science Education Week a(href="http://csedweek.org") Computer Science Education Week
| and | and
a(href="http://code.org") Code.org a(href="http://code.org") Code.org
| to introduce millions of students to one hour of computer science and computer programming. | to introduce millions of students to one hour of computer science and computer programming.

View file

@ -46,6 +46,8 @@ module.exports = class HomeView extends RootView
@$el.addClass 'hour-of-code' if @explainsHourOfCode @$el.addClass 'hour-of-code' if @explainsHourOfCode
setUpHourOfCode: -> setUpHourOfCode: ->
# All this HoC stuff is for the 2014-2015 year. 2015-2016 year lands at /hoc instead (the courses view).
# TODO: get rid of all this sometime in November 2015 when code.org/learn updates to the new version for Hour of Code tutorials.
elapsed = (new Date() - new Date(me.get('dateCreated'))) elapsed = (new Date() - new Date(me.get('dateCreated')))
if elapsed < 5 * 60 * 1000 if elapsed < 5 * 60 * 1000
me.set 'hourOfCode', true me.set 'hourOfCode', true

View file

@ -9,6 +9,8 @@ User = require 'models/User'
utils = require 'core/utils' utils = require 'core/utils'
Prepaid = require 'models/Prepaid' Prepaid = require 'models/Prepaid'
autoplayedOnce = false
module.exports = class CourseDetailsView extends RootView module.exports = class CourseDetailsView extends RootView
id: 'course-details-view' id: 'course-details-view'
template: template template: template
@ -64,7 +66,7 @@ module.exports = class CourseDetailsView extends RootView
onCourseSync: -> onCourseSync: ->
# console.log 'onCourseSync' # console.log 'onCourseSync'
if me.isAnonymous() if me.isAnonymous() and not me.get('hourOfCode')
@noCourseInstance = true @noCourseInstance = true
@render?() @render?()
return return
@ -117,7 +119,7 @@ module.exports = class CourseDetailsView extends RootView
onCourseInstanceSync: -> onCourseInstanceSync: ->
# console.log 'onCourseInstanceSync' # console.log 'onCourseInstanceSync'
@adminMode = true if @courseInstance.get('ownerID') is me.id @adminMode = true if @courseInstance.get('ownerID') is me.id and @courseInstance.get('name') isnt 'Single Player'
@levelSessions = new CocoCollection([], { url: "/db/course_instance/#{@courseInstance.id}/level_sessions", model: LevelSession, comparator:'_id' }) @levelSessions = new CocoCollection([], { url: "/db/course_instance/#{@courseInstance.id}/level_sessions", model: LevelSession, comparator:'_id' })
@listenToOnce @levelSessions, 'sync', @onLevelSessionsSync @listenToOnce @levelSessions, 'sync', @onLevelSessionsSync
@supermodel.loadCollection @levelSessions, 'level_sessions', cache: false @supermodel.loadCollection @levelSessions, 'level_sessions', cache: false
@ -180,6 +182,11 @@ module.exports = class CourseDetailsView extends RootView
@conceptsCompleted[concept]++ @conceptsCompleted[concept]++
@render?() @render?()
# If we just joined a single-player course for Hour of Code, we automatically play.
if @instanceStats.totalLevelsCompleted is 0 and @instanceStats.totalPlayTime is 0 and @courseInstance.get('members').length is 1 and me.get('hourOfCode') and not @adminMode and not autoplayedOnce
autoplayedOnce = true
@$el.find('button.btn-play-level').click()
onMembersSync: -> onMembersSync: ->
# console.log 'onMembersSync' # console.log 'onMembersSync'
@memberUserMap = {} @memberUserMap = {}

View file

@ -17,15 +17,14 @@ module.exports = class CoursesView extends RootView
'click .btn-buy': 'onClickBuy' 'click .btn-buy': 'onClickBuy'
'click .btn-enroll': 'onClickEnroll' 'click .btn-enroll': 'onClickEnroll'
'click .btn-enter': 'onClickEnter' 'click .btn-enter': 'onClickEnter'
'click .btn-hoc-student-continue': 'onClickHocStudentContinue' 'click .btn-hoc-student-continue': 'onClickHOCStudentContinue'
'click .btn-student': 'onClickStudent' 'click .btn-student': 'onClickStudent'
'click .btn-teacher': 'onClickTeacher' 'click .btn-teacher': 'onClickTeacher'
constructor: (options) -> constructor: (options) ->
super(options) super(options)
@setUpHourOfCode()
@praise = utils.getCoursePraise() @praise = utils.getCoursePraise()
@hocLandingPage = Backbone.history.getFragment()?.indexOf('hoc') >= 0
@hocMode = utils.getQueryVariable('hoc', false)
@studentMode = Backbone.history.getFragment()?.indexOf('courses/students') >= 0 @studentMode = Backbone.history.getFragment()?.indexOf('courses/students') >= 0
@courses = new CocoCollection([], { url: "/db/course", model: Course}) @courses = new CocoCollection([], { url: "/db/course", model: Course})
@supermodel.loadCollection(@courses, 'courses') @supermodel.loadCollection(@courses, 'courses')
@ -39,6 +38,21 @@ module.exports = class CoursesView extends RootView
@studentMode = true @studentMode = true
@courseEnroll(prepaidCode) @courseEnroll(prepaidCode)
setUpHourOfCode: ->
# If we are coming in at /hoc, then we show the landing page.
# If we have ?hoc=true (for the step after the landing page), then we show any HoC-specific instructions.
# If we haven't tracked this player as an hourOfCode player yet, and it's a new account, we do that now.
@hocLandingPage = Backbone.history.getFragment()?.indexOf('hoc') >= 0
@hocMode = utils.getQueryVariable('hoc', false)
elapsed = new Date() - new Date(me.get('dateCreated'))
if not me.get('hourOfCode') and (@hocLandingPage or @hocMode) and elapsed < 5 * 60 * 1000
me.set('hourOfCode', true)
me.patch()
$('body').append($('<img src="https://code.org/api/hour/begin_codecombat.png" style="visibility: hidden;">'))
application.tracker?.trackEvent 'Hour of Code Begin'
if me.get('hourOfCode') and elapsed < 24 * 60 * 60 * 1000
@hocMode = true # If they really just arrived, make sure we're still in hocMode even if they lost ?hoc=true.
getRenderData: -> getRenderData: ->
context = super() context = super()
context.courses = @courses.models ? [] context.courses = @courses.models ? []
@ -102,10 +116,12 @@ module.exports = class CoursesView extends RootView
navigationEvent = route: route, viewClass: viewClass, viewArgs: viewArgs navigationEvent = route: route, viewClass: viewClass, viewArgs: viewArgs
Backbone.Mediator.publish 'router:navigate', navigationEvent Backbone.Mediator.publish 'router:navigate', navigationEvent
onClickHocStudentContinue: (e) -> onClickHOCStudentContinue: (e) ->
$('.continue-dialog').modal('hide') $('.continue-dialog').modal('hide')
return @openModalView new AuthModal() if me.isAnonymous() if e
courseID = $(e.target).data('course-id') courseID = $(e.target).data('course-id')
else
courseID = '560f1a9f22961295f9427742'
@state = 'enrolling' @state = 'enrolling'
@stateMessage = undefined @stateMessage = undefined
@ -117,6 +133,7 @@ module.exports = class CoursesView extends RootView
name: 'Single Player' name: 'Single Player'
seats: 9999 seats: 9999
courseID: courseID courseID: courseID
hourOfCode: true
jqxhr = $.post('/db/course_instance/-/create', data) jqxhr = $.post('/db/course_instance/-/create', data)
jqxhr.done (data, textStatus, jqXHR) => jqxhr.done (data, textStatus, jqXHR) =>
application.tracker?.trackEvent 'Finished HoC student course creation', {courseID: courseID} application.tracker?.trackEvent 'Finished HoC student course creation', {courseID: courseID}
@ -145,6 +162,10 @@ module.exports = class CoursesView extends RootView
@render?() @render?()
onClickStudent: (e) -> onClickStudent: (e) ->
if @supermodel.finished() and @hocLandingPage
# Automatically enroll in first course
@onClickHOCStudentContinue()
return
route = "/courses/students" route = "/courses/students"
route += "?hoc=true" if @hocLandingPage or @hocMode route += "?hoc=true" if @hocLandingPage or @hocMode
viewClass = require 'views/courses/CoursesView' viewClass = require 'views/courses/CoursesView'

View file

@ -106,6 +106,7 @@ module.exports = class CampaignView extends RootView
window.tracker?.trackEvent 'Loaded World Map', category: 'World Map', label: @terrain window.tracker?.trackEvent 'Loaded World Map', category: 'World Map', label: @terrain
# 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. # 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.
# TODO: get rid of all this sometime in November 2015 when code.org/learn updates to the new version for Hour of Code tutorials.
elapsed = (new Date() - new Date(me.get('dateCreated'))) elapsed = (new Date() - new Date(me.get('dateCreated')))
if not trackedHourOfCode and not me.get('hourOfCode') and elapsed < 5 * 60 * 1000 if not trackedHourOfCode and not me.get('hourOfCode') and elapsed < 5 * 60 * 1000
$('body').append($('<img src="https://code.org/api/hour/begin_codecombat.png" style="visibility: hidden;">')) $('body').append($('<img src="https://code.org/api/hour/begin_codecombat.png" style="visibility: hidden;">'))

View file

@ -189,11 +189,13 @@ module.exports = class HeroVictoryModal extends ModalView
elapsed = (new Date() - new Date(me.get('dateCreated'))) elapsed = (new Date() - new Date(me.get('dateCreated')))
isHourOfCode = me.get('hourOfCode') or elapsed < 120 * 60 * 1000 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. # Later we should only check me.get('hourOfCode'), but for now so much traffic comes in that we just assume it.
# TODO: get rid of said assumption sometime in November 2015 when code.org/learn updates to the new version for Hour of Code tutorials.
if isHourOfCode if isHourOfCode
# Show the Hour of Code "I'm Done" tracking pixel after they played for 20 minutes # Show the Hour of Code "I'm Done" tracking pixel after they played for 20 minutes
enough = elapsed >= 20 * 60 * 1000 lastLevel = @level.get('slug') is 'course-kithgard-gates'
enough = elapsed >= 20 * 60 * 1000 or lastLevel
tooMuch = elapsed > 120 * 60 * 1000 tooMuch = elapsed > 120 * 60 * 1000
showDone = elapsed >= 30 * 60 * 1000 and not tooMuch showDone = (elapsed >= 30 * 60 * 1000 and not tooMuch) or lastLevel
if enough and not tooMuch and not me.get('hourOfCodeComplete') 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;">')) $('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.set 'hourOfCodeComplete', true # Note that this will track even for players who don't have hourOfCode set.

View file

@ -38,7 +38,8 @@ CourseInstanceHandler = class CourseInstanceHandler extends Handler
super arguments... super arguments...
createAPI: (req, res) -> createAPI: (req, res) ->
return @sendUnauthorizedError(res) if not req.user? or req.user?.isAnonymous() return @sendUnauthorizedError(res) if not req.user?
return @sendUnauthorizedError(res) if req.user.isAnonymous() and not (req.body.hourOfCode and req.body.courseID is '560f1a9f22961295f9427742')
# Required Input # Required Input
seats = req.body.seats seats = req.body.seats