Merge branch 'master' into production

This commit is contained in:
Matt Lott 2016-02-24 16:50:39 -08:00
commit aa14e405f2
68 changed files with 1767 additions and 1093 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 344 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 455 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 765 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 294 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1,018 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 147 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

View file

@ -83,8 +83,8 @@ module.exports.setErrorToProperty = setErrorToProperty = (el, property, message,
setErrorToField input, message, warning setErrorToField input, message, warning
module.exports.scrollToFirstError = ($el=$('body')) -> module.exports.scrollToFirstError = ($el=$('body')) ->
$first = $el.find('.has-error, .alert-danger, .error-help-block, .has-warning, .alert-warning, .warning-help-block').first() $first = $el.find('.has-error, .alert-danger, .error-help-block, .has-warning, .alert-warning, .warning-help-block').filter(':visible').first()
$('body').animate({ scrollTop: $first.offset().top - 20 }, 300) $('html, body').animate({ scrollTop: $first.offset().top - 20 }, 300)
module.exports.clearFormAlerts = (el) -> module.exports.clearFormAlerts = (el) ->
$('.has-error', el).removeClass('has-error') $('.has-error', el).removeClass('has-error')

View file

@ -25,7 +25,7 @@ module.exports = class LevelSetupManager extends CocoClass
loadLevel: -> loadLevel: ->
levelURL = "/db/level/#{@options.levelID}" levelURL = "/db/level/#{@options.levelID}"
@level = new Level().setURL levelURL @level = new Level().setURL levelURL
@level = @supermodel.loadModel(@level, 'level').model @level = @supermodel.loadModel(@level).model
if @level.loaded then @onLevelSync() else @listenToOnce @level, 'sync', @onLevelSync if @level.loaded then @onLevelSync() else @listenToOnce @level, 'sync', @onLevelSync
loadSession: -> loadSession: ->
@ -33,7 +33,7 @@ module.exports = class LevelSetupManager extends CocoClass
#sessionURL += "?team=#{@team}" if @options.team # TODO: figure out how to get the teams for multiplayer PVP hero style #sessionURL += "?team=#{@team}" if @options.team # TODO: figure out how to get the teams for multiplayer PVP hero style
sessionURL += "?course=#{@options.courseID}" if @options.courseID sessionURL += "?course=#{@options.courseID}" if @options.courseID
@session = new LevelSession().setURL sessionURL @session = new LevelSession().setURL sessionURL
@session = @supermodel.loadModel(@session, 'level_session').model @session = @supermodel.loadModel(@session).model
if @session.loaded then @onSessionSync() else @listenToOnce @session, 'sync', @onSessionSync if @session.loaded then @onSessionSync() else @listenToOnce @session, 'sync', @onSessionSync
onLevelSync: -> onLevelSync: ->

View file

@ -286,6 +286,7 @@ module.exports.thangNames = thangNames =
'Gom' 'Gom'
'Grek' 'Grek'
'Gror' 'Gror'
'Grue'
'Il\'Du\'duka' 'Il\'Du\'duka'
'Makas' 'Makas'
'Mogadishu' 'Mogadishu'

View file

@ -545,19 +545,11 @@
editor_config_behaviors_description: "Autocompletes brackets, braces, and quotes." editor_config_behaviors_description: "Autocompletes brackets, braces, and quotes."
about: about:
why_codecombat: "Why CodeCombat?" mission_title: "Our mission: make programming accessible to every student on Earth."
why_paragraph_1: "If you want to learn to program, you don't need lessons. You need to write a lot of code and have a great time doing it." mission_description_1: "Programming is magic. It's the ability to create things from pure imagination. We started CodeCombat to give learners the feeling of wizardly power at their fingertips by using typed code."
why_paragraph_2_prefix: "That's what programming is about. It's gotta be fun. Not fun like" mission_description_2: "As it turns out, that enables them to learn faster too. WAY faster. It's like having a conversation instead of reading a manual. We want to bring that conversation to every school and to every student, because everyone should have the chance to learn the magic of programming."
why_paragraph_2_italic: "yay a badge" team_title: "Meet the CodeCombat team"
why_paragraph_2_center: "but fun like" team_values: "We value open and respectful dialog, where the best idea wins. Our decisions are grounded in customer research and our process is focused on delivering tangible results for them. Everyone is hands-on, from our CEO to our Github contributors, because we value growth and learning in our team."
why_paragraph_2_italic_caps: "NO MOM I HAVE TO FINISH THE LEVEL!"
why_paragraph_2_suffix: "That's why CodeCombat is a multiplayer game, not a gamified lesson course. We won't stop until you can't stop--but this time, that's a good thing."
why_paragraph_3: "If you're going to get addicted to some game, get addicted to this one and become one of the wizards of the tech age."
press_title: "Bloggers/Press"
press_paragraph_1_prefix: "Want to write about us? Feel free to download and use all of the resources included in our"
press_paragraph_1_link: "press packet"
press_paragraph_1_suffix: ". All logos and images may be used without contacting us directly."
team: "Team"
nick_title: "Cofounder, CEO" nick_title: "Cofounder, CEO"
nick_blurb: "Motivation Guru" nick_blurb: "Motivation Guru"
matt_title: "Cofounder, CTO" matt_title: "Cofounder, CTO"
@ -582,6 +574,49 @@
jose_blurb: "Taking Off" jose_blurb: "Taking Off"
carlos_title: "Region Manager, Brazil" carlos_title: "Region Manager, Brazil"
carlos_blurb: "Celery Man" carlos_blurb: "Celery Man"
community_title: "...and our open-source community"
community_subtitle: "Over 450 contributors have helped build CodeCombat, with more joining every week!"
community_description_1: "CodeCombat is a community project, with hundreds of players volunteering to create levels, contribute to our code to add features, fix bugs, playtest, and even translate the game into 50 languages so far. Employees, contributors and the site gain by sharing ideas and pooling effort, as does the open source community in general. The site is built on numerous open source projects, and we are open sourced to give back to the community and provide code-curious players a familiar project to explore and experiment with. Anyone can join the CodeCombat community! Check out our "
community_description_link: "contribute page "
community_description_2: "for more info."
story_title: "Our story so far"
story_subtitle: "Since 2013, CodeCombat has grown from a mere set of sketches to a living, thriving game."
story_statistic_1a: "5,000,000+"
story_statistic_1b: "total players"
story_statistic_2a: "Weve been translated into over 50 languages — our players hail from"
story_statistic_2b: "200+ countries"
story_statistic_3a: "Together, they have written"
story_statistic_3b: "1 billion lines of code and counting"
story_statistic_3c: "across six different programming languages"
story_long_way_1: "Though we've come a long way..."
story_sketch_caption: "Nick's very first sketch depicting a programming game in action."
story_long_way_2: "we still have much to do before we complete our quest, so..."
jobs_title: "Come work with us and help write CodeCombat history!"
jobs_subtitle: """Don't see a good fit but interested in keeping in touch? See our "Create Your Own" listing."""
jobs_benefits: "Employee Benefits"
jobs_benefit_1: "Competitive salary and options"
jobs_benefit_2: "15 day minimum vacation policy, excluding company holidays"
jobs_benefit_3: "Work from home flexibility"
jobs_benefit_4: "Unlimited sick/personal days"
jobs_benefit_5: "Professional development and continuing education support"
jobs_benefit_6: "Medical/dental/vision insurance"
jobs_custom_title: "Create Your Own"
jobs_custom_description: "Are you passionate about CodeCombat but don't see a job listed that matches your qualifications? Write us and show how you think you can contribute to our team. We'd love to hear from you!"
jobs_custom_contact_1: "Send us a note at "
jobs_custom_contact_2: "introducing yourself and we might get in touch in the future!"
contact_title: "Press & Contact"
contact_subtitle: "Need more information? Get in touch with us at "
screenshots_title: "Game Screenshots"
screenshots_hint: "(click to view full size)"
downloads_title: "Download Assets & Information"
about_codecombat: "About CodeCombat"
logo: "Logo"
screenshots: "Screenshots"
character_art: "Character Art"
download_all: "Download All"
location_title: "We're located in downtown SF:"
teachers: teachers:
who_for_title: "Who is CodeCombat for?" who_for_title: "Who is CodeCombat for?"

View file

@ -1,36 +1,327 @@
@import "app/styles/bootstrap/variables"
@import "app/styles/mixins"
@import "app/styles/style-flat"
#about-view #about-view
@import "bootstrap/variables" overflow: hidden
.team-column #nav-container
padding-left: 0 min-height: 55px
nav
background: $gold
&.affix
z-index: 1
position: fixed
top: 0
width: 100%
ul
margin-top: 5px
padding-left: 0
list-style: none
li
height: 22pt
display: inline-block
margin: 10px 18px 0 18px
a
color: white
text-transform: uppercase
text-decoration: none
li.active
.label
padding-left: 0
padding-right: 0
padding-bottom: 0
margin-left: 0.6em
margin-right: 0.6em
border-bottom: 4px solid white
border-radius: 0
ul.thumbnails #jumbotron
margin-left: 40px background-color: $navy
background-image: url("/images/pages/about/codebackground_zoom_compressed.png")
background-size: cover
background-repeat: no-repeat
h1
color: white
margin-top: 100px
h2
color: white
margin-bottom: 100px
.responsive-side-margins, h3, h4, p
max-width: 460px
margin-left: auto
margin-right: auto
@media (min-width: $screen-sm-min)
max-width: inherit
h3
margin-top: 60px
@media (min-width: $screen-sm-min)
margin-top: 150px
#about-container
@media (min-width: $screen-sm-min)
margin-top: 85px
background-color: white
#mission-text
margin-top: 30px
@media (min-width: $screen-sm-min)
margin-top: 45px
#mission-graphic, #community-graphic
padding: 30px 40px
position: relative
min-height: 320px
@media (min-width: $screen-sm-min)
min-height: 250px
h2
color: white
width: 50%
#mission-graphic
margin-top: 30px
@media (min-width: $screen-sm-min)
margin-top: 45px
background: $navy
h2
float: right
img
position: absolute
bottom: 0
left: 0
#mission-graphic-filler
background: $navy
height: 100%
width: 2000px
position: absolute
right: 100%
top: 0
#team
ul
text-align: center
margin-top: 40px
padding: 0 padding: 0
li li
list-style-type: none width: 200px
height: 230px
list-style: none
display: inline-block
text-align: center
color: black
small
display: block
white-space: nowrap
.img-thumbnail
border-radius: 50%
padding: 0
background-color: $burgandy
border: 5px solid $gold
// #community
// margin-top: 100px
img.img-thumbnail #community-row-1
background-color: transparent #community-avatars
&:hover width: 90%
background-color: rgba(200, 244, 255, 0.2) margin: 20px 5%
float: left
width: 80px
height: 80px
margin: 0px 10px 22px 0px
.team_name #community-row-2
font-size: 20px margin-top: 35px
margin-top: 0 @media (min-width: $screen-sm-min)
margin-top: 70px
.team_bio #community-graphic
width: 150px background: $burgandy
float: left
div img
font-size: 12px position: absolute
line-height: 14px right: 0
padding-bottom: 5px bottom: 0
#community-graphic-filler
background: $burgandy
height: 100%
width: 2000px
position: absolute
left: 100%
top: 0
#story
// margin-top: 150px
font-family: $headline-font
font-variant: normal
#story-graphic-1
max-width: 580px
margin-top: 50px
@media (min-width: $screen-sm-min)
margin-top: 80px
margin-left: auto
margin-right: auto
.media-heading
color: $burgandy
#story-graphic-2
//TODO: Fix left-margin of this
margin-top: 50px
@media (min-width: $screen-sm-min)
margin-top: 80px
margin-left: auto
margin-right: auto
max-width: 390px
.media-heading
color: $forest
#story-graphic-3
margin-top: 50px
@media (min-width: $screen-sm-min)
margin-top: 80px
p
margin-top: 30px
img
margin-top: 20px
#story-bracketed-text
width: 100%
max-width: 640px
margin: 0 auto
.text-h1
display: inline-block
margin: auto 0
color: $navy
width: 80%
vertical-align: bottom
img
margin: auto 0
#left-bracket
width: 10%
display: inline-block
#right-bracket
width: 10%
display: inline-block
#story-languages
margin-top: 50px
#language-icons
display: inline-block
padding-left: auto
padding-right: auto
#story-graphic-4
margin-left: auto
margin-right: auto
margin-top: 50px
@media (min-width: $screen-sm-min)
margin-top: 150px
p
margin-top: 20px
figure
img
display: block
margin: 0 auto
#jobs
// margin-top: 50px
// @media (min-width: $screen-sm-min)
// margin-top: 100px
#jobs-row
#benefits, .job-listing
margin-top: 65px
border: thin solid $navy
border-radius: 8px
padding: 50px
width: 370px
height: 420px
margin-left: auto
margin-right: auto
h5
text-align: center
color: inherit
li
padding-bottom: 7px
#benefits
color: white
background: $navy
ul
margin-top: 20px
.job-listing
color: $navy
background: white
// centering hack
position: relative
.label
text-transform: uppercase
color: grey
a.job-link
width: 170px
bottom: 45px
// centering hack
position: absolute
left: 50%
margin-left: -85px
p
margin-top: 15px
#files
padding: 30px 0
margin-top: 50px
border: thin solid gray
border-radius: 8px
.label
color: black
display: block
#screenshots
text-align: center
#screenshot-grid
img
display: inline-block
margin: 6.5px
#downloads-container
position: relative
height: 250px
#downloads
//TODO: How do I center this in small view?
margin: 20px auto 0
width: 260px
ul
width: 260px
margin-top: 10px
margin-bottom: 20px
margin-left: -25px
a
color: black
#download-button
margin: 0 auto
color: $navy
.glyphicon-download-alt
margin-right: 15px
vertical-align: middle
font-size: 1.5em
#screenshot-lightbox
.modal-dialog
width: auto
max-width: 1024px
#location
margin-top: 75px
margin-bottom: 100px
text-align: center
p b
margin-top: 40px
a
color: inherit
text-decoration: underline
iframe
border: 2px solid lightgray
.anchor::before
content: ""
display: block
height: 55px
margin: -55px 0 0 0

View file

@ -1,205 +1,6 @@
@import "app/styles/bootstrap/variables" @import "app/styles/bootstrap/variables"
@import "app/styles/mixins" @import "app/styles/mixins"
@import "app/styles/style-flat"
// TODO: Move flat style into probably several files and Bootstrap variables
// Variables
$headline-font: 'Arvo', serif
$body-font: 'Open Sans', sans-serif
$burgandy: #7D0101
$gold: #F2BE19
$navy: #0E4C60
$forest: #20572B
.style-flat
background: white
// Fonts
h1, h2, h3, h4, h5, h6
// Unsetting game styles
font-variant: normal
color: black
margin: 0
h1
font-family: $headline-font
font-weight: normal
font-size: 46px
line-height: 62px
h2
font-family: $body-font
font-weight: lighter
font-size: 30px
line-height: 42px
h3
font-family: $headline-font
font-weight: normal
font-size: 33px
line-height: 45px
h4
font-family: $body-font
font-weight: lighter
font-size: 22px
line-height: 32px
h5
font-family: $headline-font
font-weight: bold
font-size: 20px
line-height: 31px
h6
font-family: $body-font
font-weight: bold
font-size: 14px
line-height: 20px
p
margin: 0 0 14px
.small
font-weight: normal
font-size: 14px
line-height: 20px
font-family: $body-font
font-size: 18px
line-height: 29px
blockquote
border: none
&:before
font-family: "Monaco"
content: "\201C"
position: absolute
left: 0px
top: 20px
font-size: 40px
opacity: 0.5
// Navbar
.navbar
background: white
margin-bottom: 0
white-space: nowrap // prevent home icon from going under brand
a.navbar-brand
#logo-img
width: 230px
height: 65px
margin-right: 10px
color: $burgandy
&:hover
color: white
background: $burgandy
.glyphicon-home
position: relative
top: 3px
.navbar-toggle
color: black
margin: 30px 25px 0
.nav > li > a
// TODO: Move this to bootstrap variables for navbars
font-weight: bold
font-family: $body-font
font-size: 16px
padding: 38px 15px 37px
color: $burgandy
text-shadow: 0 0 0
&:hover
background: $burgandy
color: white
#language-dropdown-wrapper
display: inline-block
padding: 30px 10px
width: 100%
@media (max-width: $screen-sm-min)
.nav > li > a
padding: 10px 20px
#language-dropdown-wrapper
display: inline-block
padding: 10px 10px
.language-dropdown
width: 150px
.img-circle
border: $gold 8px solid
width: 98px
height: 98px // Includes the border
.user-level
position: absolute
top: 76px
right: 42px
color: $gold
text-shadow: 1px 1px black, -1px -1px 0 black, 1px -1px 0 black, -1px 1px 0 black
// Buttons
.btn
border: none
border-radius: 5px
font-family: $body-font
font-weight: normal
background-image: none // overrides legacy buttons
.btn-primary, .btn-navy
background-color: $navy
color: white
.btn-primary-alt, .btn-navy-alt
background-color: white
border: 1px solid $navy
color: $navy
.btn-forest
background-color: $forest
color: white
.btn-forest-alt
background-color: white
border: 1px solid $forest
color: $forest
.btn-gold
background-color: $gold
color: white
.btn-gold-alt
background-color: white
border: 1px solid $gold
color: $gold
.btn-lg
font-size: 18px
// Classes
.text-navy
color: $navy
.bg-navy
background-color: $navy
color: white
h1, h2, h3, h4, h5, h6, a
color: white
a.btn-primary-alt
color: $navy
#new-home-view #new-home-view
@ -464,40 +265,3 @@ $forest: #20572B
img img
margin-bottom: 20px margin-bottom: 20px
#footer
background-image: url("/images/pages/home/footer_background.png")
height: 229px
margin: -22px auto 0
color: white
@media (max-width: $screen-sm-min)
background-color: #201a15
background-image: none
height: auto
ul
margin: 30px
li:first-child
border-bottom: 1px solid white
margin-bottom: 10px
a
color: white
#final-footer
position: absolute
left: 0
right: 0
height: 60px
color: white
background-color: #463a2c
@media (max-width: $screen-sm-min)
position: inherit
padding: 20px
height: auto
a
color: white
img
width: 150px
margin: 0 10px

View file

@ -1,27 +1,32 @@
#request-quote-view #request-quote-view
#site-content-area
//TODO: Maybe this should go in style-flat
margin: 50px 10px 100px
label .section
margin-bottom: 2px margin-top: 80px
margin-bottom: 50px
.row .form-group
margin: 10px 0 label
margin-bottom: 0
label.checkbox
font-weight: normal
.help-block .help-block
margin: 0 margin: -4px 0 2px
p p
margin: 0 0 20px margin: 0 0 20px
hr
margin: 30px 0
.checkbox, .checkbox-inline .checkbox, .checkbox-inline
margin: 0 input
margin-top: 8px
#anything-else-row
margin: 50px 0 20px
#other-education-level-input #other-education-level-input
label
display: inline-block
display: inline-block display: inline-block
width: 200px width: 200px
margin-left: 5px margin-left: 5px

239
app/styles/style-flat.sass Normal file
View file

@ -0,0 +1,239 @@
@import "app/styles/bootstrap/variables"
@import "app/styles/mixins"
// TODO: Move flat style into probably several files and Bootstrap variables
// Variables
$headline-font: 'Arvo', serif
$body-font: 'Open Sans', sans-serif
$burgandy: #7D0101
$gold: #F2BE19
$navy: #0E4C60
$forest: #20572B
.style-flat
background: white
// Fonts
h1, h2, h3, h4, h5, h6
// Unsetting game styles
font-variant: normal
color: black
margin: 0
h1, .text-h1
font-family: $headline-font
font-weight: normal
font-size: 46px
line-height: 62px
h2, .text-h2
font-family: $body-font
font-weight: lighter
font-size: 30px
line-height: 42px
h3, .text-h3
font-family: $headline-font
font-weight: normal
font-size: 33px
line-height: 45px
h4, .text-h4
font-family: $body-font
font-weight: lighter
font-size: 22px
line-height: 32px
h5, .text-h5
font-family: $headline-font
font-weight: bold
font-size: 20px
line-height: 31px
h6, .text-h6
font-family: $body-font
font-weight: bold
font-size: 14px
line-height: 20px
p
margin: 0 0 14px
.small
font-weight: normal
font-size: 14px
line-height: 20px
font-family: $body-font
font-size: 18px
line-height: 29px
blockquote
border: none
&:before
font-family: "Monaco"
content: "\201C"
position: absolute
left: 0px
top: 20px
font-size: 40px
opacity: 0.5
// Navbar
.navbar
background: white
margin-bottom: 0
white-space: nowrap // prevent home icon from going under brand
a.navbar-brand
#logo-img
width: 230px
height: 65px
margin-right: 10px
color: $burgandy
&:hover
color: white
background: $burgandy
.glyphicon-home
position: relative
top: 3px
.navbar-toggle
color: black
margin: 30px 25px 0
.nav > li > a
// TODO: Move this to bootstrap variables for navbars
font-weight: bold
font-family: $body-font
font-size: 16px
padding: 38px 15px 37px
color: $burgandy
text-shadow: 0 0 0
&:hover
background: $burgandy
color: white
#language-dropdown-wrapper
display: inline-block
padding: 30px 10px
width: 100%
@media (max-width: $screen-sm-min)
.nav > li > a
padding: 10px 20px
#language-dropdown-wrapper
display: inline-block
padding: 10px 10px
.language-dropdown
width: 150px
.img-circle
border: $gold 8px solid
width: 98px
height: 98px // Includes the border
.user-level
position: absolute
top: 76px
right: 42px
color: $gold
text-shadow: 1px 1px black, -1px -1px 0 black, 1px -1px 0 black, -1px 1px 0 black
// Buttons
.btn
border: none
border-radius: 5px
font-family: $body-font
font-weight: normal
background-image: none // overrides legacy buttons
.btn-primary, .btn-navy
background-color: $navy
color: white
.btn-primary-alt, .btn-navy-alt
background-color: white
border: 1px solid $navy
color: $navy
.btn-forest
background-color: $forest
color: white
.btn-forest-alt
background-color: white
border: 1px solid $forest
color: $forest
.btn-gold
background-color: $gold
color: white
.btn-gold-alt
background-color: white
border: 1px solid $gold
color: $gold
.btn-lg
font-size: 18px
// Classes
.text-navy
color: $navy
.bg-navy
background-color: $navy
color: white
h1, h2, h3, h4, h5, h6, a
color: white
a.btn-primary-alt
color: $navy
#footer
background-image: url("/images/pages/home/footer_background.png")
height: 229px
margin: -22px auto 0
color: white
@media (max-width: $screen-sm-min)
background-color: #201a15
background-image: none
height: auto
ul
margin: 30px
li:first-child
border-bottom: 1px solid white
margin-bottom: 10px
a
color: white
#final-footer
position: absolute
left: 0
right: 0
height: 60px
color: white
background-color: #463a2c
@media (max-width: $screen-sm-min)
position: inherit
padding: 20px
height: auto
a
color: white
img
width: 150px
margin: 0 10px

View file

@ -1,188 +1,441 @@
extends /templates/base extends /templates/base-flat
block content block content
.style-flat(data-spy="scroll", data-target="#nav-container")
.container-fluid#jumbotron
.container
.row
//TODO: Size these correctly
.col-xs-10
h1 If you want to learn to program, you need to write (a lot of) code.
.row
.col-xs-8
h2 At CodeCombat, our job is to make sure you're doing that with a smile on your face.
img(src="/images/pages/about/coco_comic.jpg") #nav-container
nav#fixed-nav.nav.navbar
.container-fluid.text-center
ul.center-block
li.active
a(href="#mission")#mission-link
small.label(data-i18n="about.mission_link")
| Mission
li
a(href="#team")#team-link
small.label(data-i18n="about.team_link")
| Team
li
a(href="#community")#community-link
small.label(data-i18n="about.community_link")
| Community
li
a(href="#story")#story-link
small.label(data-i18n="about.story_link")
| Story
li
a(href="#jobs")#jobs-link
small.label(data-i18n="about.jobs_link")
| Careers
li
a(href="#contact")#contact-link
small.label(data-i18n="about.contact_link")
| Press
.row #about-container.container
#mission.anchor.row
.col-sm-6 .col-sm-6#mission-graphic.responsive-side-margins
img(src="/images/pages/about/globe_white.png")
h2(data-i18n="about.why_codecombat") h2(data-i18n="about.mission_title")
| Why CodeCombat? | Our mission: make programming accessible to every student on Earth.
#mission-graphic-filler
p(data-i18n="about.why_paragraph_1") .col-sm-5.col-sm-offset-1
| If you want to learn to program, you don't need lessons. #mission-text.responsive-side-margins
| You need to write a lot of code and have a great time doing it. p(data-i18n="about.mission_description_1")
| Programming is magic. It's the ability to create things from pure imagination. We started CodeCombat to give learners the feeling of wizardly power at their fingertips by using typed code.
p p(data-i18n="about.mission_description_2")
span(data-i18n="about.why_paragraph_2_prefix") | As it turns out, that enables them to learn faster too. WAY faster. It's like having a conversation instead of reading a manual. We want to bring that conversation to every school and to every student, because everyone should have the chance to learn the magic of programming.
| That's what programming is about. It's gotta be fun.
| Not fun like
span
i(data-i18n="about.why_paragraph_2_italic")
| yay a badge
span
span(data-i18n="about.why_paragraph_2_center")
| but fun like
span
i(data-i18n="about.why_paragraph_2_italic_caps")
| NO MOM I HAVE TO FINISH THE LEVEL!
span
span(data-i18n="about.why_paragraph_2_suffix")
| That's why CodeCombat is a multiplayer game,
| not a gamified lesson course. We won't stop
| until you can't stop--but this time, that's a good thing.
p(data-i18n="about.why_paragraph_3")
| If you're going to get addicted to some game,
| get addicted to this one and become one of the wizards of the tech age.
h2(data-i18n="about.press_title")
| Bloggers/Press
p
span.spr(data-i18n="about.press_paragraph_1_prefix")
| Want to write about us? Feel free to download and use all of the resources included in our
a(href="https://s3.amazonaws.com/CodeCombatMisc/press_packet.zip", data-i18n="about.press_paragraph_1_link") press packet
span(data-i18n="about.press_paragraph_1_suffix")
| . All logos and images may be used without contacting us directly.
h2(data-i18n="nav.contact")
| Contact
p
span CodeCombat Inc.
br
span 360 3rd St Suite 700 (Livefyre)
br
span San Francisco, CA 94107
br
a(href='mailto:team@codecombat.com') team@codecombat.com
if me.get('preferredLanguage') == 'pt-BR'
span CodeCombat, Brazil
br
span Rua 1814 Militão Chaves
br
span Natal, Brazil, RN 59064-500
ul.col-sm-6.team-column
ul.thumbnails
li.row
h2(data-i18n="about.team") Team
#team.anchor
.text-center
h3(data-i18n="about.team_title")
| Meet the CodeCombat team
h4.responsive-side-margins(data-i18n="about.team_values")
| We value open and respectful dialog, where the best idea wins. Our decisions are grounded in customer research and our process is focused on delivering tangible results for them. Everyone is hands-on, from our CEO to our Github contributors, because we value growth and learning in our team.
ul
// Full time // Full time
li
a(href="http://www.nickwinter.net" rel="external")
img(src="/images/pages/about/nick_small.png").img-thumbnail
.team-bio
h6.label.team-name
a(href="http://www.nickwinter.net" rel="external") Nick Winter
small(data-i18n="about.nick_title")
small(data-i18n="about.nick_blurb")
a(href="http://www.nickwinter.net") li
img(src="/images/pages/about/nick_small.png").img-thumbnail a(href="http://www.mattlott.com/" rel="external")
.team_bio img(src="/images/pages/about/matt_small.png").img-thumbnail
h4.team_name .team-bio
a(href="http://www.nickwinter.net") Nick Winter h6.label.team-name
div(data-i18n="about.nick_title") a(href="http://www.mattlott.com/" rel="external") Matt Lott
div(data-i18n="about.nick_blurb") small(data-i18n="about.matt_title")
small(data-i18n="about.matt_blurb")
a(href="http://www.mattlott.com/") li
img(src="/images/pages/about/matt_small.png").img-thumbnail a(href="http://cat.zdh.com/" rel="external")
.team_bio img(src="/images/pages/about/cat_small.png").img-thumbnail
h4.team_name .team-bio
a(href="http://www.mattlott.com/") Matt Lott h6.label.team-name
div(data-i18n="about.matt_title") a(href="http://cat.zdh.com/" rel="external") Catherine Weresow
div(data-i18n="about.matt_blurb") small(data-i18n="about.cat_title")
small(data-i18n="about.cat_blurb")
li.row li
img(src="/images/pages/about/scott_small.png").img-thumbnail
.team-bio
h6.label.team-name Scott Erickson
small(data-i18n="about.scott_title")
small(data-i18n="about.scott_blurb")
a(href="http://cat.zdh.com/") li
img(src="/images/pages/about/cat_small.png").img-thumbnail img(src="/images/pages/about/maka_small.png").img-thumbnail
.team_bio .team-bio
h4.team_name h6.label.team-name Michael 'Maka' Gradin
a(href="http://cat.zdh.com/") Catherine Weresow small(data-i18n="about.maka_title")
div(data-i18n="about.cat_title") small(data-i18n="about.maka_blurb")
div(data-i18n="about.cat_blurb")
img(src="/images/pages/about/scott_small.png").img-thumbnail a(href="http://basicer.com/" rel="external")
.team_bio
h4.team_name Scott Erickson
div(data-i18n="about.scott_title")
div(data-i18n="about.scott_blurb")
li.row li
a(href="http://basicer.com/" rel="external")
img(src="/images/pages/about/rob_small.png").img-thumbnail
.team-bio
h6.label.team-name
a(href="http://basicer.com/" rel="external") Rob Blanckaert
small(data-i18n="about.rob_title")
small(data-i18n="about.rob_blurb")
img(src="/images/pages/about/maka_small.png").img-thumbnail li
.team_bio img(src="/images/pages/about/josh_c_small.png").img-thumbnail
h4.team_name Michael 'Maka' Gradin .team-bio
div(data-i18n="about.maka_title") h6.label.team-name Josh Callebaut
div(data-i18n="about.maka_blurb") small(data-i18n="about.josh_c_title")
small(data-i18n="about.josh_c_blurb")
a(href="http://basicer.com/") a(href="http://robinyang.com/" rel="external")
img(src="/images/pages/about/rob_small.png").img-thumbnail
.team_bio
h4.team_name
a(href="http://basicer.com/") Rob Blanckaert
div(data-i18n="about.rob_title")
div(data-i18n="about.rob_blurb")
li.row li
a(href="http://robinyang.com/" rel="external")
img(src="/images/pages/about/josh_c_small.png").img-thumbnail img(src="/images/pages/about/robin_small.png").img-thumbnail
.team_bio .team-bio
h4.team_name Josh Callebaut h6.label.team-name
div(data-i18n="about.josh_c_title") a(href="http://robinyang.com/" rel="external") Robin Yang
div(data-i18n="about.josh_c_blurb") small(data-i18n="about.robin_title")
small(data-i18n="about.robin_blurb")
a(href="http://robinyang.com/")
img(src="/images/pages/about/robin_small.png").img-thumbnail
.team_bio
h4.team_name
a(href="http://robinyang.com/") Robin Yang
div(data-i18n="about.robin_title")
div(data-i18n="about.robin_blurb")
// Part time / contract // Part time / contract
li.row li
a(href="http://floor.is/lava/" rel="external")
img(src="/images/pages/about/josh_small.png").img-thumbnail
.team-bio
h6.label.team-name
a(href="http://floor.is/lava/" rel="external") Josh Lee
small(data-i18n="about.josh_title")
small(data-i18n="about.josh_blurb")
a(href="http://floor.is/lava/") li
img(src="/images/pages/about/josh_small.png").img-thumbnail a(href="https://soundcloud.com/taking-off" rel="external")
.team_bio img(src="/images/pages/about/jose_small.png").img-thumbnail
h4.team_name .team-bio
a(href="http://floor.is/lava/") Josh Lee h6.label.team-name
div(data-i18n="about.josh_title") a(href="https://soundcloud.com/taking-off" rel="external") Jose Antonini
div(data-i18n="about.josh_blurb") small(data-i18n="about.jose_title")
small(data-i18n="about.jose_blurb")
a(href="https://soundcloud.com/taking-off") li
img(src="/images/pages/about/jose_small.png").img-thumbnail a(href="http://retrostylegames.com/" rel="external")
.team_bio img(src="/images/pages/about/pavel_small.png").img-thumbnail
h4.team_name .team-bio
a(href="https://soundcloud.com/taking-off") Jose Antonini h6.label.team-name
div(data-i18n="about.jose_title") a(href="http://retrostylegames.com/" rel="external") Pavel Konstantinov
div(data-i18n="about.jose_blurb") small(data-i18n="about.retrostyle_title")
small(data-i18n="about.retrostyle_blurb")
li.row li
a(href="http://retrostylegames.com/" rel="external")
img(src="/images/pages/about/oleg_small.png").img-thumbnail
.team-bio
h6.label.team-name
a(href="http://retrostylegames.com/" rel="external") Oleg Ulyanickiy
small(data-i18n="about.retrostyle_title")
small(data-i18n="about.retrostyle_blurb")
a(href="http://retrostylegames.com/") li
img(src="/images/pages/about/pavel_small.png").img-thumbnail img(src="/images/pages/about/carlos_small.png").img-thumbnail
.team_bio .team-bio
h4.team_name h6.label.team-name Carlos Maia
a(href="http://retrostylegames.com/") Pavel Konstantinov small(data-i18n="about.carlos_title")
div(data-i18n="about.retrostyle_title") small(data-i18n="about.carlos_blurb")
div(data-i18n="about.retrostyle_blurb")
a(href="http://retrostylegames.com/") #community.anchor
img(src="/images/pages/about/oleg_small.png").img-thumbnail #community-row-1.row.text-center
.team_bio .col-sm-12
h4.team_name .text-center
a(href="http://retrostylegames.com/") Oleg Ulyanickiy h3(data-i18n="about.community_title")
div(data-i18n="about.retrostyle_title") | ...and our open-source community
div(data-i18n="about.retrostyle_blurb") h4(data-i18n="about.community_subtitle")
| Over 450 contributors have helped build CodeCombat, with more joining every week!
img(src="/images/pages/about/github_avatars.png")#community-avatars
li.row #community-row-2.row
.col-sm-5
p.responsive-side-margins
span(data-i18n="about.community_description_1")
| CodeCombat is a community project, with hundreds of players volunteering to create levels, contribute to our code to add features, fix bugs, playtest, and even translate the game into 50 languages so far. Employees, contributors and the site gain by sharing ideas and pooling effort, as does the open source community in general. The site is built on numerous open source projects, and we are open sourced to give back to the community and provide code-curious players a familiar project to explore and experiment with. Anyone can join the CodeCombat community! Check out our
a(href="/contribute")
span(data-i18n="about.community_description_link")
| contribute page
span(data-i18n="about.community_description_2")
| for more info.
.col-sm-6.col-sm-offset-1#community-graphic.responsive-side-margins
h2 Over 450 contributors have lent their support and time to this project.
img(src="/images/pages/about/github.png")
#community-graphic-filler
img(src="/images/pages/about/carlos_small.png").img-thumbnail #story.anchor
.team_bio .text-center
h4.team_name Carlos Maia h3(data-i18n="about.story_title")
div(data-i18n="about.carlos_title") | Our story so far
div(data-i18n="about.carlos_blurb") h4.responsive-side-margins(data-i18n="about.story_subtitle")
| Since 2013, CodeCombat has grown from a mere set of sketches to a living, thriving game.
.row
#story-graphic-1.col-lg-6
.media
.pull-left
img.media-object#story-image-1(src="/images/pages/about/Character_Silouhette.png")
.media-body
.media-heading.text-h1
span(data-i18n="about.story_statistic_1a")
| 5,000,000+
br
span(data-i18n="about.story_statistic_1b")
| total players
p.text-h5 have started their programming journey through CodeCombat
.col-lg-5.col-lg-offset-1
#story-graphic-2
.media
p.text-h5(data-i18n="about.story_statistic_2a")
| Weve been translated into over 50 languages — our players hail from
.pull-right
img(src="/images/pages/about/globe_green.png")
.media-body
.media-heading.text-h1(data-i18n="about.story_statistic_2b")
| 200+ countries
#story-graphic-3.text-center
p
div.text-h5(data-i18n="about.story_statistic_3a")
| Together, they have written
#story-bracketed-text
div#left-bracket
img(src="/images/pages/about/bracket_left.png")
div.text-h1(data-i18n="about.story_statistic_3b")
| 1 billion lines of code and counting
div#right-bracket
img(src="/images/pages/about/bracket_right.png")
#story-languages
.text-center
.text-h5(data-i18n="about.story_statistic_3c")
| across six different programming languages
#language-icons.text-center
img.hidden-xs(src="/images/pages/about/Languages.png")
img.hidden-sm.hidden-md.hidden-lg(src="/images/pages/about/Languages_group1.png")
img.hidden-sm.hidden-md.hidden-lg(src="/images/pages/about/Languages_group2.png")
#story-graphic-4.text-center
p
div.text-h5(data-i18n="about.story_long_way_1")
| Though we've come a long way...
figure
img(src="/images/pages/about/sketch.png")
figcaption
small(data-i18n="about.story_sketch_caption")
| Nick's very first sketch depicting a programming game in action.
p
.text-h5(data-i18n="about.story_long_way_2")
| we still have much to do before we complete our quest, so...
#jobs.anchor
.text-center
h3(data-i18n="about.jobs_title")
| Come work with us and help write CodeCombat history!
h4(data-i18n="about.jobs_subtitle")
| Don't see a good fit but interested in keeping in touch? See our "Create Your Own" listing.
#jobs-row.row
.col-sm-6.col-md-5.col-md-offset-1.col-lg-4.col-lg-offset-0
#benefits
h5(data-i18n="about.jobs_benefits")
| Employee Benefits
ul
li.small(data-i18n="about.jobs_benefit_1")
| Competitive salary and options
li.small(data-i18n="about.jobs_benefit_2")
| 15 day minimum vacation policy, excluding company holidays
li.small(data-i18n="about.jobs_benefit_3")
| Work from home flexibility
li.small(data-i18n="about.jobs_benefit_4")
| Unlimited sick/personal days
li.small(data-i18n="about.jobs_benefit_5")
| Professional development and continuing education support
li.small(data-i18n="about.jobs_benefit_6")
| Medical/dental/vision insurance
.col-sm-6.col-md-5.col-lg-4
.job-listing
h5 Software Engineer, iOS
.text-center
small.label
| San Francisco • Fulltime
p.small Want to write the first iPad app for CodeCombat? Were looking for a product-focused engineer to translate our core gameplay and educational tools into an experience that feels like it was born on the iPad.
a.job-link.btn.btn-lg.btn-navy(href="https://jobs.lever.co/codecombat/eb190007-7195-49ee-a322-893b0d1cdcb4" rel="external")
| Learn More
.col-sm-6.col-md-5.col-md-offset-1.col-lg-4.col-lg-offset-0
.job-listing
h5 Head of Sales
.text-center
small.label
| San Francisco • Fulltime
p.small School districts are scrambling to offer computer science classes to all their students as a core subject. They have had no solution, because they can't afford to hire enough programming teachers until now.
a.job-link.btn.btn-lg.btn-navy(href="https://jobs.lever.co/codecombat/2d0194ed-7c69-4aab-b1f9-363ca4b9f04b" rel="external")
| Learn More
.col-sm-6.col-md-5.col-lg-4
.job-listing
h5 Sales Representative
.text-center
small.label
| San Francisco • Fulltime
p.small School districts are scrambling to offer computer science classes to all their students as a core subject. They have had no solution, because they can't afford to hire enough programming teachers until now.
a.job-link.btn.btn-lg.btn-navy(href="https://jobs.lever.co/codecombat/3f6ff123-16ce-4ecb-aba3-dcf4e8927c47" rel="external")
| Learn More
.col-sm-6.col-md-5.col-md-offset-1.col-lg-4.col-lg-offset-0
.job-listing
h5(data-i18n="about.jobs_custom_title")
| Create Your Own
p.small(data-i18n="about.jobs_custom_description")
| Are you passionate about CodeCombat but don't see a job listed that matches your qualifications? Write us and show how you think you can contribute to our team. We'd love to hear from you!
p.small
span(data-i18n="about.jobs_custom_contact_1")
| Send us a note at
a(href="mailto:team@codecombat.com")
| team@codecombat.com
span(data-i18n="about.jobs_custom_contact_2")
| introducing yourself and we might get in touch in the future!
#contact.anchor
.text-center
h3(data-i18n="about.contact_title")
| Press & Contact
h4(data-i18n="about.contact_subtitle")
| Need more information? Get in touch with us at
a(href="mailto:team@codecombat.com") team@codecombat.com
#files
.row
.col-md-6.col-lg-8
#screenshots
span.label(data-i18n="about.screenshots_title")
| Game Screenshots
.hidden-sm.hidden-md.hidden-lg
small(data-i18n="about.screenshots_hint")
| (click to view full size)
#screenshot-grid
a.screen-thumbnail(data-toggle="modal", data-target="#screenshot-lightbox", data-index='0')
img(src="/images/pages/about/screenshot_desert.png")
a.screen-thumbnail(data-toggle="modal", data-target="#screenshot-lightbox", data-index='1')
img(src="/images/pages/about/screenshot_forest.png")
a.screen-thumbnail(data-toggle="modal", data-target="#screenshot-lightbox", data-index='2')
img(src="/images/pages/about/screenshot_dungeon.png")
a.screen-thumbnail(data-toggle="modal", data-target="#screenshot-lightbox", data-index='3')
img(src="/images/pages/about/screenshot_glacier.png")
.clearfix.hidden-xs
small(data-i18n="about.screenshots_hint")
| (click to view full size)
.col-md-6.col-lg-4
#downloads-container
#downloads
.label(data-i18n="about.downloads_title")
| Download Assets & Information
ul
li
a.small(href="http://files.codecombat.com/presspack/AboutCodeCombat.pdf")
span(data-i18n="about.about_codecombat")
| About CodeCombat
| (.pdf)
li
a.small(href="http://files.codecombat.com/presspack/CodeCombat-Logo.ai")
span(data-i18n="about.logo")
| Logo
| (.ai)
li
a.small(href="http://files.codecombat.com/presspack/CodeCombat-Logo.png")
span(data-i18n="about.logo")
| Logo
| (.png)
li
a.small(href="http://files.codecombat.com/presspack/GameImages.zip")
span(data-i18n="about.screenshots")
| Screenshots
| (.zip)
li
a.small(href="http://files.codecombat.com/presspack/gameimages/CodeCombat_Splash.png")
span(data-i18n="about.character_art")
| Character Art
| (.png)
.text-center
a.btn.btn-lg.btn-primary-alt#download-button(href="http://files.codecombat.com/presspack/CodeCombat_PressPack.zip")
span.glyphicon.glyphicon-download-alt
span(data-i18n="about.download_all")
| Download All
#screenshot-lightbox.modal.fade(data-show="false")
.modal-dialog
.modal-content
#screenshot-carousel.carousel
ol.carousel-indicators
li(data-target=".screenshot-display", data-slide-to="0").active
li(data-target=".screenshot-display", data-slide-to="1")
li(data-target=".screenshot-display", data-slide-to="2")
li(data-target=".screenshot-display", data-slide-to="3")
.carousel-inner
.item.active
img#screenshot-desert(src="/images/pages/about/Desert.png")
.item
img#screenshot-forest(src="/images/pages/about/Forest.png")
.item
img#screenshot-dungeon(src="/images/pages/about/Dungeon.png")
.item
img#screenshot-glacier(src="/images/pages/about/Glacier.png")
a#carousel-left.left.carousel-control(href="#screenshot-carousel", role="button")
span.glyphicon.glyphicons-chevron-left.glyphicon-chevron-left(aria-hidden="true")
span.sr-only Previous
a#carousel-right.right.carousel-control(href="#screenshot-carousel", role="button")
span.glyphicon.glyphicons-chevron-right.glyphicon-chevron-right(aria-hidden="true")
span.sr-only Next
#location
.row
.col-sm-4.col-sm-offset-2
p
b CodeCombat Inc.
p 360 3rd St.
p Suite 700 (Livefyre)
p San Francisco, CA 94107
a(href="mailto:team@codecombat.com") team@codecombat.com
.col-sm-4
p
b(data-i18n="about.location_title")
| We're located in downtown SF:
iframe(width="370", height="280", frameBorder="2", src="https://www.google.com/maps/embed/v1/place?key=AIzaSyAIGQz3OMbv5YWivScUM86-zESjEgJR2Xo&q=360+3rd+St+Suite+700,+San+Francisco,+CA+94107")

View file

@ -20,11 +20,12 @@ block content
th Location th Location
th Age / Level th Age / Level
th Students th Students
th How Found / Notes th Role
th Phone
th Status th Status
tbody tbody
- var numReviewed = 0 - var numReviewed = 0
- var maxReviewedShown = 100 - var maxReviewedShown = 1000
each trialRequest in trialRequests each trialRequest in trialRequests
if trialRequest.get('status') !== 'submitted' if trialRequest.get('status') !== 'submitted'
- numReviewed++ - numReviewed++
@ -42,7 +43,8 @@ block content
td= props.location || trialRequest.locationString() td= props.location || trialRequest.locationString()
td= props.age || trialRequest.educationLevelString() td= props.age || trialRequest.educationLevelString()
td= props.numStudents td= props.numStudents
td= props.heardAbout || props.notes td= props.role
td= props.phoneNumber
td.status-cell td.status-cell
if trialRequest.get('status') === 'submitted' if trialRequest.get('status') === 'submitted'
button.btn.btn-xs.btn-success.btn-approve(data-trial-request-id=trialRequest.id) Approve button.btn.btn-xs.btn-success.btn-approve(data-trial-request-id=trialRequest.id) Approve
@ -51,3 +53,10 @@ block content
span= trialRequest.get('prepaidCode') span= trialRequest.get('prepaidCode')
else else
span= trialRequest.get('status') span= trialRequest.get('status')
if props.heardAbout || props.notes
tr
td(colspan=2)
td(colspan=7)
strong #{trialRequest.nameString()} notes:
div= props.heardAbout || props.notes
td

View file

@ -0,0 +1,144 @@
.style-flat
block header
.container-fluid.text-center
.alert.alert-danger.lt-ie9
strong(data-i18n="home.no_ie") The CodeCombat game does not run in Internet Explorer 8 or older. Sorry!
if view.isIPadBrowser() || view.isMobile()
.alert.alert-danger.mobile
strong(data-i18n="home.no_mobile") CodeCombat gameplay was not designed for mobile devices and may not work!
else if view.isOldBrowser()
.alert.alert-danger.old-browser
strong(data-i18n="home.old_browser") Uh oh, your browser is too old to play CodeCombat. Sorry!
br
span(data-i18n="home.old_browser_suffix") You can try anyway, but it probably won't work.
nav.navbar.navbar-default
.container
.row
.col-md-3.col-sm-4
.navbar-header
button.navbar-toggle.collapsed(data-toggle='collapse', data-target='#navbar-collapse' aria-expanded='false')
span.sr-only Toggle navigation
span.icon-bar
span.icon-bar
span.icon-bar
a.navbar-brand(href="/")
img#logo-img(src="/images/pages/base/logo.png")
span.glyphicon.glyphicon-home
.col-md-9.col-sm-8
#navbar-collapse.collapse.navbar-collapse
ul.nav.navbar-nav.pull-left
li
a(href="/about") About
li
a(href="/courses") Courses
li
a(href="/courses/teachers") Teachers
li
a(href="https://discourse.codecombat.com/") Forum
if me.isAnonymous()
li
a#create-account-link.signup-button Create Account
li
a#login-link.login-button Login
else
li.dropdown
a.dropdown-toggle(href="#", data-toggle="dropdown" role="button" aroa-haspopup="true" aria-expanded="false")
span.spr My Account
ul.dropdown-menu
li.user-dropdown-header.text-center
span.user-level= me.level()
a(href="/user/#{me.getSlugOrID()}")
img.img-circle(src=me.getPhotoURL())
h5=me.displayName()
li
a(href="/user/#{me.getSlugOrID()}" data-i18n="nav.profile")
li
a(href="/account/settings", data-i18n="play.settings")
li
a(href="/account/payments", data-i18n="account.payments")
li
a(href="/account/subscription", data-i18n="account.subscription")
li
a(href="/account/prepaid", data-i18n="account.prepaid_codes") Prepaid Codes
li
a#logout-button(data-i18n="login.log_out")
li
#language-dropdown-wrapper
select.language-dropdown.form-control
block outer_content
#site-content-area
block content
p If this is showing, you dun goofed
block footer
#character-lineup.text-center
img(src="/images/pages/home/character_lineup.png")
.container-fluid
#footer.small
.container
.row
.col-sm-3
ul.list-unstyled
li
strong CodeCombat
li
a(href="/about") About
li
a(href="/Careers") Jobs
li
a(href="http://blog.codecombat.com/", data-i18n="nav.blog")
li
a(href="/legal") Legal
.col-sm-3
ul.list-unstyled
li
strong Schools
li
a(href="/courses/teachers") Teachers
li
a(href="https://sites.google.com/a/codecombat.com/teacher-guides/") Educator Wiki
li
a(href="/teachers/quote") Request a Quote
.col-sm-3
ul.list-unstyled
li
strong Get Involved
li
a(href='/community', data-i18n="nav.community")
li
a(href="/contribute") Contribute
li
a(href=view.forumLink(), data-i18n="nav.forum")
li
a(href="/play/ladder") Multiplayer
li
a(href="https://github.com/codecombat/codecombat") Open source (GitHub)
.col-sm-3
ul.list-unstyled
li
strong Support
li
a(href="https://discourse.codecombat.com/t/faq-check-before-posting/1027") FAQs
li
a(tabindex=-1, data-toggle="coco-modal", data-target="core/ContactModal", data-i18n="nav.contact")
li
a(href="https://www.facebook.com/codecombat", data-i18n="nav.facebook")
li
a(href="https://twitter.com/codecombat", data-i18n="nav.twitter")
#final-footer.small.text-center
| Copyright ©2016 CodeCombat. All Rights Reserved.
br.hidden-lg.hidden-md
img(src="/images/pages/base/logo.png" alt="CodeCombat")
br.hidden-lg.hidden-md
span.spr Need help? Email
a(href="mailto:team@codecombat.com") team@codecombat.com
span.spl and we'll get in touch!

View file

@ -1,388 +1,253 @@
.container-fluid.text-center extends /templates/base-flat
.alert.alert-danger.lt-ie9
strong(data-i18n="home.no_ie") The CodeCombat game does not run in Internet Explorer 8 or older. Sorry!
if view.isIPadBrowser() || view.isMobile() block content
.alert.alert-danger.mobile .container-fluid#jumbotron-container-fluid(class=view.jumbotron === 'student' ? 'alt-image' : '')
strong(data-i18n="home.no_mobile") CodeCombat gameplay was not designed for mobile devices and may not work!
else if view.isOldBrowser()
.alert.alert-danger.old-browser
strong(data-i18n="home.old_browser") Uh oh, your browser is too old to play CodeCombat. Sorry!
br
span(data-i18n="home.old_browser_suffix") You can try anyway, but it probably won't work.
nav.navbar.navbar-default
.container
.row
.col-md-3.col-sm-4
.navbar-header
button.navbar-toggle.collapsed(data-toggle='collapse', data-target='#navbar-collapse' aria-expanded='false')
span.sr-only Toggle navigation
span.icon-bar
span.icon-bar
span.icon-bar
a.navbar-brand(href="/")
img#logo-img(src="/images/pages/base/logo.png")
span.glyphicon.glyphicon-home
.col-md-9.col-sm-8
#navbar-collapse.collapse.navbar-collapse
ul.nav.navbar-nav.pull-left
li
a(href="/about") About
li
a(href="/courses") Courses
li
a(href="/courses/teachers") Teachers
li
a(href="https://discourse.codecombat.com/") Forum
if me.isAnonymous()
li
a#create-account-link.signup-button Create Account
li
a#login-link.login-button Login
else
li.dropdown
a.dropdown-toggle(href="#", data-toggle="dropdown" role="button" aroa-haspopup="true" aria-expanded="false")
span.spr My Account
ul.dropdown-menu
li.user-dropdown-header.text-center
span.user-level= me.level()
a(href="/user/#{me.getSlugOrID()}")
img.img-circle(src=me.getPhotoURL())
h5=me.displayName()
li
a(href="/user/#{me.getSlugOrID()}" data-i18n="nav.profile")
li
a(href="/account/settings", data-i18n="play.settings")
li
a(href="/account/payments", data-i18n="account.payments")
li
a(href="/account/subscription", data-i18n="account.subscription")
li
a(href="/account/prepaid", data-i18n="account.prepaid_codes") Prepaid Codes
li
a#logout-button(data-i18n="login.log_out")
li
#language-dropdown-wrapper
select.language-dropdown.form-control
.container-fluid#jumbotron-container-fluid(class=view.jumbotron === 'student' ? 'alt-image' : '')
.container
.row
.col-lg-7.col-md-8
h1 The most engaging game for learning programming.
.col-lg-3.col-lg-offset-2.col-md-4
.well.text-center.hidden-md.hidden-lg
.row
.col-xs-8
h6 Classroom Edition:
.col-xs-4
h6 Learn to code:
.row
.col-xs-4
button#teacher-btn.btn.btn-primary.btn-lg.btn-block Teacher
.col-xs-4
a.btn.btn-forest.btn-lg.btn-block(href="/courses") Student
.col-xs-4
a.btn.btn-gold.btn-lg.btn-block(href=view.playURL) Play Now
.well.text-center.hidden-xs.hidden-sm
h6#classroom-edition-header Classroom Edition:
div
button#teacher-btn.btn.btn-primary.btn-lg.btn-block I'm a Teacher
div
a.btn.btn-forest.btn-lg.btn-block(href="/courses") I'm a Student
h6#learn-to-code-header Learn to code:
a.btn.btn-gold.btn-lg.btn-block(href=view.playURL) Play Now
.row#learn-more-row
.col-xs-12.text-center
a#learn-more-link
h6 Learn more
h2
span.glyphicon.glyphicon-chevron-down
.container#classroom-in-box-container
#classroom-in-box-row.row
.col-sm-6
h2.text-navy A classroom in-a-box for teaching computer science.
.col-sm-6
p CodeCombat is a platform for students to learn computer science while playing through a real game.
p Our courses have been specifically playtested to excel in a classroom setting, even by teachers with little to no prior programming experience.
#feature-spread-row.row.text-center
h3 Designed with teachers in mind
.col-sm-4
img.img-circle(src="/images/pages/home/F1_typedcode.png")
h4
| Real, typed code
br
| from the first level
p.small Getting students to typed code as quickly as possible is critical to learning programming syntax and proper structure.
.col-sm-4
img.img-circle(src="/images/pages/home/F2_teacherguides.png")
h4
| Educator resources
br
| and course guides
p.small Teaching computer science does not require a costly degree, because we provide tools to support educators of all backgrounds.
.col-sm-4
img.img-circle(src="/images/pages/home/F3_accessible.png")
h4
| Accessible to
br
| everyone
p.small Democratizing the process of learning coding is at the core of our philosophy. Everyone should be able to learn to code.
.testimonials-rows
.testimonials-filler-left
.testimonials-filler-right
.row
.col-lg-offset-2.col-lg-7.col-sm-8
blockquote
h3 I think they actually forgot that they were actually learning something.
.col-lg-2.col-sm-3.text-center
img.img-circle(src="/images/pages/home/timmaki.png")
h6 Tim Maki
.small Director of Technology, Tilton School
.row
.col-lg-7.col-sm-8.col-sm-push-4.col-lg-push-3
blockquote
h3 Coding is something I've always wanted to do, and I never thought I would be able to learn it in school.
.col-lg-2.col-sm-3.col-lg-offset-1.text-center.col-sm-pull-8.col-lg-pull-7
img.img-circle(src="/images/pages/home/dylan.png")
h6 Dylan
.small 3rd Grader
h3.text-center Why is learning through games important?
#benefit-row-1.row
#benefit-graphic-1.col-sm-6.col-sm-offset-1.col-sm-push-6
h2 Games reward the productive struggle.
img(src="/images/pages/home/G1_reward.png")
#benefit-graphic-1-filler
.col-sm-5.col-sm-pull-6
p
| Gaming is a medium that encourages interaction, discovery, and trial-and-error.
| A good game challenges the player to master skills over time,
| which is the same critical process students go through as they learn.
p
| Games excel at rewarding “
a(href="http://blog.mindresearch.org/blog/game-based-learning-infographic-strong-math-practices" target="_blank") productive struggle
span.spr ” - the kind of struggle that results in learning thats engaging and
a(href="http://www.gamesandlearning.org/2014/06/09/teachers-on-using-games-in-class/" target="_blank") motivating
| , not tedious.
#benefit-row-2.row
#benefit-graphic-2.col-sm-6
h2 Studies suggest gaming is good for childrens brains. (its true!)
img(src="/images/pages/home/G2_brains.png")
#benefit-graphic-2-filler
.col-sm-5.col-sm-offset-1
p
span.spr When game-based learning systems are
a(href="http://schoolsweek.co.uk/gaming-is-good-for-childrens-brains-study-suggests/" target="_blank") compared
span.spl.spr against conventional assessment methods, the difference is clear: games are better at helping students retain knowledge, concentrate and
a(href="http://dev.k-12techdecisions.com/article/game_based_learning_is_where_vygotsky_meets_dweck/P3" target="_blank") perform at a higher level of achievement
| .
p
| Games also provide real-time feedback that allows students to adjust their solution path and understand concepts more holistically, instead of being limited to just “correct” or “incorrect” answers.
#benefit-row-3.row
#benefit-graphic-3.col-sm-6.col-sm-offset-1.col-sm-push-6
h2 A real game, played with real coding.
img(src="/images/pages/home/G3_game.png")
#benefit-graphic-3-filler
.col-sm-5.col-sm-pull-6
p
| A great game is more than just badges and achievements - its about a players journey, well-designed puzzles, and the ability to tackle challenges with agency and confidence.
p
| CodeCombat is a game that gives players that agency and confidence with our robust typed code engine, which helps beginner and advanced students alike write proper, valid code.
.request-demo-row.text-center
h3 Curious? Request a demo and we'll show you the ropes
h4 Or create a class and see it for yourself!
div
a.btn.btn-primary.btn-lg(href="/teachers/freetrial") Request a Demo
a.btn.btn-primary-alt.btn-lg(href="/courses/teachers") Create a Class
div
if me.isAnonymous()
span.spr Already have an account?
a.login-button Login
else
span.spr You are currently logged in as #{me.broadName()}.
a(href="/courses/teachers") View my classes
span.spr.spl or
a#logout-button logout
h3.text-center Computer science courses for all ages
h4.text-center
span#school-level-label Show me lesson time estimates for:
select#school-level-dropdown.form-control.text-navy
option(value='elementary') Elementary School
option(value='middle', selected=true) Middle School
option(value='high') High School
h5.text-center#total-hours-header
span.spr Total curriculum hours:
span#semester-duration
#courses-row.row
- var conceptsSeen = {};
- var lastScreenshot = "";
for course, courseIndex in view.courses.models
.col-md-3.col-sm-4
.media.course-details(data-course-slug=course.get('slug'))
if courseIndex === 0
.free-course
h6 Free for all students
.media-body(title=course.get('description'))
h6.course-name= course.get('name') + ':'
p.small
- var total = 0;
each concept in course.get('concepts')
- if (conceptsSeen[concept]) continue;
- conceptsSeen[concept] = true;
if total === 3
- total += 1;
span ...
- continue;
else if total > 3
- continue;
else if total > 0
span.spr ,
- total += 1;
span(data-i18n="concepts." + concept)
img.media-object(src="/images/pages/home/course"+(courseIndex+1)+".png")
- lastScreenshot = course.get('screenshot');
h6.course-duration
span.spr Lesson time:
span.course-hours= course.get('duration') || 0
span.spl.unit(data-i18n="units.hours")
for upcomingCourse in ['Computer Science 6', 'Computer Science 7', 'Computer Science 8']
.col-md-3.col-sm-4
.media.disabled
.media-body
h6.course-name= upcomingCourse + ':'
p.small Coming soon!
img.media-object(src="/images/pages/home/inprogress.png")
.clearfix
.text-center
h4
img(src="/images/pages/home/course_languages.png")
div Courses are available in JavaScript, Python, and Java (coming soon!)
.testimonials-rows
.testimonials-filler-left
.testimonials-filler-right
.row
.col-lg-offset-2.col-lg-7.col-sm-8
blockquote
h3 Boasts riddles that are complex enough to fascinate gamers and coders alike.
.col-lg-2.col-sm-3.text-center
img.img-circle(src="/images/pages/home/opensource.png")
h6 Open Source
.small opensource.com
.row
.col-lg-7.col-sm-8.col-sm-push-4.col-lg-push-3
blockquote
h3 A winning combination of RPG gameplay and programming homework that pulls off making kid-friendly education legitimately enjoyable.
.col-lg-2.col-sm-3.col-lg-offset-1.text-center.col-sm-pull-8.col-lg-pull-7
img.img-circle(src="/images/pages/home/pcmag.png")
h6 PC Mag
.small pcmag.com
.request-demo-row.text-center
h3 Everything you need to run a computer science class in your school today, no CS background required.
p
a.btn.btn-primary.btn-lg(href="/teachers/freetrial") Request a Demo
a.btn.btn-primary-alt.btn-lg(href="/courses/teachers") Create a Class
.text-center
img(src="/images/pages/home/character_lineup.png")
.container-fluid
#footer.small
.container .container
.row .row
.col-sm-3 .col-lg-7.col-md-8
ul.list-unstyled h1 The most engaging game for learning programming.
li
strong CodeCombat
li
a(href="/about") About
li
a(href="/Careers") Jobs
li
a(href="http://blog.codecombat.com/", data-i18n="nav.blog")
li
a(href="/legal") Legal
.col-sm-3 .col-lg-3.col-lg-offset-2.col-md-4
ul.list-unstyled .well.text-center.hidden-md.hidden-lg
li .row
strong Schools .col-xs-8
li h6 Classroom Edition:
a(href="/courses/teachers") Teachers .col-xs-4
li h6 Learn to code:
a(href="https://sites.google.com/a/codecombat.com/teacher-guides/") Educator Wiki .row
li .col-xs-4
a(href="/teachers/quote") Request a Quote button#teacher-btn.btn.btn-primary.btn-lg.btn-block Teacher
.col-xs-4
a.btn.btn-forest.btn-lg.btn-block(href="/courses") Student
.col-xs-4
a.btn.btn-gold.btn-lg.btn-block(href=view.playURL) Play Now
.col-sm-3 .well.text-center.hidden-xs.hidden-sm
ul.list-unstyled h6#classroom-edition-header Classroom Edition:
li div
strong Get Involved button#teacher-btn.btn.btn-primary.btn-lg.btn-block I'm a Teacher
li div
a(href='/community', data-i18n="nav.community") a.btn.btn-forest.btn-lg.btn-block(href="/courses") I'm a Student
li
a(href="/contribute") Contribute h6#learn-to-code-header Learn to code:
li a.btn.btn-gold.btn-lg.btn-block(href=view.playURL) Play Now
a(href=view.forumLink(), data-i18n="nav.forum") .row#learn-more-row
li .col-xs-12.text-center
a(href="/play/ladder") Multiplayer a#learn-more-link
li h6 Learn more
a(href="https://github.com/codecombat/codecombat") Open source (GitHub) h2
.col-sm-3 span.glyphicon.glyphicon-chevron-down
ul.list-unstyled
li
strong Support .container#classroom-in-box-container
li #classroom-in-box-row.row
a(href="https://discourse.codecombat.com/t/faq-check-before-posting/1027") FAQs .col-sm-6
li h2.text-navy A classroom in-a-box for teaching computer science.
a(tabindex=-1, data-toggle="coco-modal", data-target="core/ContactModal", data-i18n="nav.contact") .col-sm-6
li p CodeCombat is a platform for students to learn computer science while playing through a real game.
a(href="https://www.facebook.com/codecombat", data-i18n="nav.facebook") p Our courses have been specifically playtested to excel in a classroom setting, even by teachers with little to no prior programming experience.
li
a(href="https://twitter.com/codecombat", data-i18n="nav.twitter") #feature-spread-row.row.text-center
h3 Designed with teachers in mind
.col-sm-4
img.img-circle(src="/images/pages/home/F1_typedcode.png")
h4
| Real, typed code
br
| from the first level
p.small Getting students to typed code as quickly as possible is critical to learning programming syntax and proper structure.
.col-sm-4
img.img-circle(src="/images/pages/home/F2_teacherguides.png")
h4
| Educator resources
br
| and course guides
p.small Teaching computer science does not require a costly degree, because we provide tools to support educators of all backgrounds.
.col-sm-4
img.img-circle(src="/images/pages/home/F3_accessible.png")
h4
| Accessible to
br
| everyone
p.small Democratizing the process of learning coding is at the core of our philosophy. Everyone should be able to learn to code.
.testimonials-rows
.testimonials-filler-left
.testimonials-filler-right
.row
.col-lg-offset-2.col-lg-7.col-sm-8
blockquote
h3 I think they actually forgot that they were actually learning something.
.col-lg-2.col-sm-3.text-center
img.img-circle(src="/images/pages/home/timmaki.png")
h6 Tim Maki
.small Director of Technology, Tilton School
.row
.col-lg-7.col-sm-8.col-sm-push-4.col-lg-push-3
blockquote
h3 Coding is something I've always wanted to do, and I never thought I would be able to learn it in school.
.col-lg-2.col-sm-3.col-lg-offset-1.text-center.col-sm-pull-8.col-lg-pull-7
img.img-circle(src="/images/pages/home/dylan.png")
h6 Dylan
.small 3rd Grader
h3.text-center Why is learning through games important?
#benefit-row-1.row
#benefit-graphic-1.col-sm-6.col-sm-offset-1.col-sm-push-6
h2 Games reward the productive struggle.
img(src="/images/pages/home/G1_reward.png")
#benefit-graphic-1-filler
.col-sm-5.col-sm-pull-6
p
| Gaming is a medium that encourages interaction, discovery, and trial-and-error.
| A good game challenges the player to master skills over time,
| which is the same critical process students go through as they learn.
p
| Games excel at rewarding “
a(href="http://blog.mindresearch.org/blog/game-based-learning-infographic-strong-math-practices" target="_blank") productive struggle
span.spr ” - the kind of struggle that results in learning thats engaging and
a(href="http://www.gamesandlearning.org/2014/06/09/teachers-on-using-games-in-class/" target="_blank") motivating
| , not tedious.
#benefit-row-2.row
#benefit-graphic-2.col-sm-6
h2 Studies suggest gaming is good for childrens brains. (its true!)
img(src="/images/pages/home/G2_brains.png")
#benefit-graphic-2-filler
.col-sm-5.col-sm-offset-1
p
span.spr When game-based learning systems are
a(href="http://schoolsweek.co.uk/gaming-is-good-for-childrens-brains-study-suggests/" target="_blank") compared
span.spl.spr against conventional assessment methods, the difference is clear: games are better at helping students retain knowledge, concentrate and
a(href="http://dev.k-12techdecisions.com/article/game_based_learning_is_where_vygotsky_meets_dweck/P3" target="_blank") perform at a higher level of achievement
| .
p
| Games also provide real-time feedback that allows students to adjust their solution path and understand concepts more holistically, instead of being limited to just “correct” or “incorrect” answers.
#benefit-row-3.row
#benefit-graphic-3.col-sm-6.col-sm-offset-1.col-sm-push-6
h2 A real game, played with real coding.
img(src="/images/pages/home/G3_game.png")
#benefit-graphic-3-filler
.col-sm-5.col-sm-pull-6
p
| A great game is more than just badges and achievements - its about a players journey, well-designed puzzles, and the ability to tackle challenges with agency and confidence.
p
| CodeCombat is a game that gives players that agency and confidence with our robust typed code engine, which helps beginner and advanced students alike write proper, valid code.
.request-demo-row.text-center
h3 Curious? Request a demo and we'll show you the ropes
h4 Or create a class and see it for yourself!
div
a.btn.btn-primary.btn-lg(href="/teachers/freetrial") Request a Demo
a.btn.btn-primary-alt.btn-lg(href="/courses/teachers") Create a Class
div
if me.isAnonymous()
span.spr Already have an account?
a.login-button Login
else
span.spr You are currently logged in as #{me.broadName()}.
a(href="/courses/teachers") View my classes
span.spr.spl or
a#logout-button logout
h3.text-center Computer science courses for all ages
h4.text-center
span#school-level-label Show me lesson time estimates for:
select#school-level-dropdown.form-control.text-navy
option(value='elementary') Elementary School
option(value='middle', selected=true) Middle School
option(value='high') High School
h5.text-center#total-hours-header
span.spr Total curriculum hours:
span#semester-duration
#courses-row.row
- var conceptsSeen = {};
- var lastScreenshot = "";
for course, courseIndex in view.courses.models
.col-md-3.col-sm-4
.media.course-details(data-course-slug=course.get('slug'))
if courseIndex === 0
.free-course
h6 Free for all students
.media-body(title=course.get('description'))
h6.course-name= course.get('name') + ':'
p.small
- var total = 0;
each concept in course.get('concepts')
- if (conceptsSeen[concept]) continue;
- conceptsSeen[concept] = true;
if total === 3
- total += 1;
span ...
- continue;
else if total > 3
- continue;
else if total > 0
span.spr ,
- total += 1;
span(data-i18n="concepts." + concept)
img.media-object(src="/images/pages/home/course"+(courseIndex+1)+".png")
- lastScreenshot = course.get('screenshot');
h6.course-duration
span.spr Lesson time:
span.course-hours= course.get('duration') || 0
span.spl.unit(data-i18n="units.hours")
for upcomingCourse in ['Computer Science 6', 'Computer Science 7', 'Computer Science 8']
.col-md-3.col-sm-4
.media.disabled
.media-body
h6.course-name= upcomingCourse + ':'
p.small Coming soon!
img.media-object(src="/images/pages/home/inprogress.png")
.clearfix
.text-center
h4
img(src="/images/pages/home/course_languages.png")
div Courses are available in JavaScript, Python, and Java (coming soon!)
.testimonials-rows
.testimonials-filler-left
.testimonials-filler-right
.row
.col-lg-offset-2.col-lg-7.col-sm-8
blockquote
h3 Boasts riddles that are complex enough to fascinate gamers and coders alike.
.col-lg-2.col-sm-3.text-center
img.img-circle(src="/images/pages/home/opensource.png")
h6 Open Source
.small opensource.com
.row
.col-lg-7.col-sm-8.col-sm-push-4.col-lg-push-3
blockquote
h3 A winning combination of RPG gameplay and programming homework that pulls off making kid-friendly education legitimately enjoyable.
.col-lg-2.col-sm-3.col-lg-offset-1.text-center.col-sm-pull-8.col-lg-pull-7
img.img-circle(src="/images/pages/home/pcmag.png")
h6 PC Mag
.small pcmag.com
.request-demo-row.text-center
h3 Everything you need to run a computer science class in your school today, no CS background required.
p
a.btn.btn-primary.btn-lg(href="/teachers/freetrial") Request a Demo
a.btn.btn-primary-alt.btn-lg(href="/courses/teachers") Create a Class
#final-footer.small.text-center
| Copyright ©2016 CodeCombat. All Rights Reserved.
br.hidden-lg.hidden-md
img(src="/images/pages/base/logo.png" alt="CodeCombat")
br.hidden-lg.hidden-md
span.spr Need help? Email
a(href="mailto:team@codecombat.com") team@codecombat.com
span.spl and we'll get in touch!

View file

@ -1,155 +1,152 @@
extends /templates/base extends /templates/base-flat
block content block content
form.form(class=view.trialRequest.isNew() ? '' : 'hide') .container
h1.text-center(data-i18n="teachers_quote.title") form.form(class=view.trialRequest.isNew() ? '' : 'hide')
p.text-center(data-i18n="teachers_quote.subtitle") h1.text-center(data-i18n="teachers_quote.title")
h2.text-center(data-i18n="teachers_quote.subtitle")
#form-teacher-info.section
.row
.col-sm-offset-2.col-sm-4
.form-group
label.control-label(data-i18n="general.name")
- var name = me.get('name') || '';
input.form-control(name="name" value=name, disabled=!!name)
.col-sm-4
#email-form-group.form-group
label.control-label(data-i18n="general.email")
- var email = me.get('email') || '';
input.form-control(name="email" type="email", value=email, disabled=!!email)
.row
.col-sm-offset-2.col-sm-4
.form-group
label.control-label
span(data-i18n="teachers_quote.phone_number")
span.spl.text-muted(data-i18n="signup.optional")
.help-block.small
em.text-info(data-i18n="teachers_quote.phone_number_help")
input.form-control(name="phoneNumber")
.col-sm-4
.form-group
label.control-label(data-i18n="teachers_quote.role_label")
.help-block.small
em.text-info(data-i18n="teachers_quote.role_help")
select.form-control(name="role")
option
option(data-i18n="courses.teacher", value="Teacher")
option(data-i18n="teachers_quote.tech_coordinator", value="Technology coordinator")
option(data-i18n="teachers_quote.advisor", value="Advisor")
option(data-i18n="teachers_quote.principal", value="Principal")
option(data-i18n="teachers_quote.superintendent", value="Superintendent")
option(data-i18n="teachers_quote.parent", value="Parent")
#form-school-info.section
.row
.col-sm-offset-2.col-sm-4
.form-group
label.control-label(data-i18n="teachers_quote.organization_label")
input.form-control(name="organization")
.col-sm-4
.form-group
label.control-label(data-i18n="teachers_quote.city")
input.form-control(name="city")
.row
.col-sm-offset-2.col-sm-4
.form-group
label.control-label(data-i18n="teachers_quote.state")
input.form-control(name="state")
.col-sm-4
.form-group
label.control-labellabel.control-label(data-i18n="teachers_quote.country")
input.form-control(name="country")
#form-students-info.section
.row
.col-sm-offset-2.col-sm-5
.form-group
label.control-label(data-i18n="courses.number_students")
.help-block.small
em.text-info(data-i18n="teachers_quote.num_students_help")
select.form-control(name="numStudents")
option
option 1-10
option 11-50
option 51-100
option 101-200
option 201-500
option 501-1000
option 1000+
.row
.col-sm-offset-2.col-sm-4
.form-group .form-group
label.control-label(data-i18n="general.name")
- var name = me.get('name') || '';
input.form-control(name="name" value=name, disabled=!!name)
.col-sm-4 .row
#email-form-group.form-group .col-sm-offset-2.col-sm-4
label.control-label(data-i18n="general.email") label.control-label(data-i18n="teachers_quote.education_level_label")
- var email = me.get('email') || ''; .help-block.small
input.form-control(name="email" type="email", value=email, disabled=!!email) em.text-info(data-i18n="teachers_quote.education_level_help")
.row
.col-sm-offset-2.col-sm-2
label.control-label.checkbox
input(type="checkbox" name="educationLevel" value="Elementary")
span(data-i18n="teachers_quote.elementary_school")
.col-sm-2
label.control-label.checkbox
input(type="checkbox" name="educationLevel" value="High")
span(data-i18n="teachers_quote.high_school")
.col-sm-2
label.control-label.checkbox
input(type="checkbox" name="educationLevel" value="Middle")
span(data-i18n="teachers_quote.middle_school")
.col-sm-2
label.control-label.checkbox
input(type="checkbox" name="educationLevel" value="College+")
span(data-i18n="teachers_quote.college_plus")
.row .row
.col-sm-offset-2.col-sm-4 .col-sm-offset-2.col-sm-6
.form-group // Other field uses custom logic, so no name field is included in either input.
label.control-label // That way the forms library ignores it.
span(data-i18n="teachers_quote.phone_number") .form-group
span.spl.text-muted(data-i18n="signup.optional") label.control-label.checkbox
.help-block input#other-education-level-checkbox(type="checkbox")
em.text-info(data-i18n="teachers_quote.phone_number_help") span(data-i18n="nav.other")
input.form-control(name="phoneNumber") |
span(data-i18n="teachers_quote.please_explain")
input#other-education-level-input.form-control
.col-sm-4 #anything-else-row.section
.form-group .row
label.control-label(data-i18n="teachers_quote.role_label") .col-sm-offset-2.col-sm-8
.help-block
em.text-info(data-i18n="teachers_quote.role_help")
select.form-control(name="role")
option
option(data-i18n="courses.teacher", value="Teacher")
option(data-i18n="teachers_quote.tech_coordinator", value="Technology coordinator")
option(data-i18n="teachers_quote.advisor", value="Advisor")
option(data-i18n="teachers_quote.principal", value="Principal")
option(data-i18n="teachers_quote.superintendent", value="Superintendent")
option(data-i18n="teachers_quote.parent", value="Parent")
.row
.col-sm-offset-2.col-sm-8
hr
.row
.col-sm-offset-2.col-sm-4
.form-group
label.control-label(data-i18n="teachers_quote.organization_label")
input.form-control(name="organization")
.col-sm-4
.form-group
label.control-label(data-i18n="teachers_quote.city")
input.form-control(name="city")
.row
.col-sm-offset-2.col-sm-4
.form-group
label.control-label(data-i18n="teachers_quote.state")
input.form-control(name="state")
.col-sm-4
.form-group
label.control-labellabel.control-label(data-i18n="teachers_quote.country")
input.form-control(name="country")
.row
.col-sm-offset-2.col-sm-8
hr
.row
.col-sm-offset-2.col-sm-5
.form-group
label.control-label(data-i18n="courses.number_students")
.help-block
em.text-info(data-i18n="teachers_quote.num_students_help")
select.form-control(name="numStudents")
option
option 1-10
option 11-50
option 51-100
option 101-200
option 201-500
option 501-1000
option 1000+
.form-group
.row
.col-sm-offset-2.col-sm-4
label.control-label(data-i18n="teachers_quote.education_level_label")
.help-block
em.text-info(data-i18n="teachers_quote.education_level_help")
.row
.col-sm-offset-2.col-sm-2
label.control-label.checkbox
input(type="checkbox" name="educationLevel" value="Elementary")
span(data-i18n="teachers_quote.elementary_school")
.col-sm-2
label.control-label.checkbox
input(type="checkbox" name="educationLevel" value="High")
span(data-i18n="teachers_quote.high_school")
.col-sm-6
// Other field uses custom logic, so no name field is included in either input.
// That way the forms library ignores it.
.checkbox-inline
label.control-label label.control-label
input#other-education-level-checkbox(type="checkbox") span(data-i18n="teachers_quote.anything_else")
span(data-i18n="nav.other") span.spl.text-muted(data-i18n="signup.optional")
br
span(data-i18n="teachers_quote.please_explain")
input#other-education-level-input.form-control
.row textarea.form-control(rows=8, name="notes")
.col-sm-offset-2.col-sm-2
label.control-label.checkbox
input(type="checkbox" name="educationLevel" value="Middle")
span(data-i18n="teachers_quote.middle_school")
.col-sm-2
label.control-label.checkbox
input(type="checkbox" name="educationLevel" value="College+")
span(data-i18n="teachers_quote.college_plus")
#anything-else-row.row #buttons-row.row.text-center
.col-sm-offset-2.col-sm-8 input#submit-request-btn.btn.btn-lg.btn-primary(type="submit" data-i18n="[value]common.send")
label.control-label
span(data-i18n="teachers_quote.anything_else")
span.spl.text-muted(data-i18n="signup.optional")
textarea.form-control(rows=8, name="notes")
#buttons-row.row.text-center
input#submit-request-btn.btn.btn-primary(type="submit" data-i18n="[value]common.send")
#form-submit-success.text-center(class=view.trialRequest.isNew() ? 'hide' : '') #form-submit-success.text-center(class=view.trialRequest.isNew() ? 'hide' : '')
h1.text-center(data-i18n="teachers_quote.thanks_header") h1.text-center(data-i18n="teachers_quote.thanks_header")
p.text-center
span.spr(data-i18n="teachers_quote.thanks_p")
a.spl(href="mailto:team@codecombat.com") team@codecombat.com
if me.isAnonymous()
p.text-center(data-i18n="teachers_quote.thanks_anon")
p.text-center p.text-center
button#login-btn.btn.btn-info(data-i18n="login.log_in") span.spr(data-i18n="teachers_quote.thanks_p")
button#signup-btn.btn.btn-info(data-i18n="login.sign_up") a.spl(href="mailto:team@codecombat.com") team@codecombat.com
else
p.text-center(data-i18n="teachers_quote.thanks_logged_in") if me.isAnonymous()
p.text-center(data-i18n="teachers_quote.thanks_anon")
p.text-center
button#login-btn.btn.btn-info(data-i18n="login.log_in")
button#signup-btn.btn.btn-info(data-i18n="login.sign_up")
else
p.text-center(data-i18n="teachers_quote.thanks_logged_in")

View file

@ -6,3 +6,85 @@ module.exports = class AboutView extends RootView
template: template template: template
logoutRedirectURL: false logoutRedirectURL: false
events:
'click #mission-link': 'onClickMissionLink'
'click #team-link': 'onClickTeamLink'
'click #community-link': 'onClickCommunityLink'
'click #story-link': 'onClickStoryLink'
'click #jobs-link': 'onClickJobsLink'
'click #contact-link': 'onClickContactLink'
'click .screen-thumbnail': 'onClickScreenThumbnail'
'click #carousel-left': 'onLeftPressed'
'click #carousel-right': 'onRightPressed'
shortcuts:
'right': 'onRightPressed'
'left': 'onLeftPressed'
'esc': 'onEscapePressed'
afterRender: ->
super(arguments...)
@$('#fixed-nav').affix({
offset:
top: ->
$('#nav-container').offset().top
})
#TODO: Maybe cache top value between page resizes to save CPU
$('body').scrollspy(
target: '#nav-container'
offset: 150
)
@$('#screenshot-lightbox').modal()
@$('#screenshot-carousel').carousel({
interval: 0
keyboard: false
})
onClickMissionLink: (event) ->
event.preventDefault()
@scrollToLink('#mission')
onClickTeamLink: (event) ->
event.preventDefault()
@scrollToLink('#team')
onClickCommunityLink: (event) ->
event.preventDefault()
@scrollToLink('#community')
onClickStoryLink: (event) ->
event.preventDefault()
@scrollToLink('#story')
onClickJobsLink: (event) ->
event.preventDefault()
@scrollToLink('#jobs')
onClickContactLink: (event) ->
event.preventDefault()
@scrollToLink('#contact')
onRightPressed: (event) ->
if $('#screenshot-lightbox').data('bs.modal')?.isShown
event.preventDefault()
$('#screenshot-carousel').carousel('next')
onLeftPressed: (event) ->
if $('#screenshot-lightbox').data('bs.modal')?.isShown
event.preventDefault()
$('#screenshot-carousel').carousel('prev')
onEscapePressed: (event) ->
if $('#screenshot-lightbox').data('bs.modal')?.isShown
event.preventDefault()
$('#screenshot-lightbox').modal('hide')
onClickScreenThumbnail: (event) ->
unless $('#screenshot-lightbox').data('bs.modal')?.isShown
event.preventDefault()
# Modal opening happens automatically from bootstrap
$('#screenshot-carousel').carousel($(event.currentTarget).data("index"))

View file

@ -41,16 +41,6 @@ module.exports = class HomeView extends RootView
afterInsert: -> afterInsert: ->
super(arguments...) super(arguments...)
isOldBrowser: ->
if $.browser
majorVersion = $.browser.versionNumber
return true if $.browser.mozilla && majorVersion < 25
return true if $.browser.chrome && majorVersion < 31 # Noticed Gems in the Deep not loading with 30
return true if $.browser.safari && majorVersion < 6 # 6 might have problems with Aether, or maybe just old minors of 6: https://errorception.com/projects/51a79585ee207206390002a2/errors/547a202e1ead63ba4e4ac9fd
else
console.warn 'no more jquery browser version...'
return false
justPlaysCourses: -> justPlaysCourses: ->
# This heuristic could be better, but currently we don't add to me.get('courseInstances') for single-player anonymous intro courses, so they have to beat a level without choosing a hero. # This heuristic could be better, but currently we don't add to me.get('courseInstances') for single-player anonymous intro courses, so they have to beat a level without choosing a hero.
return me.get('stats')?.gamesCompleted and not me.get('heroConfig') return me.get('stats')?.gamesCompleted and not me.get('heroConfig')

View file

@ -75,14 +75,5 @@ module.exports = class NewHomeView extends RootView
onClickTeacherButton: -> onClickTeacherButton: ->
@scrollToLink('.request-demo-row', 600) @scrollToLink('.request-demo-row', 600)
isOldBrowser: ->
if $.browser
majorVersion = $.browser.versionNumber
return true if $.browser.mozilla && majorVersion < 25
return true if $.browser.chrome && majorVersion < 31 # Noticed Gems in the Deep not loading with 30
return true if $.browser.safari && majorVersion < 6 # 6 might have problems with Aether, or maybe just old minors of 6: https://errorception.com/projects/51a79585ee207206390002a2/errors/547a202e1ead63ba4e4ac9fd
else
console.warn 'no more jquery browser version...'
return false

View file

@ -105,6 +105,7 @@ module.exports = class RequestQuoteView extends RootView
.addClass('has-error') .addClass('has-error')
.append($("<div class='help-block error-help-block'>#{userExists} <a id='email-exists-login-link'>#{logIn}</a>")) .append($("<div class='help-block error-help-block'>#{userExists} <a id='email-exists-login-link'>#{logIn}</a>"))
@$('#submit-request-btn').text('Submit').attr('disabled', false) @$('#submit-request-btn').text('Submit').attr('disabled', false)
forms.scrollToFirstError()
onClickEmailExistsLoginLink: -> onClickEmailExistsLoginLink: ->
modal = new AuthModal({ modal = new AuthModal({

View file

@ -14,7 +14,7 @@ module.exports = class AdministerUserModal extends ModalView
constructor: (options, @userHandle) -> constructor: (options, @userHandle) ->
super(options) super(options)
@user = @supermodel.loadModel(new User({_id:@userHandle}), 'user', {cache: false}).model @user = @supermodel.loadModel(new User({_id:@userHandle}), {cache: false}).model
options = {cache: false, url: '/stripe/coupons'} options = {cache: false, url: '/stripe/coupons'}
options.success = (@coupons) => options.success = (@coupons) =>
@couponsResource = @supermodel.addRequestResource('coupon', options) @couponsResource = @supermodel.addRequestResource('coupon', options)

View file

@ -30,7 +30,7 @@ module.exports = class TrialRequestsView extends RootView
-1 -1
else else
1 1
@trialRequests = new CocoCollection([], { url: '/db/trial.request?conditions[sort]=-created&conditions[limit]=500', model: TrialRequest, comparator: sortRequests }) @trialRequests = new CocoCollection([], { url: '/db/trial.request?conditions[sort]=-created&conditions[limit]=1000', model: TrialRequest, comparator: sortRequests })
@supermodel.loadCollection(@trialRequests, 'trial-requests', {cache: false}) @supermodel.loadCollection(@trialRequests, 'trial-requests', {cache: false})
getRenderData: -> getRenderData: ->

View file

@ -60,8 +60,8 @@ module.exports = class ClanDetailsView extends RootView
@listenTo @memberAchievements, 'sync', @onMemberAchievementsSync @listenTo @memberAchievements, 'sync', @onMemberAchievementsSync
@listenTo @memberSessions, 'sync', @onMemberSessionsSync @listenTo @memberSessions, 'sync', @onMemberSessionsSync
@supermodel.loadModel @campaigns, 'campaigns', cache: false @supermodel.loadModel @campaigns, cache: false
@supermodel.loadModel @clan, 'clan', cache: false @supermodel.loadModel @clan, cache: false
@supermodel.loadCollection(@members, 'members', {cache: false}) @supermodel.loadCollection(@members, 'members', {cache: false})
@supermodel.loadCollection(@memberAchievements, 'member_achievements', {cache: false}) @supermodel.loadCollection(@memberAchievements, 'member_achievements', {cache: false})
@ -204,7 +204,7 @@ module.exports = class ClanDetailsView extends RootView
unless @owner? unless @owner?
@owner = new User _id: @clan.get('ownerID') @owner = new User _id: @clan.get('ownerID')
@listenTo @owner, 'sync', => @render?() @listenTo @owner, 'sync', => @render?()
@supermodel.loadModel @owner, 'owner', cache: false @supermodel.loadModel @owner, cache: false
if @clan.get("dashboardType") is "premium" if @clan.get("dashboardType") is "premium"
@supermodel.loadCollection(@memberSessions, 'member_sessions', {cache: false}) @supermodel.loadCollection(@memberSessions, 'member_sessions', {cache: false})
@render?() @render?()

View file

@ -13,7 +13,7 @@ module.exports = class LevelSessionCodeView extends CocoView
@session = options.session @session = options.session
@level = LevelSession.getReferencedModel(@session.get('level'), LevelSession.schema.properties.level) @level = LevelSession.getReferencedModel(@session.get('level'), LevelSession.schema.properties.level)
@level.setProjection ['employerDescription', 'name', 'icon', 'banner', 'slug'] @level.setProjection ['employerDescription', 'name', 'icon', 'banner', 'slug']
@supermodel.loadModel @level, 'level' @supermodel.loadModel @level
getRenderData: -> getRenderData: ->
c = super() c = super()

View file

@ -17,7 +17,7 @@ module.exports = class UserView extends RootView
@user = me @user = me
@onLoaded() @onLoaded()
@user = new User _id: @userID @user = new User _id: @userID
@supermodel.loadModel @user, 'user', cache: false @supermodel.loadModel @user, cache: false
getRenderData: -> getRenderData: ->
context = super() context = super()

View file

@ -172,4 +172,14 @@ module.exports = class RootView extends CocoView
res.success (model, response, options) -> res.success (model, response, options) ->
#console.log 'Saved language:', newLang #console.log 'Saved language:', newLang
isOldBrowser: ->
if $.browser
majorVersion = $.browser.versionNumber
return true if $.browser.mozilla && majorVersion < 25
return true if $.browser.chrome && majorVersion < 31 # Noticed Gems in the Deep not loading with 30
return true if $.browser.safari && majorVersion < 6 # 6 might have problems with Aether, or maybe just old minors of 6: https://errorception.com/projects/51a79585ee207206390002a2/errors/547a202e1ead63ba4e4ac9fd
else
console.warn 'no more jquery browser version...'
return false
logoutRedirectURL: '/' logoutRedirectURL: '/'

View file

@ -31,7 +31,7 @@ module.exports = class CourseDetailsView extends RootView
if @course.loaded if @course.loaded
@onCourseSync() @onCourseSync()
else else
@supermodel.loadModel @course, 'course' @supermodel.loadModel @course
getRenderData: -> getRenderData: ->
context = super() context = super()
@ -67,7 +67,7 @@ module.exports = class CourseDetailsView extends RootView
if @campaign.loaded if @campaign.loaded
@onCampaignSync() @onCampaignSync()
else else
@supermodel.loadModel @campaign, 'campaign' @supermodel.loadModel @campaign
@render() @render()
onCampaignSync: -> onCampaignSync: ->
@ -106,7 +106,7 @@ module.exports = class CourseDetailsView extends RootView
if @courseInstance.loaded if @courseInstance.loaded
@onCourseInstanceSync() @onCourseInstanceSync()
else else
@courseInstance = @supermodel.loadModel(@courseInstance, 'course_instance').model @courseInstance = @supermodel.loadModel(@courseInstance).model
onCourseInstancesSync: -> onCourseInstancesSync: ->
return if @destroyed return if @destroyed
@ -128,14 +128,14 @@ module.exports = class CourseDetailsView extends RootView
# console.log 'onCourseInstanceSync' # console.log 'onCourseInstanceSync'
if @courseInstance.get('classroomID') if @courseInstance.get('classroomID')
@classroom = new Classroom({_id: @courseInstance.get('classroomID')}) @classroom = new Classroom({_id: @courseInstance.get('classroomID')})
@supermodel.loadModel @classroom, 'classroom' @supermodel.loadModel @classroom
@singlePlayerMode = @courseInstance.get('name') is 'Single Player' @singlePlayerMode = @courseInstance.get('name') is 'Single Player'
@teacherMode = @courseInstance.get('ownerID') is me.id and not @singlePlayerMode @teacherMode = @courseInstance.get('ownerID') is me.id and not @singlePlayerMode
@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
@owner = new User({_id: @courseInstance.get('ownerID')}) @owner = new User({_id: @courseInstance.get('ownerID')})
@supermodel.loadModel @owner, 'user' @supermodel.loadModel @owner
@render() @render()
onLevelSessionsSync: -> onLevelSessionsSync: ->
@ -192,7 +192,7 @@ module.exports = class CourseDetailsView extends RootView
if @nextCourseInstance if @nextCourseInstance
nextCourseID = @nextCourseInstance.get('courseID') nextCourseID = @nextCourseInstance.get('courseID')
@nextCourse = @supermodel.getModel(Course, nextCourseID) or new Course _id: nextCourseID @nextCourse = @supermodel.getModel(Course, nextCourseID) or new Course _id: nextCourseID
@nextCourse = @supermodel.loadModel(@nextCourse, 'course').model @nextCourse = @supermodel.loadModel(@nextCourse).model
else if @allCourses?.loaded else if @allCourses?.loaded
@nextCourse = _.find @allCourses.models, (course) => course.id > @course.id @nextCourse = _.find @allCourses.models, (course) => course.id > @course.id
else else

View file

@ -46,7 +46,7 @@ module.exports = class HourOfCodeView extends RootView
if @lastSession if @lastSession
@lastLevel = new Level() @lastLevel = new Level()
levelData = @lastSession.get('level') levelData = @lastSession.get('level')
@supermodel.loadModel(@lastLevel, 'level', { @supermodel.loadModel(@lastLevel, {
url: "/db/level/#{levelData.original}/version/#{levelData.majorVersion}" url: "/db/level/#{levelData.original}/version/#{levelData.majorVersion}"
data: { data: {
project: 'name,slug' project: 'name,slug'

View file

@ -36,7 +36,7 @@ module.exports = class DeltaView extends CocoView
@[modelName] = options[modelName] @[modelName] = options[modelName]
continue unless @[modelName] and options.loadModels continue unless @[modelName] and options.loadModels
if not @[modelName].isLoaded if not @[modelName].isLoaded
@[modelName] = @supermodel.loadModel(@[modelName], 'document').model @[modelName] = @supermodel.loadModel(@[modelName]).model
@buildDeltas() if @supermodel.finished() @buildDeltas() if @supermodel.finished()

View file

@ -27,7 +27,7 @@ module.exports = class PatchModal extends ModalView
@originalSource = @targetModel.clone(false) @originalSource = @targetModel.clone(false)
else else
@originalSource = new @targetModel.constructor({_id:targetID}) @originalSource = new @targetModel.constructor({_id:targetID})
@supermodel.loadModel @originalSource, 'source_document' @supermodel.loadModel @originalSource
applyDelta: -> applyDelta: ->
@headModel = null @headModel = null

View file

@ -22,7 +22,7 @@ module.exports = class AchievementEditView extends RootView
super options super options
@achievement = new Achievement(_id: @achievementID) @achievement = new Achievement(_id: @achievementID)
@achievement.saveBackups = true @achievement.saveBackups = true
@supermodel.loadModel @achievement, 'achievement' @supermodel.loadModel @achievement
@pushChangesToPreview = _.throttle(@pushChangesToPreview, 500) @pushChangesToPreview = _.throttle(@pushChangesToPreview, 500)
onLoaded: -> onLoaded: ->

View file

@ -20,7 +20,7 @@ module.exports = class ArticleEditView extends RootView
super options super options
@article = new Article({_id: @articleID}) @article = new Article({_id: @articleID})
@article.saveBackups = true @article.saveBackups = true
@supermodel.loadModel @article, 'article' @supermodel.loadModel @article
@pushChangesToPreview = _.throttle(@pushChangesToPreview, 500) @pushChangesToPreview = _.throttle(@pushChangesToPreview, 500)
onLoaded: -> onLoaded: ->

View file

@ -32,7 +32,7 @@ module.exports = class CampaignEditorView extends RootView
constructor: (options, @campaignHandle) -> constructor: (options, @campaignHandle) ->
super(options) super(options)
@campaign = new Campaign({_id:@campaignHandle}) @campaign = new Campaign({_id:@campaignHandle})
@supermodel.loadModel(@campaign, 'campaign') @supermodel.loadModel(@campaign)
@listenToOnce @campaign, 'sync', (model, response, jqXHR) -> @listenToOnce @campaign, 'sync', (model, response, jqXHR) ->
@campaign.set '_id', response._id @campaign.set '_id', response._id
@campaign.url = -> '/db/campaign/' + @id @campaign.url = -> '/db/campaign/' + @id
@ -72,7 +72,7 @@ module.exports = class CampaignEditorView extends RootView
thangType = new ThangType() thangType = new ThangType()
thangType.setProjection(thangTypeProject) thangType.setProjection(thangTypeProject)
thangType.setURL("/db/thang.type/#{original}/version") thangType.setURL("/db/thang.type/#{original}/version")
@supermodel.loadModel(thangType, 'thang') @supermodel.loadModel(thangType)
onFundamentalLoaded: -> onFundamentalLoaded: ->
# Load any levels which haven't been denormalized into our campaign. # Load any levels which haven't been denormalized into our campaign.
@ -82,7 +82,7 @@ module.exports = class CampaignEditorView extends RootView
model = new Level({}) model = new Level({})
model.setProjection Campaign.denormalizedLevelProperties model.setProjection Campaign.denormalizedLevelProperties
model.setURL("/db/level/#{level.original}/version") model.setURL("/db/level/#{level.original}/version")
@levels.add @supermodel.loadModel(model, 'level').model @levels.add @supermodel.loadModel(model).model
achievements = new RelatedAchievementsCollection level.original achievements = new RelatedAchievementsCollection level.original
achievements.setProjection achievementProject achievements.setProjection achievementProject
@supermodel.loadCollection achievements, 'achievements' @supermodel.loadCollection achievements, 'achievements'
@ -109,20 +109,20 @@ module.exports = class CampaignEditorView extends RootView
rewardObject.hero = reward rewardObject.hero = reward
thangType = new ThangType({}, {project: thangTypeProject}) thangType = new ThangType({}, {project: thangTypeProject})
thangType.setURL("/db/thang.type/#{reward}/version") thangType.setURL("/db/thang.type/#{reward}/version")
@supermodel.loadModel(thangType, 'thang') @supermodel.loadModel(thangType)
if rewardType is 'levels' if rewardType is 'levels'
rewardObject.level = reward rewardObject.level = reward
if not @levels.findWhere({original: reward}) if not @levels.findWhere({original: reward})
level = new Level({}, {project: Campaign.denormalizedLevelProperties}) level = new Level({}, {project: Campaign.denormalizedLevelProperties})
level.setURL("/db/level/#{reward}/version") level.setURL("/db/level/#{reward}/version")
@supermodel.loadModel(level, 'level') @supermodel.loadModel(level)
if rewardType is 'items' if rewardType is 'items'
rewardObject.item = reward rewardObject.item = reward
thangType = new ThangType({}, {project: thangTypeProject}) thangType = new ThangType({}, {project: thangTypeProject})
thangType.setURL("/db/thang.type/#{reward}/version") thangType.setURL("/db/thang.type/#{reward}/version")
@supermodel.loadModel(thangType, 'thang') @supermodel.loadModel(thangType)
rewards.push rewardObject rewards.push rewardObject
campaignLevel.rewards = rewards campaignLevel.rewards = rewards

View file

@ -71,7 +71,7 @@ module.exports = class ThangComponentsEditView extends CocoView
levelComponent = new LevelComponent(componentRef) levelComponent = new LevelComponent(componentRef)
url = "/db/level.component/#{componentRef.original}/version/#{componentRef.majorVersion}" url = "/db/level.component/#{componentRef.original}/version/#{componentRef.majorVersion}"
levelComponent.setURL(url) levelComponent.setURL(url)
resource = @supermodel.loadModel levelComponent, 'component' resource = @supermodel.loadModel levelComponent
continue unless resource.isLoading continue unless resource.isLoading
@listenToOnce resource, 'loaded', -> @listenToOnce resource, 'loaded', ->
return if @handlingChange return if @handlingChange

View file

@ -30,7 +30,7 @@ module.exports = class SystemsTabView extends CocoView
for system in @buildDefaultSystems() for system in @buildDefaultSystems()
url = "/db/level.system/#{system.original}/version/#{system.majorVersion}" url = "/db/level.system/#{system.original}/version/#{system.majorVersion}"
ls = new LevelSystem().setURL(url) ls = new LevelSystem().setURL(url)
@supermodel.loadModel(ls, 'system') @supermodel.loadModel(ls)
afterRender: -> afterRender: ->
@buildSystemsTreema() @buildSystemsTreema()

View file

@ -30,7 +30,7 @@ module.exports = class VersionsModal extends ModalView
constructor: (options, @ID, @model) -> constructor: (options, @ID, @model) ->
super options super options
@original = new @model(_id: @ID) @original = new @model(_id: @ID)
@original = @supermodel.loadModel(@original, 'document').model @original = @supermodel.loadModel(@original).model
@listenToOnce(@original, 'sync', @onViewSync) @listenToOnce(@original, 'sync', @onViewSync)
onViewSync: -> onViewSync: ->

View file

@ -25,7 +25,7 @@ module.exports = class PollEditView extends RootView
loadPoll: -> loadPoll: ->
@poll = new Poll _id: @pollID @poll = new Poll _id: @pollID
@poll.saveBackups = true @poll.saveBackups = true
@supermodel.loadModel @poll, 'poll' @supermodel.loadModel @poll
loadUserPollsRecord: -> loadUserPollsRecord: ->
url = "/db/user.polls.record/-/user/#{me.id}" url = "/db/user.polls.record/-/user/#{me.id}"
@ -34,7 +34,7 @@ module.exports = class PollEditView extends RootView
return if @destroyed return if @destroyed
@userPollsRecord.url = -> '/db/user.polls.record/' + @id @userPollsRecord.url = -> '/db/user.polls.record/' + @id
@listenToOnce @userPollsRecord, 'sync', onRecordSync @listenToOnce @userPollsRecord, 'sync', onRecordSync
@userPollsRecord = @supermodel.loadModel(@userPollsRecord, 'user_polls_record').model @userPollsRecord = @supermodel.loadModel(@userPollsRecord).model
onRecordSync.call @ if @userPollsRecord.loaded onRecordSync.call @ if @userPollsRecord.loaded
onLoaded: -> onLoaded: ->

View file

@ -13,7 +13,7 @@ module.exports = class ThangTypeColorsTabView extends CocoView
constructor: (@thangType, options) -> constructor: (@thangType, options) ->
super options super options
@supermodel.loadModel @thangType, 'thang' @supermodel.loadModel @thangType
@colorConfig = {hue: 0, saturation: 0.5, lightness: 0.5} @colorConfig = {hue: 0, saturation: 0.5, lightness: 0.5}
@spriteBuilder = new SpriteBuilder(@thangType) if @thangType.get('raw') @spriteBuilder = new SpriteBuilder(@thangType) if @thangType.get('raw')
f = => f = =>

View file

@ -174,7 +174,7 @@ module.exports = class ThangTypeEditView extends RootView
super options super options
@mockThang = $.extend(true, {}, @mockThang) @mockThang = $.extend(true, {}, @mockThang)
@thangType = new ThangType(_id: @thangTypeID) @thangType = new ThangType(_id: @thangTypeID)
@thangType = @supermodel.loadModel(@thangType, 'thang').model @thangType = @supermodel.loadModel(@thangType).model
@thangType.saveBackups = true @thangType.saveBackups = true
@listenToOnce @thangType, 'sync', -> @listenToOnce @thangType, 'sync', ->
@files = @supermodel.loadCollection(new DocumentFiles(@thangType), 'files').model @files = @supermodel.loadCollection(new DocumentFiles(@thangType), 'files').model

View file

@ -19,7 +19,7 @@ module.exports = class I18NEditModelView extends RootView
constructor: (options, @modelHandle) -> constructor: (options, @modelHandle) ->
super(options) super(options)
@model = new @modelClass(_id: @modelHandle) @model = new @modelClass(_id: @modelHandle)
@model = @supermodel.loadModel(@model, 'model').model @model = @supermodel.loadModel(@model).model
@model.saveBackups = true @model.saveBackups = true
@selectedLanguage = me.get('preferredLanguage', true) @selectedLanguage = me.get('preferredLanguage', true)

View file

@ -41,7 +41,7 @@ module.exports = class LadderView extends RootView
constructor: (options, @levelID, @leagueType, @leagueID) -> constructor: (options, @levelID, @leagueType, @leagueID) ->
super(options) super(options)
@level = @supermodel.loadModel(new Level(_id: @levelID), 'level').model @level = @supermodel.loadModel(new Level(_id: @levelID)).model
@sessions = @supermodel.loadCollection(new LevelSessionsCollection(@levelID), 'your_sessions', {cache: false}).model @sessions = @supermodel.loadCollection(new LevelSessionsCollection(@levelID), 'your_sessions', {cache: false}).model
@teams = [] @teams = []
@loadLeague() @loadLeague()
@ -51,8 +51,7 @@ module.exports = class LadderView extends RootView
@leagueID = @leagueType = null unless @leagueType in ['clan', 'course'] @leagueID = @leagueType = null unless @leagueType in ['clan', 'course']
return unless @leagueID return unless @leagueID
modelClass = if @leagueType is 'clan' then Clan else CourseInstance modelClass = if @leagueType is 'clan' then Clan else CourseInstance
resourceString = if @leagueType is 'clan' then 'clans.clan' else 'courses.course' @league = @supermodel.loadModel(new modelClass(_id: @leagueID)).model
@league = @supermodel.loadModel(new modelClass(_id: @leagueID), resourceString).model
if @leagueType is 'course' if @leagueType is 'course'
if @league.loaded if @league.loaded
@onCourseInstanceLoaded @league @onCourseInstanceLoaded @league
@ -62,7 +61,7 @@ module.exports = class LadderView extends RootView
onCourseInstanceLoaded: (courseInstance) -> onCourseInstanceLoaded: (courseInstance) ->
return if @destroyed return if @destroyed
course = new Course({_id: courseInstance.get('courseID')}) course = new Course({_id: courseInstance.get('courseID')})
@course = @supermodel.loadModel(course, 'courses.course').model @course = @supermodel.loadModel(course).model
@listenToOnce @course, 'sync', @render @listenToOnce @course, 'sync', @render
onLoaded: -> onLoaded: ->

View file

@ -13,7 +13,7 @@ module.exports = class ModelModal extends ModalView
super options super options
@models = options.models @models = options.models
for model in @models when not model.loaded for model in @models when not model.loaded
@supermodel.loadModel model, 'source_document' @supermodel.loadModel model
model.fetch cache: false model.fetch cache: false
afterRender: -> afterRender: ->

View file

@ -82,7 +82,7 @@ module.exports = class CampaignView extends RootView
@campaign = new Campaign({_id:@terrain}) @campaign = new Campaign({_id:@terrain})
@campaign.saveBackups = @editorMode @campaign.saveBackups = @editorMode
@campaign = @supermodel.loadModel(@campaign, 'campaign').model @campaign = @supermodel.loadModel(@campaign).model
# Temporary attempt to make sure all earned rewards are accounted for. Figure out a better solution... # Temporary attempt to make sure all earned rewards are accounted for. Figure out a better solution...
@earnedAchievements = new CocoCollection([], {url: '/db/earned_achievement', model:EarnedAchievement, project: ['earnedRewards']}) @earnedAchievements = new CocoCollection([], {url: '/db/earned_achievement', model:EarnedAchievement, project: ['earnedRewards']})
@ -442,11 +442,11 @@ module.exports = class CampaignView extends RootView
preloadLevel: (levelSlug) -> preloadLevel: (levelSlug) ->
levelURL = "/db/level/#{levelSlug}" levelURL = "/db/level/#{levelSlug}"
level = new Level().setURL levelURL level = new Level().setURL levelURL
level = @supermodel.loadModel(level, 'level', null, 0).model level = @supermodel.loadModel(level, null, 0).model
sessionURL = "/db/level/#{levelSlug}/session" sessionURL = "/db/level/#{levelSlug}/session"
@preloadedSession = new LevelSession().setURL sessionURL @preloadedSession = new LevelSession().setURL sessionURL
@listenToOnce @preloadedSession, 'sync', @onSessionPreloaded @listenToOnce @preloadedSession, 'sync', @onSessionPreloaded
@preloadedSession = @supermodel.loadModel(@preloadedSession, 'level_session', {cache: false}).model @preloadedSession = @supermodel.loadModel(@preloadedSession, {cache: false}).model
@preloadedSession.levelSlug = levelSlug @preloadedSession.levelSlug = levelSlug
onSessionPreloaded: (session) -> onSessionPreloaded: (session) ->
@ -604,7 +604,7 @@ module.exports = class CampaignView extends RootView
continue if @supermodel.getModel url continue if @supermodel.getModel url
fullHero = new ThangType() fullHero = new ThangType()
fullHero.setURL url fullHero.setURL url
@supermodel.loadModel fullHero, 'thang' @supermodel.loadModel fullHero
updateVolume: (volume) -> updateVolume: (volume) ->
volume ?= me.get('volume') ? 1.0 volume ?= me.get('volume') ? 1.0
@ -675,7 +675,7 @@ module.exports = class CampaignView extends RootView
else else
console.log 'Poll will be ready in', (22 * 60 * 60 * 1000 - interval) / (60 * 60 * 1000), 'hours.' console.log 'Poll will be ready in', (22 * 60 * 60 * 1000 - interval) / (60 * 60 * 1000), 'hours.'
@listenToOnce @userPollsRecord, 'sync', onRecordSync @listenToOnce @userPollsRecord, 'sync', onRecordSync
@userPollsRecord = @supermodel.loadModel(@userPollsRecord, 'user_polls_record', null, 0).model @userPollsRecord = @supermodel.loadModel(@userPollsRecord, null, 0).model
onRecordSync.call @ if @userPollsRecord.loaded onRecordSync.call @ if @userPollsRecord.loaded
loadPoll: -> loadPoll: ->
@ -693,7 +693,7 @@ module.exports = class CampaignView extends RootView
delete @poll delete @poll
@listenToOnce @poll, 'sync', onPollSync @listenToOnce @poll, 'sync', onPollSync
@listenToOnce @poll, 'error', onPollError @listenToOnce @poll, 'error', onPollError
@poll = @supermodel.loadModel(@poll, 'poll', null, 0).model @poll = @supermodel.loadModel(@poll, null, 0).model
onPollSync.call @ if @poll.loaded onPollSync.call @ if @poll.loaded
activatePoll: -> activatePoll: ->

View file

@ -41,13 +41,13 @@ module.exports = class CourseVictoryModal extends ModalView
@nextLevel = options.nextLevel @nextLevel = options.nextLevel
if (nextLevel = @level.get('nextLevel')) and not @nextLevel if (nextLevel = @level.get('nextLevel')) and not @nextLevel
@nextLevel = new Level().setURL "/db/level/#{nextLevel.original}/version/#{nextLevel.majorVersion}" @nextLevel = new Level().setURL "/db/level/#{nextLevel.original}/version/#{nextLevel.majorVersion}"
@nextLevel = @supermodel.loadModel(@nextLevel, 'level').model @nextLevel = @supermodel.loadModel(@nextLevel).model
@campaign = new Campaign() @campaign = new Campaign()
@course = options.course @course = options.course
if @courseID and not @course if @courseID and not @course
@course = new Course().setURL "/db/course/#{@courseID}" @course = new Course().setURL "/db/course/#{@courseID}"
@course = @supermodel.loadModel(@course, 'course').model @course = @supermodel.loadModel(@course).model
if @course.loading if @course.loading
@listenToOnce @course, 'sync', @onCourseLoaded @listenToOnce @course, 'sync', @onCourseLoaded
else else
@ -65,7 +65,7 @@ module.exports = class CourseVictoryModal extends ModalView
onCourseLoaded: -> onCourseLoaded: ->
@campaign.set('_id', @course.get('campaignID')) @campaign.set('_id', @course.get('campaignID'))
@campaign = @supermodel.loadModel(@campaign, 'campaign').model @campaign = @supermodel.loadModel(@campaign).model
onAchievementsLoaded: -> onAchievementsLoaded: ->
@ -89,7 +89,7 @@ module.exports = class CourseVictoryModal extends ModalView
thang= new ThangType() thang= new ThangType()
thang.url = "/db/thang.type/#{original}/version" thang.url = "/db/thang.type/#{original}/version"
thang.project = project thang.project = project
@supermodel.loadModel(thang, 'thang') @supermodel.loadModel(thang)
newThangTypeCollection.add(thang) newThangTypeCollection.add(thang)
@newEarnedAchievements = [] @newEarnedAchievements = []
@ -108,7 +108,7 @@ module.exports = class CourseVictoryModal extends ModalView
model.sr.markLoaded() model.sr.markLoaded()
if _.all((ea.id for ea in @newEarnedAchievements)) if _.all((ea.id for ea in @newEarnedAchievements))
unless me.loading unless me.loading
@supermodel.loadModel(me, 'user', {cache: false}) @supermodel.loadModel(me, {cache: false})
@newEarnedAchievementsResource.markLoaded() @newEarnedAchievementsResource.markLoaded()
@ -166,5 +166,3 @@ module.exports = class CourseVictoryModal extends ModalView
onDone: -> onDone: ->
link = "/courses/#{@courseID}/#{@courseInstanceID}" link = "/courses/#{@courseID}/#{@courseInstanceID}"
application.router.navigate(link, {trigger: true}) application.router.navigate(link, {trigger: true})

View file

@ -66,10 +66,10 @@ module.exports = class HeroVictoryModal extends ModalView
if @level.get('type', true) is 'course' if @level.get('type', true) is 'course'
if nextLevel = @level.get('nextLevel') if nextLevel = @level.get('nextLevel')
@nextLevel = new Level().setURL "/db/level/#{nextLevel.original}/version/#{nextLevel.majorVersion}" @nextLevel = new Level().setURL "/db/level/#{nextLevel.original}/version/#{nextLevel.majorVersion}"
@nextLevel = @supermodel.loadModel(@nextLevel, 'level').model @nextLevel = @supermodel.loadModel(@nextLevel).model
if @courseID if @courseID
@course = new Course().setURL "/db/course/#{@courseID}" @course = new Course().setURL "/db/course/#{@courseID}"
@course = @supermodel.loadModel(@course, 'course').model @course = @supermodel.loadModel(@course).model
if @level.get('type', true) in ['course', 'course-ladder'] if @level.get('type', true) in ['course', 'course-ladder']
@saveReviewEventually = _.debounce(@saveReviewEventually, 2000) @saveReviewEventually = _.debounce(@saveReviewEventually, 2000)
@loadExistingFeedback() @loadExistingFeedback()
@ -123,7 +123,7 @@ module.exports = class HeroVictoryModal extends ModalView
thangType.url = "/db/thang.type/#{thangTypeOriginal}/version" thangType.url = "/db/thang.type/#{thangTypeOriginal}/version"
#thangType.project = ['original', 'rasterIcon', 'name', 'soundTriggers', 'i18n'] # This is what we need, but the PlayHeroesModal needs more, and so we load more to fill up the supermodel. #thangType.project = ['original', 'rasterIcon', 'name', 'soundTriggers', 'i18n'] # This is what we need, but the PlayHeroesModal needs more, and so we load more to fill up the supermodel.
thangType.project = ['original', 'rasterIcon', 'name', 'slug', 'soundTriggers', 'featureImages', 'gems', 'heroClass', 'description', 'components', 'extendedName', 'unlockLevelName', 'i18n'] thangType.project = ['original', 'rasterIcon', 'name', 'slug', 'soundTriggers', 'featureImages', 'gems', 'heroClass', 'description', 'components', 'extendedName', 'unlockLevelName', 'i18n']
@thangTypes[thangTypeOriginal] = @supermodel.loadModel(thangType, 'thang').model @thangTypes[thangTypeOriginal] = @supermodel.loadModel(thangType).model
@newEarnedAchievements = [] @newEarnedAchievements = []
hadOneCompleted = false hadOneCompleted = false

View file

@ -170,7 +170,7 @@ module.exports = class CastButtonView extends CocoView
url = "/db/level/#{@options.level.get('slug') or @options.level.id}/session" url = "/db/level/#{@options.level.get('slug') or @options.level.id}/session"
url += "?team=#{if me.team is 'humans' then 'ogres' else 'humans'}" url += "?team=#{if me.team is 'humans' then 'ogres' else 'humans'}"
mirrorSession = new LevelSession().setURL url mirrorSession = new LevelSession().setURL url
@mirrorSession = @supermodel.loadModel(mirrorSession, 'level_session', {cache: false}).model @mirrorSession = @supermodel.loadModel(mirrorSession, {cache: false}).model
updateLadderSubmissionViews: -> updateLadderSubmissionViews: ->
@removeSubView subview for key, subview of @subviews when subview instanceof LadderSubmissionView @removeSubView subview for key, subview of @subviews when subview instanceof LadderSubmissionView

View file

@ -21,7 +21,7 @@ module.exports = class LeaderboardModal extends ModalView
@levelSlug = @options.levelSlug @levelSlug = @options.levelSlug
level = new Level({_id: @levelSlug}) level = new Level({_id: @levelSlug})
level.project = ['name', 'i18n', 'scoreType', 'original'] level.project = ['name', 'i18n', 'scoreType', 'original']
@level = @supermodel.loadModel(level, 'level').model @level = @supermodel.loadModel(level).model
getRenderData: (c) -> getRenderData: (c) ->
c = super c c = super c

View file

@ -139,7 +139,7 @@ module.exports = class PlayHeroesModal extends ModalView
return fullHero return fullHero
fullHero = new ThangType() fullHero = new ThangType()
fullHero.setURL url fullHero.setURL url
fullHero = (@supermodel.loadModel fullHero, 'thang').model fullHero = (@supermodel.loadModel fullHero).model
fullHero fullHero
preloadHero: (heroIndex) -> preloadHero: (heroIndex) ->

View file

@ -27,14 +27,14 @@ describe 'SuperModel', ->
it 'starts loading the model if it isn\'t already loading', -> it 'starts loading the model if it isn\'t already loading', ->
s = new SuperModel() s = new SuperModel()
m = new User({_id: '12345'}) m = new User({_id: '12345'})
s.loadModel(m, 'user') s.loadModel(m)
request = jasmine.Ajax.requests.mostRecent() request = jasmine.Ajax.requests.mostRecent()
expect(request).toBeDefined() expect(request).toBeDefined()
it 'also loads collections', -> it 'also loads collections', ->
s = new SuperModel() s = new SuperModel()
c = new ComponentsCollection() c = new ComponentsCollection()
s.loadModel(c, 'collection') s.loadModel(c)
request = jasmine.Ajax.requests.mostRecent() request = jasmine.Ajax.requests.mostRecent()
expect(request).toBeDefined() expect(request).toBeDefined()
@ -44,7 +44,7 @@ describe 'SuperModel', ->
m = new User({_id: '12345'}) m = new User({_id: '12345'})
triggered = false triggered = false
s.once 'loaded-all', -> triggered = true s.once 'loaded-all', -> triggered = true
s.loadModel(m, 'user') s.loadModel(m)
request = jasmine.Ajax.requests.mostRecent() request = jasmine.Ajax.requests.mostRecent()
request.respondWith({status: 200, responseText: '{}'}) request.respondWith({status: 200, responseText: '{}'})
_.defer -> _.defer ->