Merge branch 'master' into production

This commit is contained in:
Matt Lott 2016-08-10 15:08:37 -07:00
commit eb70d90d9c
33 changed files with 324 additions and 134 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 MiB

View file

@ -769,7 +769,7 @@ module.exports = nativeDescription: "Deutsch (Deutschland)", englishDescription:
about: about:
main_title: "Wenn du das Programmieren erlernen willst, musst du (viel) Code schreiben." main_title: "Wenn du das Programmieren erlernen willst, musst du (viel) Code schreiben."
main_description: "Bei CodeCombat ist es unser Job das du das mit einem Lächeln im Gesicht tust." main_description: "Bei CodeCombat ist es unser Job, dass du das mit einem Lächeln im Gesicht tust."
mission_link: "Mission" mission_link: "Mission"
team_link: "Team" team_link: "Team"
story_link: "Geschichte" story_link: "Geschichte"

View file

@ -304,6 +304,7 @@
signup_as_individual: "Sign up as an Individual" signup_as_individual: "Sign up as an Individual"
enter_class_code: "Enter your Class Code" enter_class_code: "Enter your Class Code"
enter_birthdate: "Enter your birthdate:" enter_birthdate: "Enter your birthdate:"
parent_use_birthdate: "Parents, use your own birthdate."
ask_teacher_1: "Ask your teacher for your Class Code." ask_teacher_1: "Ask your teacher for your Class Code."
ask_teacher_2: "Not part of a class? Create an " ask_teacher_2: "Not part of a class? Create an "
ask_teacher_3: "Individual Account" ask_teacher_3: "Individual Account"
@ -475,6 +476,7 @@
victory_experience_gained: "XP Gained" victory_experience_gained: "XP Gained"
victory_gems_gained: "Gems Gained" victory_gems_gained: "Gems Gained"
victory_new_item: "New Item" victory_new_item: "New Item"
victory_new_hero: "New Hero"
victory_viking_code_school: "Holy smokes, that was a hard level you just beat! If you aren't already a software developer, you should be. You just got fast-tracked for acceptance with Viking Code School, where you can take your skills to the next level and become a professional web developer in 14 weeks." victory_viking_code_school: "Holy smokes, that was a hard level you just beat! If you aren't already a software developer, you should be. You just got fast-tracked for acceptance with Viking Code School, where you can take your skills to the next level and become a professional web developer in 14 weeks."
victory_become_a_viking: "Become a Viking" victory_become_a_viking: "Become a Viking"
victory_no_progress_for_teachers: "Progress is not saved for teachers. But, you can add a student account to your classroom for yourself." victory_no_progress_for_teachers: "Progress is not saved for teachers. But, you can add a student account to your classroom for yourself."
@ -571,6 +573,18 @@
tip_good_idea: "The best way to have a good idea is to have a lot of ideas. - Linus Pauling" tip_good_idea: "The best way to have a good idea is to have a lot of ideas. - Linus Pauling"
tip_programming_not_about_computers: "Computer Science is no more about computers than astronomy is about telescopes. - Edsger Dijkstra" tip_programming_not_about_computers: "Computer Science is no more about computers than astronomy is about telescopes. - Edsger Dijkstra"
tip_mulan: "Believe you can, then you will. - Mulan" tip_mulan: "Believe you can, then you will. - Mulan"
play_game_dev_level:
created_by: "Created by {{name}}"
how_to_play_title: "How to play:"
how_to_play_1: "Use the mouse to control the hero!"
how_to_play_2: "Click anywhere on the map to move to that location."
how_to_play_3: "Click on the ogres to attack them."
restart: "Restart Level"
play: "Play Level"
play_more_codecombat: "Play More CodeCombat"
default_student_instructions: "Click to control your hero and win your game!"
back_to_coding: "Back to Coding"
game_menu: game_menu:
inventory_tab: "Inventory" inventory_tab: "Inventory"
@ -804,6 +818,7 @@
elliot_title: "Partnership Manager" elliot_title: "Partnership Manager"
elliot_blurb: "Mindreader" elliot_blurb: "Mindreader"
lisa_title: "Market Development Rep" lisa_title: "Market Development Rep"
sean_title: "Territory Manager"
retrostyle_title: "Illustration" retrostyle_title: "Illustration"
retrostyle_blurb: "RetroStyle Games" retrostyle_blurb: "RetroStyle Games"
jose_title: "Music" jose_title: "Music"

View file

@ -1,4 +1,4 @@
module.exports = nativeDescription: "עברית", englishDescription: "Hebrew", translation: module.exports = nativeDescription: "עברית", englishDescription: "Hebrew", translation:
home: home:
slogan: "גם לשחק וגם ללמוד לתכנת" slogan: "גם לשחק וגם ללמוד לתכנת"
no_ie: "המשחק לא עובד באקפלורר 8 וישן יותר. סליחה!" # Warning that only shows up in IE8 and older no_ie: "המשחק לא עובד באקפלורר 8 וישן יותר. סליחה!" # Warning that only shows up in IE8 and older

View file

