Merge remote-tracking branch 'codecombat/master' into translation
This commit is contained in:
commit
1520c4e297
10 changed files with 73 additions and 17 deletions
app
locale
styles/courses
templates
views
server/courses
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 = {}
|
||||||
|
|
|
@ -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'
|
||||||
|
|
|
@ -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;">'))
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
Reference in a new issue