@ -132,7 +132,7 @@ module.exports = nativeDescription: "Nederlands (Nederland)", englishDescription
help_suff: "en we nemen contact op!" help_suff: "en we nemen contact op!"
modal: modal:
# cancel: "Cancel" cancel: "Annuleren"
close: "Sluiten" close: "Sluiten"
okay: "Oké" okay: "Oké"
@ -256,13 +256,13 @@ module.exports = nativeDescription: "Nederlands (Nederland)", englishDescription
signup_switch: "Wil je een account maken?" signup_switch: "Wil je een account maken?"
signup: signup:
# create_student_header: "Create Student Account" create_student_header: "Creëer studenten account"
# create_teacher_header: "Create Teacher Account" create_teacher_header: "Creeër leraren account"
# create_individual_header: "Create Individual Account" create_individual_header: "Creeër persoonlijk account"
# create_header: "Create Account" create_header: "Creëer Account"
email_announcements: "Ontvang aankondigingen via e-mail" # {change} email_announcements: "Ontvang aankondigingen via e-mail" # {change}
creating: "Account aanmaken..." creating: "Account aanmaken..."
# create_account: "Create Account" create_account: "Creëer account"
sign_up: "Aanmelden" sign_up: "Aanmelden"
log_in: "inloggen met wachtwoord" log_in: "inloggen met wachtwoord"
required: "Je moet inloggen om daarheen te gaan." required: "Je moet inloggen om daarheen te gaan."
@ -270,7 +270,7 @@ module.exports = nativeDescription: "Nederlands (Nederland)", englishDescription
school_name: "Schoolnaam en stad" school_name: "Schoolnaam en stad"
optional: "optioneel" optional: "optioneel"
school_name_placeholder: "Voorbeeld middelbare school, Amsterdam" school_name_placeholder: "Voorbeeld middelbare school, Amsterdam"
# connect_with: "Connect with:" connect_with: "Verbind met:"
connected_gplus_header: "Je bent ingelogd met Google+!" connected_gplus_header: "Je bent ingelogd met Google+!"
connected_gplus_p: "Maak je inschrijving compleet zodat je kan inloggen met je Google+ account." connected_gplus_p: "Maak je inschrijving compleet zodat je kan inloggen met je Google+ account."
gplus_exists: "Jouw Google+ account is al gekoppeld!" gplus_exists: "Jouw Google+ account is al gekoppeld!"
@ -280,35 +280,35 @@ module.exports = nativeDescription: "Nederlands (Nederland)", englishDescription
hey_students: "Leerlingen, voer hier de klassencode van je docent in." hey_students: "Leerlingen, voer hier de klassencode van je docent in."
birthday: "Verjaardag" birthday: "Verjaardag"
# parent_email_blurb: "We know you can't wait to learn programming — we're excited too! Your parents will receive an email with further instructions on how to create an account for you. Email {{email_link}} if you have any questions." # parent_email_blurb: "We know you can't wait to learn programming — we're excited too! Your parents will receive an email with further instructions on how to create an account for you. Email {{email_link}} if you have any questions."
# classroom_not_found: "No classes exist with this Class Code. Check your spelling or ask your teacher for help." classroom_not_found: "Er zijn geen klassen met deze klassencode. Controleer je spelling of vraag je leraar om hulp."
# checking: "Checking..." checking: "Controleren..."
# account_exists: "This email is already in use:" # {change} account_exists: "Dit emailadres bestaat al:" # {change}
# sign_in: "Sign in" sign_in: "Log in"
# email_good: "Email looks good!" email_good: "Email ziet er goed uit!"
# name_taken: "Username already taken! Try {{suggestedName}}?" name_taken: "Gebruikersnaam bestaat al! Probeer {{suggestedName}}?"
# name_available: "Username available!" name_available: "Gebruikersnaam beschikbaar!"
# name_is_email: "Username may not be an email" name_is_email: "Gebruikersnaam mag geen email zijn"
# choose_type: "Choose your account type:" choose_type: "Kies je account type:"
# teacher_type_1: "Teach programming using CodeCombat!" teacher_type_1: "Leer ze programmeren met gebruik van CodeCombat!"
# teacher_type_2: "Set up your class" teacher_type_2: "Maak je klas"
# teacher_type_3: "Access Course Guides" # teacher_type_3: "Access Course Guides"
# teacher_type_4: "View student progress" teacher_type_4: "Bekijk voortgang studenten"
# signup_as_teacher: "Sign up as a Teacher" signup_as_teacher: "Registreer als een docent"
# student_type_1: "Learn to program while playing an engaging game!" student_type_1: "Leer programmeren terwijl je een uitdagend spel speelt!"
# student_type_2: "Play with your class" student_type_2: "Speel met je klas"
# student_type_3: "Compete in arenas" student_type_3: "Strijd in arena's"
# student_type_4: "Choose your hero!" student_type_4: "Kies je held!"
# student_type_5: "Have your Class Code ready!" student_type_5: "Heb je klassencode bij de hand!"
# signup_as_student: "Sign up as a Student" signup_as_student: "Registreer als een student"
# individuals_or_parents: "Individuals & Parents" individuals_or_parents: "Individueel & Ouders"
# individual_type: "For players learning to code outside of a class. Parents should sign up for an account here." individual_type: "Voor spelers die leren coderen buiten school. Ouders moeten zich hier aanmelden."
# signup_as_individual: "Sign up as an Individual" signup_as_individual: "Registreer als een individu (persoonlijk)"
# enter_class_code: "Enter your Class Code" enter_class_code: "Vul je klassencode in"
# enter_birthdate: "Enter your birthdate:" enter_birthdate: "Vul je geboortedatum in:"
# ask_teacher_1: "Ask your teacher for your Class Code." ask_teacher_1: "Vraag je leraar om een klassencode."
# ask_teacher_2: "Not part of a class? Create an " ask_teacher_2: "Maak je geen deel uit een klas? Maak dan een "
# ask_teacher_3: "Individual Account" ask_teacher_3: "Individuele account"
# ask_teacher_4: " instead." ask_teacher_4: "."
# about_to_join: "You're about to join:" # about_to_join: "You're about to join:"
# enter_parent_email: "Enter your parents email address:" # enter_parent_email: "Enter your parents email address:"
# parent_email_error: "Something went wrong when trying to send the email. Check the email address and try again." # parent_email_error: "Something went wrong when trying to send the email. Check the email address and try again."

View file

@ -16,7 +16,7 @@ module.exports = nativeDescription: "Português do Brasil", englishDescription:
new_home: new_home:
slogan: "O jogo mais envolvente para aprender programação." slogan: "O jogo mais envolvente para aprender programação."
# classroom_edition: "Classroom Edition:" classroom_edition: "Editar sala de aula:"
learn_to_code: "Aprenda a programar:" learn_to_code: "Aprenda a programar:"
teacher: "Professor" teacher: "Professor"
student: "Aluno" student: "Aluno"
@ -25,38 +25,38 @@ module.exports = nativeDescription: "Português do Brasil", englishDescription:
im_a_student: "Eu sou um Aluno" im_a_student: "Eu sou um Aluno"
learn_more: "Aprenda mais" learn_more: "Aprenda mais"
classroom_in_a_box: "Uma sala de aula in-a-box para o ensino de ciência da computação." classroom_in_a_box: "Uma sala de aula in-a-box para o ensino de ciência da computação."
# codecombat_is: "CodeCombat is a platform <strong>for students</strong> to learn computer science while playing through a real game." codecombat_is: "CodeCombat é uma plataforma <strong>para estudantes</strong> aprenderem ciência da computação através de um jogo real."
# our_courses: "Our courses have been specifically playtested to <strong>excel in the classroom</strong>, even by teachers with little to no prior programming experience." our_courses: "Nossos cursos foram pensados especificamente para <strong>o uso em sala de aula</strong>, mesmo para professores com pouco conhecimento prévio em programação."
top_screenshots_hint: "Alunos escrevem seus códigos e veem suas mudanças em tempo real." top_screenshots_hint: "Alunos escrevem seus códigos e veem suas mudanças em tempo real."
designed_with: "Projetado com professores em mente" designed_with: "Projetado com professores em mente"
real_code: "Código escrito, de verdade" real_code: "Código escrito, de verdade"
from_the_first_level: "a partir do primeiro nível" from_the_first_level: "a partir do primeiro nível"
# getting_students: "Getting students to typed code as quickly as possible is critical to learning programming syntax and proper structure." getting_students: "Fazer os estudantes digitarem o código o mais rapido possível é fundamental para aprender a sintaxe de programação e estrurutura apropriada."
educator_resources: "Recursos do educador" educator_resources: "Recursos do educador"
course_guides: "e guia dos cursos" course_guides: "e guia dos cursos"
# teaching_computer_science: "Teaching computer science does not require a costly degree, because we provide tools to support educators of all backgrounds." teaching_computer_science: "Ensinar ciência da computação não requer um diploma oneroso, pois nós disponibilizamos ferramentas para apoiar todoos os tipos de educadores."
accessible_to: "Acessível a" accessible_to: "Acessível a"
everyone: "todos" everyone: "todos"
democratizing: "Democratizar o processo de aprendizagem de codificação é o objectivo da nossa filosofia. Qualquer um deve ser capaz de aprender a programar." democratizing: "Democratizar o processo de aprendizagem de codificação é o objectivo da nossa filosofia. Qualquer um deve ser capaz de aprender a programar."
forgot_learning: "Eu acho que eles realmente esqueceram que estavam aprendendo de verdade." forgot_learning: "Eu acho que eles realmente esqueceram que estavam aprendendo de verdade."
wanted_to_do: "Programar é algo que eu sempre quis fazer, e eu nunca pensei que seria capaz de aprender isso na escola." wanted_to_do: "Programar é algo que eu sempre quis fazer, e eu nunca pensei que seria capaz de aprender isso na escola."
# why_games: "Why is learning through games important?" why_games: "Porque é importante aprender através de jogos?"
# games_reward: "Games reward the productive struggle." games_reward: "Jogos recompensam o esforço produtivo."
# encourage: "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." encourage: "Jogar é um meio de encorajar a interação, descoberta, e a tentativa e erro. Um bom jogo desafia o jogador a dominar as habilidades com o tempo, que é o mesmo processo crítico que alunos passam quando eles estão aprendendo algo."
# excel: "Games excel at rewarding" excel: "Jogos destacam-se pela recompesa do"
# struggle: "productive struggle" struggle: "esforço produtivo"
# kind_of_struggle: "the kind of struggle that results in learning thats engaging and" kind_of_struggle: "o tipo de esforço resultante do aprendizado é cativante,"
motivating: "motivador" motivating: "motivador"
# not_tedious: "not tedious." not_tedious: "e divertido."
gaming_is_good: "Estudos indicam que jogos são bons para o cérebro das crianças. (é verdade!)" gaming_is_good: "Estudos indicam que jogos são bons para o cérebro das crianças. (é verdade!)"
# game_based: "When game-based learning systems are" game_based: "Quando sistemas de aprendizado baseados em jogos são"
compared: "comparado" compared: "comparados"
# conventional: "against conventional assessment methods, the difference is clear: games are better at helping students retain knowledge, concentrate and" conventional: "com métodos de avaliação convencional a diferença é clara: jogos são melhores e ajudam alunos a reter o conhecimento, concentração e"
# perform_at_higher_level: "perform at a higher level of achievement" perform_at_higher_level: "desenvolver um nível superior de realização"
# feedback: "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." feedback: "Jogos também fornecem respostas em tempo real permitindo que os alunos criem seus caminhos para a solução e entendam conceitos mais holisticamente, ao invés de limitar as repostas como “corretas” ou “incorretas”."
real_game: "Um jogo de verdade, com programação de verdade." real_game: "Um jogo de verdade, com programação de verdade."
# great_game: "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." great_game: "Um grande jogo é mais do que apenas emblemas e realizações - Isso é sobre a jornada de um jogador, quebra-cabeças bem desenhados, e a habilidade para enfrentar desafios com ação e confiança."
# agency: "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." agency: "CodeCombat é um jogo que fornece aos jogadores essa ação e confiança com nosso robusto motor de digitação de código, que ajuda alunos iniciantes e avançados tanto na escrita quanto na validação do código."
# request_demo_title: "Get your students started today!" # request_demo_title: "Get your students started today!"
# request_demo_subtitle: "Request a demo and get your students started in less than an hour." # request_demo_subtitle: "Request a demo and get your students started in less than an hour."
# get_started_title: "Set up your class today" # get_started_title: "Set up your class today"

View file

@ -278,6 +278,7 @@ LevelSchema = c.object {
c.extendNamedProperties LevelSchema # let's have the name be the first property c.extendNamedProperties LevelSchema # let's have the name be the first property
_.extend LevelSchema.properties, _.extend LevelSchema.properties,
description: {title: 'Description', description: 'A short explanation of what this level is about.', type: 'string', maxLength: 65536, format: 'markdown'} description: {title: 'Description', description: 'A short explanation of what this level is about.', type: 'string', maxLength: 65536, format: 'markdown'}
studentPlayInstructions: {title: 'Student Play Instructions', description: 'Instructions for game dev levels when students play them.', type: 'string', maxLength: 65536, format: 'markdown'}
loadingTip: { type: 'string', title: 'Loading Tip', description: 'What to show for this level while it\'s loading.' } loadingTip: { type: 'string', title: 'Loading Tip', description: 'What to show for this level while it\'s loading.' }
documentation: c.object {title: 'Documentation', description: 'Documentation articles relating to this level.', 'default': {specificArticles: [], generalArticles: []}}, documentation: c.object {title: 'Documentation', description: 'Documentation articles relating to this level.', 'default': {specificArticles: [], generalArticles: []}},
specificArticles: c.array {title: 'Specific Articles', description: 'Specific documentation articles that live only in this level.', uniqueItems: true }, SpecificArticleSchema specificArticles: c.array {title: 'Specific Articles', description: 'Specific documentation articles that live only in this level.', uniqueItems: true }, SpecificArticleSchema
@ -312,7 +313,7 @@ _.extend LevelSchema.properties,
body: {type: 'string', format: 'markdown', title: 'Body Text', description: 'Inserted into the Victory Modal once this level is complete. Tell the player they did a good job and what they accomplished!'}, body: {type: 'string', format: 'markdown', title: 'Body Text', description: 'Inserted into the Victory Modal once this level is complete. Tell the player they did a good job and what they accomplished!'},
i18n: {type: 'object', format: 'i18n', props: ['body'], description: 'Help translate this victory message'} i18n: {type: 'object', format: 'i18n', props: ['body'], description: 'Help translate this victory message'}
} }
i18n: {type: 'object', format: 'i18n', props: ['name', 'description', 'loadingTip'], description: 'Help translate this level'} i18n: {type: 'object', format: 'i18n', props: ['name', 'description', 'loadingTip', 'studentPlayInstructions'], description: 'Help translate this level'}
icon: {type: 'string', format: 'image-file', title: 'Icon'} icon: {type: 'string', format: 'image-file', title: 'Icon'}
banner: {type: 'string', format: 'image-file', title: 'Banner'} banner: {type: 'string', format: 'image-file', title: 'Banner'}
goals: c.array {title: 'Goals', description: 'An array of goals which are visible to the player and can trigger scripts.'}, GoalSchema goals: c.array {title: 'Goals', description: 'An array of goals which are visible to the player and can trigger scripts.'}, GoalSchema

View file

@ -117,6 +117,7 @@ module.exports =
'level:show-victory': c.object {required: ['showModal']}, 'level:show-victory': c.object {required: ['showModal']},
showModal: {type: 'boolean'} showModal: {type: 'boolean'}
manual: { type: 'boolean' }
'level:highlight-dom': c.object {required: ['selector']}, 'level:highlight-dom': c.object {required: ['selector']},
selector: {type: 'string'} selector: {type: 'string'}

View file

@ -16,3 +16,7 @@
.teacher-name .teacher-name
font-size: 14pt font-size: 14pt
.parent_birthdate
font-size: 11pt
margin-top: 20px

View file

@ -592,6 +592,79 @@ $gameControlMargin: 30px
margin: 15px 0 margin: 15px 0
min-width: 100px min-width: 100px
.beta-container
$betaImagesWidth: 1902px
width: $campaignWidth
height: $campaignHeight
display: inline-block
flex-shrink: 0
position: relative
.beta-campaign
width: $campaignWidth
height: $campaignHeight / 2
display: inline-block
flex-shrink: 0
position: relative
cursor: pointer
// http://easings.net/#easeOutBack plus tweaked a bit: http://cubic-bezier.com/#.11,.67,.08,1.42
@include transition(0.25s cubic-bezier(0.11, 0.67, 0.8, 1.42))
&:hover
@include scale($campaignHoverScale)
&.silhouette
@include filter(contrast(50%) brightness(65%))
pointer-events: none
&.locked
@include filter(contrast(80%) brightness(80%))
pointer-events: none
.campaign-label
position: absolute
top: 40%
width: 100%
text-align: center
.campaign-name, .levels-completed, .campaign-locked
margin: 0
color: white
text-shadow: black 2px 2px 0, black -2px -2px 0, black 2px -2px 0, black -2px 2px 0, black 2px 0px 0, black 0px -2px 0, black -2px 0px 0, black 0px 2px 0
.campaign-locked
margin: 32px 0
.campaign-description
margin: 0px 40px
background: transparent url(/images/level/popover_border_background.png) no-repeat
background-size: 100% 100%
padding: 12px
color: black
font-size: 12px
.levels-completed
font-size: 22px
.play-button
margin: 10px 0
min-width: 100px
color: white
.background-container
position: absolute
left: $campaignWidth / 4
width: $campaignWidth / 2
height: $campaignHeight / 2
background: transparent url(/images/pages/play/portal-beta-campaigns.png) no-repeat 0 0
background-size: $betaImagesWidth / 2
&.campaign-web-dev-1
background-position: -151px 0px
&.campaign-game-dev-1
background-position: -454px 0px
.small-nav-logo, .picoctf-powered-by .small-nav-logo, .picoctf-powered-by
position: absolute position: absolute
top: 1% top: 1%

View file

@ -52,6 +52,7 @@ body.dialogue-view-active
.spell-palette-popover.popover .spell-palette-popover.popover
// Only those popovers which are our direct children (spell documentation) // Only those popovers which are our direct children (spell documentation)
top: 80px !important
left: auto !important left: auto !important
right: 45% right: 45%
max-width: 600px max-width: 600px

View file

@ -146,6 +146,13 @@ block content
small(data-i18n="about.lisa_title") small(data-i18n="about.lisa_title")
br br
li
img(src="/images/pages/about/sean_small.png").img-thumbnail
.team-bio
h6.label.team-name Sean McNulty
small(data-i18n="about.sean_title")
br
// Part time / contract // Part time / contract
li li
a(href="http://floor.is/lava/" rel="external") a(href="http://floor.is/lava/" rel="external")

View file

@ -50,6 +50,7 @@ form.modal-body.segment-check
- var thisYear = new Date().getFullYear() - var thisYear = new Date().getFullYear()
for year in _.range(thisYear, thisYear - 100, -1) for year in _.range(thisYear, thisYear - 100, -1)
option(selected=(year == view.signupState.get('birthdayYear'))) #{year} option(selected=(year == view.signupState.get('birthdayYear'))) #{year}
.parent_birthdate(data-i18n="signup.parent_use_birthdate")
default default
p p

View file

@ -22,12 +22,9 @@ block content
#article-treema #article-treema
#article-view
h3(data-i18n="resources.patches") Patches h3(data-i18n="resources.patches") Patches
.patches-view .patches-view
hr hr
div#error-view div#error-view

View file

@ -7,7 +7,7 @@ mixin box
div div
a.teacher-btn.btn.btn-primary.btn-lg.btn-block(data-event-action="Homepage Click Teacher Button CTA", data-i18n="new_home.im_a_teacher") a.teacher-btn.btn.btn-primary.btn-lg.btn-block(data-event-action="Homepage Click Teacher Button CTA", data-i18n="new_home.im_a_teacher")
div div
a.student-btn.btn.btn-forest.btn-lg.btn-block(href="/courses", data-event-action="Homepage Click Student Button CTA", data-i18n="new_home.im_a_student") a.student-btn.btn.btn-forest.btn-lg.btn-block(href="/home#create-account-student", data-event-action="Homepage Click Student Button CTA", data-i18n="new_home.im_a_student")
h6#learn-to-code-header(data-i18n="new_home.learn_to_code") h6#learn-to-code-header(data-i18n="new_home.learn_to_code")
a.btn.btn-gold.btn-lg.btn-block.play-btn(href=view.playURL, data-event-action="Homepage Play Now CTA", data-i18n="new_home.play_now") a.btn.btn-gold.btn-lg.btn-block.play-btn(href=view.playURL, data-event-action="Homepage Play Now CTA", data-i18n="new_home.play_now")

View file

@ -100,28 +100,57 @@ if view.showAds()
else else
.portal .portal
.portals .portals
for campaignSlug in ['dungeon', 'forest', 'desert', 'mountain', 'glacier', 'volcano'] for campaignSlug in ['dungeon', 'beta-campaigns', 'forest', 'desert', 'mountain', 'glacier', 'volcano']
- var campaign = campaigns[campaignSlug]; if campaignSlug === 'beta-campaigns'
- var godmode = me.get('permissions', true).indexOf('godmode') != -1; - var betaSlugs = _.shuffle(['campaign-game-dev-1', 'campaign-web-dev-1']);
div(class="campaign #{campaignSlug}" + (campaign ? "" : " silhouette") + (campaign && campaign.locked && !godmode ? " locked" : ""), data-campaign-slug=campaignSlug) .beta-container
.campaign-label each campaignSlug in betaSlugs
h2.campaign-name - var campaign = campaigns[campaignSlug];
if campaign if !campaign
span= i18n(campaign.attributes, 'fullName') - continue;
else div(class="beta-campaign" + (campaign ? "" : " silhouette") + (campaign && campaign.locked && !godmode ? " locked" : ""), data-campaign-slug=campaignSlug)
span ??? .background-container(class="#{campaignSlug}")
if campaign && campaign.levelsTotal .campaign-label
h3.levels-completed h3.campaign-name
span= campaign.levelsCompleted if campaign
| / span= i18n(campaign.attributes, 'fullName')
span= campaign.levelsTotal if campaign.levelsTotal
if campaign && campaign.locked && !godmode span.spl= campaign.levelsCompleted
h3.campaign-locked(data-i18n="play.locked") Locked | /
else if campaign span= campaign.levelsTotal
btn(data-i18n="common.play").btn.btn-illustrated.btn-lg.btn-success.play-button else
if campaign && campaign.get('description') span ???
p.campaign-description if campaign && campaign.locked && !godmode
span= i18n(campaign.attributes, 'description') h4.campaign-locked(data-i18n="play.locked") Locked
else if campaign
btn.btn.btn-illustrated.btn-lg.btn-primary.play-button(data-i18n="common.play")
if campaign && campaign.get('description')
p.campaign-description
span= i18n(campaign.attributes, 'description')
else
- var campaign = campaigns[campaignSlug];
if !campaign
- continue;
- var godmode = me.get('permissions', true).indexOf('godmode') != -1;
div(class="campaign #{campaignSlug}" + (campaign ? "" : " silhouette") + (campaign && campaign.locked && !godmode ? " locked" : ""), data-campaign-slug=campaignSlug)
.campaign-label
h2.campaign-name
if campaign
span= i18n(campaign.attributes, 'fullName')
else
span ???
if campaign && campaign.levelsTotal
h3.levels-completed
span= campaign.levelsCompleted
| /
span= campaign.levelsTotal
if campaign && campaign.locked && !godmode
h3.campaign-locked(data-i18n="play.locked") Locked
else if campaign
btn(data-i18n="common.play").btn.btn-illustrated.btn-lg.btn-success.play-button
if campaign && campaign.get('description')
p.campaign-description
span= i18n(campaign.attributes, 'description')
.game-controls.header-font.picoctf-hide .game-controls.header-font.picoctf-hide
button.btn.poll.hidden(data-i18n="[title]play.poll") button.btn.poll.hidden(data-i18n="[title]play.poll")

View file

@ -79,7 +79,10 @@ block modal-body-content
.reward-panel.hero(data-hero-thang-type=hero.get('original')) .reward-panel.hero(data-hero-thang-type=hero.get('original'))
.reward-image-container(class=animate ? 'pending-reward-image' : 'show') .reward-image-container(class=animate ? 'pending-reward-image' : 'show')
img(src=hero.getPortraitURL()) img(src=hero.getPortraitURL())
.reward-text= animate ? 'New Hero' : hero.get('name') if animate
.reward-text(data-i18n="play_level.victory_new_hero") New Hero
else
.reward-text= i18n(hero.attributes, 'name')
if rewards.items if rewards.items
for item in rewards.items for item in rewards.items

View file

@ -15,7 +15,7 @@
if view.level.id && view.session.id if view.level.id && view.session.id
h3.m-y-1= view.level.get('name') h3.m-y-1= view.level.get('name')
h4 Created by #{view.session.get('creatorName')} h4= view.state.get('creatorString')
hr hr
if view.state.get('loading') if view.state.get('loading')
@ -24,24 +24,24 @@
.progress-bar(style="width: #{view.state.get('progress')}") .progress-bar(style="width: #{view.state.get('progress')}")
if ready if ready
h3 Goals h3(data-i18n="play_level.goals")
for goalName in view.state.get('goalNames') for goalName in view.state.get('goalNames')
p= goalName p= goalName
hr hr
h3 How to play: h3(data-i18n="play_game_dev_level.how_to_play_title")
p Use the mouse to control the hero! p(data-i18n="play_game_dev_level.how_to_play_1")
p Click anywhere on the map to move to that location. p(data-i18n="play_game_dev_level.how_to_play_2")
p Click on the ogres to attack them. p(data-i18n="play_game_dev_level.how_to_play_3")
if ready if ready
.panel-footer .panel-footer
- var playing = view.state.get('playing') - var playing = view.state.get('playing')
if playing if playing
button#play-btn.btn.btn-lg.btn-burgandy.btn-block Restart Level button#play-btn.btn.btn-lg.btn-burgandy.btn-block(data-i18n="play_game_dev_level.restart")
else else
button#play-btn.btn.btn-lg.btn-forest.btn-block Play Level button#play-btn.btn.btn-lg.btn-forest.btn-block(data-i18n="play_game_dev_level.play")
#share-row.m-t-3 #share-row.m-t-3
if ready if ready
@ -55,4 +55,4 @@
span(data-i18n='sharing.copy_url') span(data-i18n='sharing.copy_url')
.panel-body .panel-body
a#play-more-codecombat-btn.btn.btn-lg.btn-navy-alt.pull-right(href="/") Play More CodeCombat a#play-more-codecombat-btn.btn.btn-lg.btn-navy-alt.pull-right(href="/", data-i18n="play_game_dev_level.play_more_codecombat")

View file

@ -52,17 +52,15 @@ if view.showAds()
button.btn.btn-lg.btn-warning.banner.header-font#stop-real-time-playback-button(title="Stop real-time playback") button.btn.btn-lg.btn-warning.banner.header-font#stop-real-time-playback-button(title="Stop real-time playback")
if view.level && view.level.isType('game-dev') if view.level && view.level.isType('game-dev')
| Back to coding span(data-i18n="play_game_dev_level.back_to_coding")
else else
span(data-i18n="play_level.skip") span(data-i18n="play_level.skip")
#how-to-play-game-dev-panel.panel.panel-default.hide.style-flat #how-to-play-game-dev-panel.panel.panel-default.hide.style-flat
.panel-heading .panel-heading
h3.panel-title How to play: h3.panel-title(data-i18n="play_game_dev_level.how_to_play_title")
.panel-body
p Use the mouse to control the hero! .panel-body!= view.howToPlayText
p Click anywhere on the map to move to that location.
p Click on the ogres to attack them.
.hints-view.hide .hints-view.hide

View file

@ -84,13 +84,14 @@ module.exports = class NewHomeView extends RootView
onClickStudentButton: (e) -> onClickStudentButton: (e) ->
window.tracker?.trackEvent $(e.target).data('event-action'), category: 'Homepage', [] window.tracker?.trackEvent $(e.target).data('event-action'), category: 'Homepage', []
@render?() if document.location.href.search('/home#create-account-student') isnt -1
onClickTeacherButton: (e) -> onClickTeacherButton: (e) ->
window.tracker?.trackEvent $(e.target).data('event-action'), category: 'Homepage', [] window.tracker?.trackEvent $(e.target).data('event-action'), category: 'Homepage', []
if me.isTeacher() if me.isTeacher()
application.router.navigate('/teachers', { trigger: true }) application.router.navigate('/teachers', { trigger: true })
else else
@scrollToLink('.request-demo-row', 600) application.router.navigate('/teachers/signup', { trigger: true })
onClickViewProfile: (e) -> onClickViewProfile: (e) ->
window.tracker?.trackEvent $(e.target).data('event-action'), category: 'Homepage', [] window.tracker?.trackEvent $(e.target).data('event-action'), category: 'Homepage', []

View file

@ -16,7 +16,7 @@ module.exports = class SettingsTabView extends CocoView
'name', 'description', 'documentation', 'nextLevel', 'background', 'victory', 'i18n', 'icon', 'goals', 'name', 'description', 'documentation', 'nextLevel', 'background', 'victory', 'i18n', 'icon', 'goals',
'type', 'terrain', 'showsGuide', 'banner', 'employerDescription', 'loadingTip', 'requiresSubscription', 'type', 'terrain', 'showsGuide', 'banner', 'employerDescription', 'loadingTip', 'requiresSubscription',
'helpVideos', 'replayable', 'scoreTypes', 'concepts', 'picoCTFProblem', 'practice', 'practiceThresholdMinutes' 'helpVideos', 'replayable', 'scoreTypes', 'concepts', 'picoCTFProblem', 'practice', 'practiceThresholdMinutes'
'shareable' 'shareable', 'studentPlayInstructions'
] ]
subscriptions: subscriptions:

View file

@ -17,6 +17,8 @@ module.exports = class I18NEditLevelView extends I18NEditModelView
@wrapRow 'Level description', ['description'], description, i18n[lang]?.description, [] @wrapRow 'Level description', ['description'], description, i18n[lang]?.description, []
if loadingTip = @model.get('loadingTip') if loadingTip = @model.get('loadingTip')
@wrapRow 'Loading tip', ['loadingTip'], loadingTip, i18n[lang]?.loadingTip, [] @wrapRow 'Loading tip', ['loadingTip'], loadingTip, i18n[lang]?.loadingTip, []
if studentPlayInstructions = @model.get('studentPlayInstructions')
@wrapRow 'Student Play Instructions', ['studentPlayInstructions'], studentPlayInstructions, i18n[lang]?.studentPlayInstructions, []
# goals # goals
for goal, index in @model.get('goals') ? [] for goal, index in @model.get('goals') ? []

View file

@ -55,6 +55,7 @@ module.exports = class CampaignView extends RootView
'click #back-button': 'onClickBack' 'click #back-button': 'onClickBack'
'click #clear-storage-button': 'onClickClearStorage' 'click #clear-storage-button': 'onClickClearStorage'
'click .portal .campaign': 'onClickPortalCampaign' 'click .portal .campaign': 'onClickPortalCampaign'
'click .portal .beta-campaign': 'onClickPortalCampaign'
'mouseenter .portals': 'onMouseEnterPortals' 'mouseenter .portals': 'onMouseEnterPortals'
'mouseleave .portals': 'onMouseLeavePortals' 'mouseleave .portals': 'onMouseLeavePortals'
'mousemove .portals': 'onMouseMovePortals' 'mousemove .portals': 'onMouseMovePortals'
@ -365,7 +366,7 @@ module.exports = class CampaignView extends RootView
return experienceScore return experienceScore
createLine: (o1, o2) -> createLine: (o1, o2) ->
mapHeight = parseFloat($(".map").css("height")) mapHeight = parseFloat($(".map").css("height"))
mapWidth = parseFloat($(".map").css("width")) mapWidth = parseFloat($(".map").css("width"))
return unless mapHeight > 0 return unless mapHeight > 0
ratio = mapWidth / mapHeight ratio = mapWidth / mapHeight
@ -668,7 +669,7 @@ module.exports = class CampaignView extends RootView
console.error "CampaignView hero update couldn't find hero slug for original:", hero console.error "CampaignView hero update couldn't find hero slug for original:", hero
onClickPortalCampaign: (e) -> onClickPortalCampaign: (e) ->
campaign = $(e.target).closest('.campaign') campaign = $(e.target).closest('.campaign, .beta-campaign')
return if campaign.is('.locked') or campaign.is('.silhouette') return if campaign.is('.locked') or campaign.is('.silhouette')
campaignSlug = campaign.data('campaign-slug') campaignSlug = campaign.data('campaign-slug')
Backbone.Mediator.publish 'router:navigate', Backbone.Mediator.publish 'router:navigate',

View file

@ -33,6 +33,7 @@ module.exports = class PlayGameDevLevelView extends RootView
@state = new State({ @state = new State({
loading: true loading: true
progress: 0 progress: 0
creatorString: ''
}) })
@supermodel.on 'update-progress', (progress) => @supermodel.on 'update-progress', (progress) =>
@ -92,6 +93,7 @@ module.exports = class PlayGameDevLevelView extends RootView
loading: false loading: false
goalNames goalNames
shareURL shareURL
creatorString: $.i18n.t('play_game_dev_level.created_by').replace('{{name}}', @session.get('creatorName'))
}) })
@eventProperties = { @eventProperties = {
category: 'Play GameDev Level' category: 'Play GameDev Level'

View file

@ -211,7 +211,12 @@ module.exports = class PlayLevelView extends RootView
@$el.addClass 'web-dev' # Hide some of the elements we won't be using @$el.addClass 'web-dev' # Hide some of the elements we won't be using
return return
@world = @levelLoader.world @world = @levelLoader.world
@$el.addClass 'game-dev' if @level.isType('game-dev') if @level.isType('game-dev')
@$el.addClass 'game-dev'
@howToPlayText = utils.i18n(@level.attributes, 'studentPlayInstructions')
@howToPlayText ?= $.i18n.t('play_game_dev_level.default_student_instructions')
@howToPlayText = marked(@howToPlayText, { sanitize: true })
@renderSelectors('#how-to-play-game-dev-panel')
@$el.addClass 'hero' if @level.isType('hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev') # TODO: figure out what this does and comment it @$el.addClass 'hero' if @level.isType('hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev') # TODO: figure out what this does and comment it
@$el.addClass 'flags' if _.any(@world.thangs, (t) -> (t.programmableProperties and 'findFlags' in t.programmableProperties) or t.inventory?.flag) or @level.get('slug') is 'sky-span' @$el.addClass 'flags' if _.any(@world.thangs, (t) -> (t.programmableProperties and 'findFlags' in t.programmableProperties) or t.inventory?.flag) or @level.get('slug') is 'sky-span'
# TODO: Update terminology to always be opponentSession or otherSession # TODO: Update terminology to always be opponentSession or otherSession
@ -548,9 +553,9 @@ module.exports = class PlayLevelView extends RootView
onDonePressed: -> @showVictory() onDonePressed: -> @showVictory()
onShowVictory: (e) -> onShowVictory: (e={}) ->
$('#level-done-button').show() unless @level.isType('hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'web-dev') $('#level-done-button').show() unless @level.isType('hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'web-dev')
@showVictory() if e.showModal @showVictory(_.pick(e, 'manual')) if e.showModal
return if @victorySeen return if @victorySeen
@victorySeen = true @victorySeen = true
victoryTime = (new Date()) - @loadEndTime victoryTime = (new Date()) - @loadEndTime
@ -563,8 +568,9 @@ module.exports = class PlayLevelView extends RootView
ls: @session?.get('_id') ls: @session?.get('_id')
application.tracker?.trackTiming victoryTime, 'Level Victory Time', @levelID, @levelID application.tracker?.trackTiming victoryTime, 'Level Victory Time', @levelID, @levelID
showVictory: -> showVictory: (options={}) ->
return if @level.hasLocalChanges() # Don't award achievements when beating level changed in level editor return if @level.hasLocalChanges() # Don't award achievements when beating level changed in level editor
return if @level.isType('game-dev') and @level.get('shareable') and not options.manual
@endHighlight() @endHighlight()
options = {level: @level, supermodel: @supermodel, session: @session, hasReceivedMemoryWarning: @hasReceivedMemoryWarning, courseID: @courseID, courseInstanceID: @courseInstanceID, world: @world} options = {level: @level, supermodel: @supermodel, session: @session, hasReceivedMemoryWarning: @hasReceivedMemoryWarning, courseID: @courseID, courseInstanceID: @courseInstanceID, world: @world}
ModalClass = if @level.isType('hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'web-dev') then HeroVictoryModal else VictoryModal ModalClass = if @level.isType('hero', 'hero-ladder', 'hero-coop', 'course', 'course-ladder', 'game-dev', 'web-dev') then HeroVictoryModal else VictoryModal
@ -638,18 +644,21 @@ module.exports = class PlayLevelView extends RootView
if @level.isType('game-dev') if @level.isType('game-dev')
panel = @$('#how-to-play-game-dev-panel') panel = @$('#how-to-play-game-dev-panel')
panel.removeClass('hide') panel.removeClass('hide')
lines = switch @level.get('slug') # TODO: Remove this once these levels have studentPlayInstructions set.
when 'over-the-garden-wall' then ['Watch to see if the peasants are properly protected.'] if not @level.get('studentPlayInstructions')
when 'click-gait' then ['Move to each red "X".', 'Click on the screen to move the Knight there.'] lines = switch @level.get('slug')
when 'heros-journey' then ['Move to each red "X".', 'Click on the screen to move the Knight there.'] when 'over-the-garden-wall' then ['Watch to see if the peasants are properly protected.']
when 'a-maze-ing' then ['Move to the chest of gems.', 'Click on the screen to move the Duelist there.'] when 'click-gait' then ['Move to each red "X".', 'Click on the screen to move the Knight there.']
when 'gemtacular' then ['Move to each of the gems.', 'Click on the screen to move the Captain there.'] when 'heros-journey' then ['Move to each red "X".', 'Click on the screen to move the Knight there.']
when 'vorpal-mouse' then ['Slay the ogres.', 'Click on the screen to move the Guardian there.', 'Click on the munchkins to attack them!'] when 'a-maze-ing' then ['Move to the chest of gems.', 'Click on the screen to move the Duelist there.']
when 'crushing-it' then ['Slay the ogres.', 'Click on the screen to move the Goliath there.', 'Click on the munchkins to attack them!'] when 'gemtacular' then ['Move to each of the gems.', 'Click on the screen to move the Captain there.']
when 'tabula-rasa' then ['Slay any ogres.', 'Collect any coins.', 'Click on the screen to move the Raider there.', 'Click on any munchkins to attack them!'] when 'vorpal-mouse' then ['Slay the ogres.', 'Click on the screen to move the Guardian there.', 'Click on the munchkins to attack them!']
else ['Click to control your hero and win your game!'] when 'crushing-it' then ['Slay the ogres.', 'Click on the screen to move the Goliath there.', 'Click on the munchkins to attack them!']
html = _.map(lines, (line) -> "<p>#{line}</p>").join('') when 'tabula-rasa' then ['Slay any ogres.', 'Collect any coins.', 'Click on the screen to move the Raider there.', 'Click on any munchkins to attack them!']
panel.find('.panel-body').html(html) else null
if lines
html = _.map(lines, (line) -> "<p>#{line}</p>").join('')
panel.find('.panel-body').html(html)
@onWindowResize() @onWindowResize()

View file

@ -324,7 +324,7 @@ module.exports = class HeroVictoryModal extends ModalView
@playSound 'item-unlocked' if 0.5 < ratio < 0.6 @playSound 'item-unlocked' if 0.5 < ratio < 0.6
else if panel.hero else if panel.hero
thangType = @thangTypes[panel.hero] thangType = @thangTypes[panel.hero]
panel.textEl.text(thangType.get('name')) panel.textEl.text utils.i18n(thangType.attributes, 'name')
@playSelectionSound thangType if 0.5 < ratio < 0.6 @playSelectionSound thangType if 0.5 < ratio < 0.6
if ratio is 1 if ratio is 1
panel.rootEl.removeClass('animating').find('.reward-image-container img').removeClass('pulse') panel.rootEl.removeClass('animating').find('.reward-image-container img').removeClass('pulse')
@ -413,7 +413,17 @@ module.exports = class HeroVictoryModal extends ModalView
AudioPlayer.playSound name, 1 AudioPlayer.playSound name, 1
getNextLevelCampaign: -> getNextLevelCampaign: ->
{'kithgard-gates': 'forest', 'kithgard-mastery': 'forest', 'siege-of-stonehold': 'desert', 'clash-of-clones': 'mountain', 'summits-gate': 'glacier'}[@level.get('slug')] or @level.get 'campaign' # Much easier to just keep this updated than to dynamically figure it out. # Much easier to just keep this updated than to dynamically figure it out.
# TODO: only go back to world selector if any beta campaigns are incomplete
{
'kithgard-gates': '',
'kithgard-mastery': '',
'tabula-rasa': '',
'wanted-poster': '',
'siege-of-stonehold': '',
'clash-of-clones': 'mountain',
'summits-gate': 'glacier'
}[@level.get('slug')] ? @level.get 'campaign'
getNextLevelLink: (returnToCourse=false) -> getNextLevelLink: (returnToCourse=false) ->
if @level.isType('course', 'game-dev', 'web-dev') and nextLevel = @level.get('nextLevel') and not returnToCourse if @level.isType('course', 'game-dev', 'web-dev') and nextLevel = @level.get('nextLevel') and not returnToCourse

View file

@ -81,7 +81,7 @@ module.exports = class CastButtonView extends CocoView
onDoneButtonClick: (e) -> onDoneButtonClick: (e) ->
return if @options.level.hasLocalChanges() # Don't award achievements when beating level changed in level editor return if @options.level.hasLocalChanges() # Don't award achievements when beating level changed in level editor
@options.session.recordScores @world?.scores, @options.level @options.session.recordScores @world?.scores, @options.level
Backbone.Mediator.publish 'level:show-victory', showModal: true Backbone.Mediator.publish 'level:show-victory', { showModal: true, manual: true }
onSpellChanged: (e) -> onSpellChanged: (e) ->
@updateCastButton() @updateCastButton()

View file

@ -198,10 +198,10 @@ module.exports = class Zatanna
editor.completer.autoInsert = false editor.completer.autoInsert = false
editor.completer.showPopup(editor) editor.completer.showPopup(editor)
# Hide popup if more than 10 suggestions # Hide popup if too many suggestions
# TODO: Completions aren't asked for unless we show popup, so this is super hacky # TODO: Completions aren't asked for unless we show popup, so this is super hacky
# TODO: Backspacing to yield more suggestions does not close popup # TODO: Backspacing to yield more suggestions does not close popup
if editor.completer?.completions?.filtered?.length > 10 if editor.completer?.completions?.filtered?.length > 20
editor.completer.detach() editor.completer.detach()
# Update popup CSS after it's been launched # Update popup CSS after it's been launched
@ -244,6 +244,7 @@ module.exports = class Zatanna
addCodeCombatSnippets: (level, spellView, e) -> addCodeCombatSnippets: (level, spellView, e) ->
snippetEntries = [] snippetEntries = []
source = spellView.getSource()
haveFindNearestEnemy = false haveFindNearestEnemy = false
haveFindNearest = false haveFindNearest = false
for group, props of e.propGroups for group, props of e.propGroups
@ -279,7 +280,6 @@ module.exports = class Zatanna
else 'while true' else 'while true'
# For now, update autocomplete to use hero instead of self/this, if hero is already used in the source. # For now, update autocomplete to use hero instead of self/this, if hero is already used in the source.
# Later, we should make this happen all the time - or better yet update the snippets. # Later, we should make this happen all the time - or better yet update the snippets.
source = spellView.getSource()
if /hero/.test(source) or not /(self[\.\:]|this\.|\@)/.test(source) if /hero/.test(source) or not /(self[\.\:]|this\.|\@)/.test(source)
thisToken = thisToken =
'python': /self/, 'python': /self/,
@ -318,6 +318,15 @@ module.exports = class Zatanna
attackEntry.content = attackEntry.content.replace '${1:enemy}', '"${1:Enemy Name}"' attackEntry.content = attackEntry.content.replace '${1:enemy}', '"${1:Enemy Name}"'
snippetEntries.push attackEntry snippetEntries.push attackEntry
# Add copied hero. entries for most important ones that start with hero.
sortedEntries = _.sortBy snippetEntries, (entry) -> -1 * parseInt(entry.importance ? 0)
for entry in sortedEntries
if entry.content?.indexOf('hero.') is 0
newEntry = _.cloneDeep(entry)
entry.name = "hero.#{newEntry.name}"
snippetEntries.push(newEntry)
break if snippetEntries.length - sortedEntries.length >= 10
if haveFindNearest and not haveFindNearestEnemy if haveFindNearest and not haveFindNearestEnemy
spellView.translateFindNearest() spellView.translateFindNearest()

View file

@ -51,6 +51,16 @@ function createCloseLead(zpContact, done) {
if (zpContact.phone) { if (zpContact.phone) {
postData.contacts[0].phones = [{phone: zpContact.phone}]; postData.contacts[0].phones = [{phone: zpContact.phone}];
} }
if (zpContact.district) {
postData.custom['demo_nces_district'] = zpContact.district;
postData.custom['demo_nces_name'] = zpContact.organization;
}
if (zpContact.nces_district_id) {
postData.custom['demo_nces_district_id'] = zpContact.nces_district_id;
}
if (zpContact.nces_school_id) {
postData.custom['demo_nces_id'] = zpContact.nces_school_id;
}
const options = { const options = {
uri: `https://${closeIoApiKey}:X@app.close.io/api/v1/lead/`, uri: `https://${closeIoApiKey}:X@app.close.io/api/v1/lead/`,
body: JSON.stringify(postData) body: JSON.stringify(postData)
@ -146,16 +156,31 @@ function getZPContactsPage(contacts, searchQuery, done) {
if (err) return done(err); if (err) return done(err);
const data = JSON.parse(body); const data = JSON.parse(body);
for (let contact of data.contacts) { for (let contact of data.contacts) {
let organization = contact.organization_name; const newContact = {
if (contact.custom_fields && contact.custom_fields.school_name) organization = contact.custom_fields.school_name; organization: contact.organization_name,
contacts.push({
organization: organization,
name: contact.name, name: contact.name,
title: contact.title, title: contact.title,
email: contact.email, email: contact.email,
phone: contact.phone, phone: contact.phone,
data: contact data: contact
}); };
// Check custom fields, school_name set means organization_name is district name
if (contact.custom_fields) {
if (contact.custom_fields.school_name) {
newContact.district = contact.organization_name;
newContact.organization = contact.custom_fields.school_name;
// console.log(`DEBUG: found contact with school name ${newContact.email} ${contact.custom_fields.school_name}`);
}
if (contact.custom_fields.nces_district_id) {
newContact.nces_district_id = contact.custom_fields.nces_district_id;
// console.log(`DEBUG: found contact with district id ${newContact.email} ${newContact.nces_district_id}`);
}
if (contact.custom_fields.nces_school_id) {
newContact.nces_school_id = contact.custom_fields.nces_school_id;
// console.log(`DEBUG: found contact with school id ${newContact.email} ${newContact.nces_school_id}`);
}
}
contacts.push(newContact);
} }
return done(null, data.pipeline_total); return done(null, data.pipeline_total);
}); });

View file

@ -68,7 +68,8 @@ LevelHandler = class LevelHandler extends Handler
'scoreTypes' 'scoreTypes'
'concepts' 'concepts'
'picoCTFProblem' 'picoCTFProblem'
'practiceThresholdMinutes' 'practiceThresholdMinutes',
'studentPlayInstructions'
] ]
postEditableProperties: ['name'] postEditableProperties: ['name']

View file

@ -107,7 +107,7 @@ module.exports =
getStudents: wrap (req, res, next) -> getStudents: wrap (req, res, next) ->
throw new errors.Unauthorized('You must be an administrator.') unless req.user?.isAdmin() throw new errors.Unauthorized('You must be an administrator.') unless req.user?.isAdmin()
query = $or: [{role: 'student'}, {$and: [{schoolName: {$exists: true}}, {schoolName: {$ne: ''}}, {anonymous: false}]}] query = $or: [{role: 'student'}, {$and: [{schoolName: {$exists: true}}, {schoolName: {$ne: ''}}, {anonymous: false}]}]
users = yield User.find(query).select('lastIP schoolName').lean() users = yield User.find(query).select('lastIP').lean()
for user in users for user in users
if ip = user.lastIP if ip = user.lastIP
user.geo = geoip.lookup(ip) user.geo = geoip.lookup(ip)

View file

@ -48,7 +48,7 @@ describe 'RequestQuoteView', ->
} }
}]) }])
}) })
_.defer done # Let SuperModel finish view.supermodel.once('loaded-all', done)
it 'shows request received', -> it 'shows request received', ->
expect(view.$('#request-form').hasClass('hide')).toBe(true) expect(view.$('#request-form').hasClass('hide')).toBe(true)
@ -220,7 +220,7 @@ describe 'RequestQuoteView', ->
} }
}]) }])
}) })
_.defer done # Let SuperModel finish view.supermodel.once('loaded-all', done)
it 'shows form with data from the most recent request', -> it 'shows form with data from the most recent request', ->
expect(view.$('input[name="firstName"]').val()).toBe('First') expect(view.$('input[name="firstName"]').val()).toBe('First')