Merge branch 'master' into production

This commit is contained in:
Matt Lott 2016-01-31 09:08:41 -08:00
commit d8e217a232
46 changed files with 1425 additions and 452 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

View file

@ -0,0 +1,11 @@
CocoCollection = require 'collections/CocoCollection'
TrialRequest = require 'models/TrialRequest'
module.exports = class TrialRequestCollection extends CocoCollection
url: '/db/trial.request'
model: TrialRequest
fetchOwn: (options) ->
options = _.extend({data: {}}, options)
options.url = _.result(@, 'url') + '/-/own'
@fetch(options)

View file

@ -121,7 +121,8 @@ module.exports = class CocoRouter extends Backbone.Router
'schools': go('SalesView')
'teachers': go('TeachersView')
'teachers/freetrial': go('TeachersFreeTrialView')
'teachers/freetrial': go('RequestQuoteView')
'teachers/quote': go('RequestQuoteView')
'test(/*subpath)': go('TestView')

View file

@ -93,7 +93,7 @@ module.exports = class Tracker
ga? 'send', 'pageview', url
# Mixpanel
mixpanelIncludes = ['courses', 'courses/purchase', 'courses/teachers', 'courses/students', 'schools', 'teachers', 'teachers/freetrial']
mixpanelIncludes = ['', 'courses', 'courses/purchase', 'courses/teachers', 'courses/students', 'schools', 'teachers', 'teachers/freetrial', 'teachers/quote']
mixpanel.track('page viewed', 'page name' : name, url : url) if name in mixpanelIncludes
trackEvent: (action, properties={}, includeIntegrations=[]) =>
@ -142,7 +142,7 @@ module.exports = class Tracker
$.post("#{window.location.protocol or 'http:'}//analytics.codecombat.com/analytics", dataToSend).fail ->
console.error "Analytics post failed!"
else
request = @supermodel.addRequestResource 'log_event', {
request = @supermodel.addRequestResource {
url: '/db/analytics.log.event/-/log_event'
data: {event: event, properties: properties}
method: 'POST'

View file

@ -1,22 +1,35 @@
module.exports.formToObject = (el) ->
module.exports.formToObject = ($el, options) ->
options = _.extend({ trim: true, ignoreEmptyString: true }, options)
obj = {}
inputs = $('input', el).add('textarea', el)
inputs = $('input, textarea, select', $el)
for input in inputs
input = $(input)
continue unless name = input.attr('name')
obj[name] = input.val()
obj[name] = obj[name].trim() if obj[name]?.trim
if input.attr('type') is 'checkbox'
obj[name] ?= []
if input.is(':checked')
obj[name].push(input.val())
else if input.attr('type') is 'radio'
continue unless input.is('checked')
obj[name] = input.val()
else
value = input.val() or ''
value = _.string.trim(value) if options.trim
if value or (not options.ignoreEmptyString)
obj[name] = value
obj
module.exports.applyErrorsToForm = (el, errors, warning=false) ->
errors = [errors] if not $.isArray(errors)
missingErrors = []
for error in errors
if error.dataPath
if error.code is tv4.errorCodes.OBJECT_REQUIRED
prop = _.last(_.string.words(error.message)) # hack
message = 'Required field'
else if error.dataPath
prop = error.dataPath[1..]
console.log prop
message = error.message
else
@ -35,8 +48,13 @@ module.exports.setErrorToField = setErrorToField = (el, message, warning=false)
return console.error el, " did not contain a form group, so couldn't show message:", message
kind = if warning then 'warning' else 'error'
afterEl = $(formGroup.find('.help-block, .form-control, input, select, textarea')[0])
formGroup.addClass "has-#{kind}"
formGroup.append $("<span class='help-block #{kind}-help-block'>#{message}</span>")
helpBlock = $("<span class='help-block #{kind}-help-block'>#{message}</span>")
if afterEl.length
afterEl.before helpBlock
else
formGroup.append helpBlock
module.exports.setErrorToProperty = setErrorToProperty = (el, property, message, warning=false) ->
input = $("[name='#{property}']", el)

View file

@ -98,6 +98,7 @@ module.exports.thangNames = thangNames =
# Female
'Vyrryx'
'Yzzrith'
'Xith'
]
'Ogre Chieftain': [
# Female
@ -146,6 +147,8 @@ module.exports.thangNames = thangNames =
# Animal
'Nevermore'
'Baltimore'
'Columbia'
'Dawnstar'
]
'Cougar': [
# Animal
@ -368,6 +371,7 @@ module.exports.thangNames = thangNames =
'Goliath': [
# Male
'Okar'
'Ivan'
]
'Guardian': [
# Female

View file

@ -34,6 +34,11 @@
twitter_follow: "Follow"
teachers: "Teachers"
careers: "Careers"
facebook: "Facebook"
twitter: "Twitter"
create_a_class: "Create a Class"
other: "Other"
learn_to_code: "Learn to Code!"
modal:
close: "Close"
@ -618,6 +623,37 @@
fill_fields: "Please fill out all fields."
thanks: "Thanks! We'll send you setup instructions shortly."
teachers_quote:
name: "Quote Form"
title: "Request a Quote"
subtitle: "Get CodeCombat in your classroom, club, school or district!"
phone_number: "Phone number"
phone_number_help: "Where can we reach you during the workday?"
role_label: "Your role"
role_help: "Select your primary role."
tech_coordinator: "Technology coordinator"
advisor: "Advisor"
principal: "Principal"
superintendent: "Superintendent"
parent: "Parent"
organization_label: "Name of School/District"
city: "City"
state: "State"
country: "Country"
num_students_help: "How many do you anticipate enrolling in CodeCombat?"
education_level_label: "Education Level of Students"
education_level_help: "Choose as many as apply."
elementary_school: "Elementary School"
high_school: "High School"
please_explain: "(please explain)"
middle_school: "Middle School"
college_plus: "College or higher"
anything_else: "Anything else we should know?"
thanks_header: "Thanks for requesting a quote!"
thanks_p: "We'll be in touch soon. Questions? Email us:"
thanks_anon: "Login or sign up with your account below to access your two free enrollments (well notify you by email when they have been approved, which usually takes less than 48 hours). As always, the first hour of content is free for an unlimited number of students."
thanks_logged_in: "Your two free enrollments are pending approval. Well notify you by email when they have been approved (usually within 48 hours). As always, the first hour of content is free for an unlimited number of students."
versions:
save_version_title: "Save New Version"
new_major_version: "New Major Version"
@ -1352,78 +1388,34 @@
loading_error:
could_not_load: "Error loading from server"
connection_failure: "Connection failed."
connection_failure: "Connection Failed" # {change}
connection_failure_desc: "It doesnt look like youre connected to the internet! Check your network connection and then reload this page."
login_required: "Login Required"
login_required_desc: "You need to be logged in to access this page."
unauthorized: "You need to be signed in. Do you have cookies disabled?"
forbidden: "You do not have the permissions."
not_found: "Not found."
forbidden: "Forbidden" # {change}
forbidden_desc: "Oh no, theres nothing we can show you here! Make sure youre logged into the correct account, or visit one of the links below to get back to programming!"
not_found: "Not Found" # {change}
not_found_desc: "Hm, theres nothing here. Visit one of the following links to get back to programming!"
not_allowed: "Method not allowed."
timeout: "Server timeout."
timeout: "Server Timeout" # {change}
conflict: "Resource conflict."
bad_input: "Bad input."
server_error: "Server error."
unknown: "Unknown error."
unknown: "Unknown Error" # {change}
error: "ERROR"
general_desc: "Something went wrong, and its probably our fault. Try waiting a bit and then refreshing the page, or visit one of the following links to get back to programming!"
resources:
sessions: "Sessions"
your_sessions: "Your Sessions"
level: "Level"
social_network_apis: "Social Network APIs"
facebook_status: "Facebook Status"
facebook_friends: "Facebook Friends"
facebook_friend_sessions: "Facebook Friend Sessions"
gplus_friends: "G+ Friends"
gplus_friend_sessions: "G+ Friend Sessions"
leaderboard: "Leaderboard"
user_schema: "User Schema"
user_profile: "User Profile"
patch: "Patch"
patches: "Patches"
patched_model: "Source Document"
model: "Model"
system: "System"
systems: "Systems"
component: "Component"
components: "Components"
thang: "Thang"
thangs: "Thangs"
level_session: "Your Session"
opponent_session: "Opponent Session"
article: "Article"
user_names: "User Names"
thang_names: "Thang Names"
files: "Files"
top_simulators: "Top Simulators"
source_document: "Source Document"
document: "Document"
sprite_sheet: "Sprite Sheet"
employers: "Employers"
candidates: "Candidates"
candidate_sessions: "Candidate Sessions"
user_remark: "User Remark"
user_remarks: "User Remarks"
versions: "Versions"
items: "Items"
hero: "Hero"
heroes: "Heroes"
achievement: "Achievement"
clas: "CLAs"
play_counts: "Play Counts"
feedback: "Feedback"
payment_info: "Payment Info"
campaigns: "Campaigns"
poll: "Poll"
user_polls_record: "Poll Voting History"
course: "Course"
courses: "Courses"
course_instance: "Course Instance"
course_instances: "Course Instances"
classroom: "Classroom"
classrooms: "Classrooms"
clan: "Clan"
clans: "Clans"
members: "Members"
users: "Users"
concepts:
advanced_strings: "Advanced Strings"

View file

@ -116,7 +116,7 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
login_switch: "¿Ya tienes una cuenta?"
school_name: "Nombre de Escuela y Ciudad"
optional: "opcional"
# school_name_placeholder: "Example High School, Springfield, IL"
school_name_placeholder: "Ejemplo: High School, Springfield, IL"
recover:
recover_account_title: "recuperar cuenta"
@ -251,7 +251,7 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
victory_title_suffix: " Completo!"
victory_sign_up: "Regístrate para recibir actualizaciones"
victory_sign_up_poke: "¿Quieres recibir las ultimas noticias por correo? ¡Crea una cuenta gratuita y te mantendremos informado!"
victory_rate_the_level: "Valora el nivel: " # {change}
victory_rate_the_level: "¿Cómo de divertido estuvo este nivel?"
victory_return_to_ladder: "Volver a la escalera"
victory_saving_progress: "Guardando Progreso"
victory_go_home: "Ir al Inicio"
@ -403,7 +403,7 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
comparison_blurb: "Agudiza tus habilidades con la suscripción a CodeCombat!"
feature1: "Más de 110 niveles basicos a lo largo de 4 mundos"
feature2: "10 poderosos <strong>nuevos heroés</strong> con habilidades unicas!"
feature3: "Más de 70 niveles extras" # {change}
feature3: "+80 niveles extras"
feature4: "<strong>{{gems}} gemas de bono</strong> cada mes!"
feature5: "Video tutoriales"
feature6: "Soporte Premium vía email"
@ -436,12 +436,12 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
parents_blurb3: "Sin Riesgo: Garantía de 100% de devolución, fácil 1-click y des- suscribirse."
payment_methods: "Metodos de pago"
payment_methods_title: "Metodos de pago aceptados."
payment_methods_blurb1: "Actualmente aceptamos tarjetas de credito y Alipay." # {change}
payment_methods_blurb1: "Actualmente aceptamos tarjetas de credito y Alipay. Tambíen puedes usar PayPal, enviando a nick@codecombat tu correo electrónico, y pudiendo adquirir por {{three_month_price}} USD una suscripción de tres meses y gemas, o por ${{year_price}} una de un año."
payment_methods_blurb2: "Si necesitas una forma alternativa de pago, por favor contactarse"
sale_button: "Venta!"
sale_button_title: "Ahorra ${{discount}} al adquirir una suscripción por 1 año" # {change}
sale_button_title: "Ahorre $21 al adquirir una suscripción por 1 año"
stripe_description: "Suscripción Mensual"
stripe_description_year_sale: "Suscripción por 1 año (${{discount}} descuento)" # {change}
stripe_description_year_sale: "Suscripción por 1 año (${{discount}} de descuento)"
subscription_required_to_play: "Necesitas una suscripción para jugar este nivel."
unlock_help_videos: "Suscríbete para desbloquear todos los video tutoriales."
personal_sub: "Suscripción Personal" # Accounts Subscription View below
@ -454,7 +454,7 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
managed_subs: "Suscripciones administradas"
subscribing: "Suscribiendo..."
current_recipients: "Recipientes actuales"
unsubscribing: "Desuscribiendo..." # {change}
unsubscribing: "Dando de baja..."
subscribe_prepaid: "Click en suscribirse para utlizar un código prepago"
using_prepaid: "Usar código prepago para una suscribción mensual"
@ -552,22 +552,22 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
press_paragraph_1_link: "paquete de prensa"
press_paragraph_1_suffix: ". Todos los logos e imágenes pueden ser usados sin contactarnos directamente."
team: "Equipo"
nick_title: "Cofundador" # {change}
nick_title: "Cofundador, CEO"
nick_blurb: "Gurú motivacional"
matt_title: "Cofundador" # {change}
matt_title: "Cofundador, CTO"
matt_blurb: "Bicicletero"
cat_title: "Jefe Artesano" # {change}
cat_title: "Diseñadora de Juegos"
cat_blurb: "Maestro del Aire"
scott_title: "Cofundador" # {change}
scott_title: "Cofundador, Ingeniero de Software"
scott_blurb: "Razonable"
# maka_title: "Customer Advocate"
# maka_blurb: "Storyteller"
rob_title: "Ingeniero de Compilación" # {change}
maka_title: "Defensor del Consumidor"
maka_blurb: "Cuentista"
rob_title: "Ingeniero de Software"
rob_blurb: "Hace código y demás"
josh_c_title: "Diseñador de Juegos"
josh_c_blurb: "Diseña juegos"
# robin_title: "UX Design & Research"
# robin_blurb: "Scaffolding"
robin_title: "Diseñadora de UX & Investigadora"
robin_blurb: "Scaffolding"
josh_title: "Diseñador de Juegos"
josh_blurb: "El piso es Lava"
retrostyle_title: "Ilustración"
@ -579,8 +579,8 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
teachers:
who_for_title: "¿Para quienes es CodeCombat?"
who_for_1: "Recomendamos CodeCombat para estudiantes de edades 9 y arriba. No se require experiencia en programación." # {change}
who_for_2: "Hemos diseñado a CodeCombat para atraer a niños y niñas." # {change}
who_for_1: "Recomendamos CodeCombat para estudiantes con +9 años de edad. No se require experiencia en programación. Diseñamos CodeCombat para que sea atractivo tanto para los chicos como para las chicas."
who_for_2: "Nuestro sistema de Cursos permite a los maestros configurar las clases, monitorizar el progreso y asignar contenido adicional a los estudiantes a través de una interfaz dedicada."
more_info_title: "¿Dónde puedo encontrar más información?"
more_info_1: "Nuestro"
more_info_2: "el foro de profesores"
@ -590,14 +590,14 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
title: "Encuesta de Maestros"
must_be_logged: "Debes ingresar primero. Por favor, crea una cuenta o ingresa desde el menú de arriba."
retrieving: "Obteniendo información..."
being_reviewed_1: "Su aplicación a una suscripción gratuita está siendo" # {change}
being_reviewed_1: "Su aplicación a una suscripción gratuita está siendo"
being_reviewed_2: "revisada."
approved_1: "Su aplicación a una suscripción gratuita fue" # {change}
approved_2: "aprobada." # {change}
# approved_4: "You can now enroll your students on the"
approved_1: "Su aplicación para una prueba gratuita está siendo"
approved_2: "revisada."
approved_4: "Ahora puedes inscribir a tus estudiantes en los"
approved_5: "cursos"
# approved_6: "page."
denied_1: "Su aplicación a una suscripción gratuita ha sido" # {change}
approved_6: "página."
denied_1: "Su aplicación para una prueba gratuita ha sido"
denied_2: "denegada."
contact_1: "Por favor contactarse"
contact_2: "si tiene más preguntas."
@ -736,7 +736,7 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
subs_only: "solo suscriptores"
create_clan: "Crear nuevo clan"
private_preview: "Vista previa"
# private_clans: "Private Clans"
private_clans: "Clanes Privados"
public_clans: "Clanes publicos"
my_clans: "Mis Clanes"
clan_name: "Nombre del clan"
@ -856,7 +856,7 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
see_the: "Vea la"
more_info: "para más información."
choose_course: "Elige tu Curso:"
enter_code: "Introducir un código de desbloqueo" # {change}
enter_code: "Introducir un código de desbloqueo para ingresar a una clase"
enter_code1: "Introducir código de desbloqueo"
enroll: "Inscribirse"
pick_from_classes: "Elije de tus clases actuales"
@ -867,14 +867,14 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
get_free: "Obtenga curso GRATIS"
enroll_paid: "Anotar estudiantes en cursos pagos."
you_have1: "Tiene"
# you_have2: "unused paid enrollments"
# use_one: "Use 1 paid enrollment for"
# use_multiple: "Use paid enrollments for the following students:"
# already_enrolled: "already enrolled"
you_have2: "matrículas pagadas no utilizadas"
use_one: "Utilizar 1 matrícula pagada para"
use_multiple: "Utilizar matrículas pagadas para los siguientes estudiantes:"
already_enrolled: "ya matriculados"
licenses_remaining: "licencias restantes:"
# insufficient_enrollments: "insufficient paid enrollments"
# enroll_students: "Enroll Students"
# get_enrollments: "Get More Enrollments"
insufficient_enrollments: "matrículas pagas insuficientes"
enroll_students: "Matricular Estudiantes"
get_enrollments: "Obtener Más Matrículas"
change_language: "Cambiar idioma del curso"
keep_using: "Seguir Usando"
switch_to: "Cambiar a"
@ -885,24 +885,24 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
back_classrooms: "Volver a mis aulas"
back_courses: "Volver a mis cursos"
edit_details: "Editar detallesde clase"
# enrolled_courses: "enrolled in paid courses:"
# purchase_enrollments: "Purchase Enrollments"
enrolled_courses: "matriculados en cursos pagos:"
purchase_enrollments: "Comprar Matrículas"
remove_student: "Quitar alumno"
assign: "Asignar"
# to_assign: "to assign paid courses."
to_assign: "para asignar cursos pagos."
teacher: "Maestro"
complete: "Completado"
# none: "None"
none: "Ninguno"
save: "Guardar"
play_campaign_title: "Jugar Campaña"
play_campaign_description: "Estas listo para dar el siguiente paso! Explora cientos de desafiantes niveles, aprende habilidades avanzadas de programación, y compite en arenas multijugador!"
create_account_title: "Crea una Cuenta"
create_account_description: "Registrate gratis con una cuenta CodeCombat y obten acceso a mas niveles, mas habilidades de programacion, y mas diversion!"
preview_campaign_title: "Previsualizar campaña"
# preview_campaign_description: "Take a sneak peek at all that CodeCombat has to offer before signing up for your FREE account."
preview_campaign_description: "Echa un vistazo a todo lo que CodeCombat tiene para ofrecer antes de registrarse con una cuenta GRATUITA."
arena: "Arena"
arena_soon_title: "Arena pronto disponible"
# arena_soon_description: "We are working on a multiplayer arena for classrooms at the end of"
arena_soon_description: "Estamos trabajando en una arena multijugador para las aulas para finales de"
not_enrolled1: "No inscrito"
not_enrolled2: "Preguntale a tu maestro para anotarte en el proximo curso."
next_course: "Próximo curso"
@ -914,7 +914,7 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
start_new_game: "Iniciar un Nuevo Juego"
play_now_learn_header: "Juega y Aprende"
play_now_learn_1: "Sintaxis básica para controlar a tu personaje"
# play_now_learn_2: "while loops to solve pesky puzzles"
play_now_learn_2: "bucles while para resolver rompecabezas molestos"
play_now_learn_3: "cadenas & variables para personalizar acciones"
play_now_learn_4: "como vencer a un ogro (habilidades importantes en la vida!)"
welcome_to_page: "¡Bienvenido a tu página de cursose!"
@ -931,7 +931,7 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
view_levels: "ver niveles"
join_class: "Unirse a clase"
ask_teacher_for_code: "Preguntalé a tu profesor si tu tienes un código de CodeCombat! Si lo tiene, ingresalo debajo:"
# enter_c_code: "<Enter Class Code>"
enter_c_code: "<Ingresar Código de la Clase>"
join: "Unirse"
joining: "Uniendose a claseJoining class"
course_complete: "Curso completo"
@ -945,72 +945,72 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
continue_playing: "Seguir jugando"
more_options: "Másopciones:"
option1_header: "Opción 1: Invitar estudiantes vía email"
# option1_body: "Students will automatically be sent an invitation to join this class, and will need to create an account with a username and password."
option1_body: "Se enviará automaticamente una invitación a los estudiantes para unirse a esta clase, y tendrán que crear una cuenta con un nombre de usuario y una contraseña."
option2_header: "Opción 2: Enviarles la URL a tus estudiantes"
# option2_body: "Students will be asked to enter an email address, username and password to create an account."
option2_body: "Se pedirá a los estudiantes que ingresen un correo electrónico, un nombre de usuario y una contraseña para crear una cuenta."
option3_header: "Opción 3: Dirigir estudiantes a to codecombat.com/courses"
# option3_body: "Give students the following passcode to enter along with an email address, username and password when they create an account."
option3_body: "Dar a los estudiantes el siguiente código de acceso para ingresar junto con el correo electrónico, el nombre de usuario y la contraseña cuando creen una cuenta."
thank_you_pref: "Gracias por tu compra! Ahora puedes asignar"
thank_you_suff: "más estudiantes a cursos pagos."
# return_to_class: "Return to classroom"
# return_to_course_man: "Return to course management."
# students_not_enrolled: "students not enrolled"
# total_all_classes: "Total Across All Classes"
# how_many_enrollments: "How many additional paid enrollments do you need?"
# each_student_access: "Each student in a class will get access to Courses 2-4 once they are enrolled in paid courses. You may assign each course to each student individually."
return_to_class: "Regresar al aula"
return_to_course_man: "Regresar a la administración del curso."
students_not_enrolled: "estudiantes no matriculados"
total_all_classes: "Total Por Todas las Clases"
how_many_enrollments: "¿Cuántas matriculas pagas adicionales necesitas?"
each_student_access: "Cada estudiante en una clase obtendrá acceso a los Cursos 2-4 una vez que esten matriculados en los cursos pagos. Puedes asignar cada curso a cada estudiante de forma individual."
purchase_now: "Comprar Ahora"
# enrollments: "enrollments"
enrollments: "matrículas"
remove_student1: "Quitar alumno"
are_you_sure: "¿Estás seguro que quieres quitar este alumno de tu clase?"
# remove_description1: "Student will lose access to this classroom and assigned classes. Progress and gameplay is NOT lost, and the student can be added back to the classroom at any time."
# remove_description2: "The activated paid license will not be returned."
remove_description1: "El estudiante perderá acceso a esta aula y a sus clases asignadas. El progreso y la experiencia del juego NO se pierde, y el estudiante puede ser agregado de vuelta al aula en cualquier momento."
remove_description2: "La matrícula paga activada no será devuelta."
keep_student: "Mantener alumno"
removing_user: "Removiendo usuario"
to_join_ask: "Para ingresar a una clase, preguntale a tu maestro por un código de acceso."
join_this_class: "Ingresar clase"
enter_here: "<Ingresar el código aquí>"
# successfully_joined: "Successfully joined"
# click_to_start: "Click here to start taking"
successfully_joined: "Ingresado exitosamente"
click_to_start: "Click aquí para comenzar a hablar"
my_courses: "Mis Cursos"
classroom: "Aulas"
# use_school_email: "use your school email if you have one"
# unique_name: "a unique name no one has chosen"
use_school_email: "utilize su correo electrónico de la escuela si tiene uno"
unique_name: "un nombre único, no uno que ya esté escogido"
pick_something: "Escoge algo que recuerdes"
# class_code: "Class Code"
# optional_ask: "optional - ask your teacher to give you one!"
class_code: "Código de acceso"
optional_ask: "opcional - pregunta a tu maestro para que te de uno!"
optional_school: "opcional - a qué escuela vas?"
start_playing: "Comienza a Jugar"
skip_this: "Saltar esto, Crearé una cuenta mas tarde!"
welcome: "Bienvenido"
# getting_started: "Getting Started with Courses"
# download_getting_started: "Download Getting Started Guide [PDF]"
# getting_started_1: "Create a new class by clicking the green 'Create New Class' button below."
# getting_started_2: "Once you've created a class, click the blue 'Add Students' button."
# getting_started_3: "You'll see student's progress below as they sign up and join your class."
# additional_resources: "Additional Resources"
# additional_resources_1_pref: "Download/print our"
# additional_resources_1_mid: "Course 1 Teacher's Guide"
# additional_resources_1_suff: "explanations and solutions to each level."
# additional_resources_2_pref: "Complete our"
# additional_resources_2_suff: "to get two free enrollments for the rest of our paid courses."
# additional_resources_3_pref: "Visit our"
# additional_resources_3_mid: "Teacher Forums"
# additional_resources_3_suff: "to connect to fellow educators who are using CodeCombat."
# additional_resources_4_pref: "Check out our"
# additional_resources_4_mid: "Schools Page"
# additional_resources_4_suff: "to learn more about CodeCombat's classroom offerings."
# your_classes: "Your Classes"
# no_classes: "No classes yet!"
# create_new_class1: "create new class"
getting_started: "Cómo empezar con los Cursos"
download_getting_started: "Descargar Guía de Introducción [PDF]"
getting_started_1: "Crea una nueva clase haciendo click en el botón verde 'Crear Nueva Clase' de más abajo."
getting_started_2: "Una vez que creaste una clase, haz click en el botón azul 'Añadir Estudiantes'"
getting_started_3: "Verás los progresos de los estudiantes más abajo cuando se registren e ingresen a tu clase."
additional_resources: "Recursos Adicionales"
additional_resources_1_pref: "Descargar/imprimir nuestra"
additional_resources_1_mid: "Guía para maestros: Curso 1"
additional_resources_1_suff: "explicaciones y soluciones para cada nivel."
additional_resources_2_pref: "Complete nuestro"
additional_resources_2_suff: "para obtener dos matrículas gratuitas para el resto de nuestros cursos pagos."
additional_resources_3_pref: "Visite nuestro"
additional_resources_3_mid: "Foro de Maestros"
additional_resources_3_suff: "para relacionarse con sus colegas educadores que están usando CodeCombat."
additional_resources_4_pref: "Consulte nuestra"
additional_resources_4_mid: "Página de Escuelas"
additional_resources_4_suff: "para aprender más sobre la oferta para el aula de CodeCombat."
your_classes: "Tus Clases"
no_classes: "Aún no hay clases!"
create_new_class1: "crear nueva clase"
available_courses: "Cursos Disponibles"
# unused_enrollments: "Unused enrollments available:"
# students_access: "All students get access to Introduction to Computer Science for free. One enrollment per student is required to assign them to paid CodeCombat courses. A single student does not need multiple enrollments to access all paid courses."
# active_courses: "active courses"
unused_enrollments: "Matrículas no utilizadas disponibles:"
students_access: "Todos los estudiantes obtienen acceso gratuito a Introducción a la Informática. Una matrícula por estudiante es necesaria para asignarles los cursos pagos de CodeCombat. Un solo estudiante no necesita múltiples matrículas para acceder a todos los cursos pagos."
active_courses: "cursos activos"
no_students: "Aún no hay alumnos!"
add_students1: "añadir alumnos"
view_edit: "ver/editar"
# students_enrolled: "students enrolled"
# length: "Length:"
students_enrolled: "estudiantes matriculados"
length: "Duración:"
classes:
archmage_title: "Archimago"
@ -1232,7 +1232,7 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
tutorial_skip: "Saltar Tutorial"
tutorial_not_sure: "¿No estás seguro de que sucede?"
tutorial_play_first: "Juega el Tutorial primero."
simple_ai: "IA Simple" # {change}
simple_ai: "IA Simple"
warmup: "Calentamiento"
friends_playing: "Amigos Jugando"
log_in_for_friends: "Ingresa para jugar con tus amigos!"
@ -1255,7 +1255,7 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
winners: "Ganadores"
league: "Liga"
red_ai: "IA Roja" # "Red AI Wins", at end of multiplayer match playback
blue_ai: "IA Azul" # {change}
blue_ai: "IA Azul"
wins: "Gana" # At end of multiplayer match playback
humans: "Rojo" # Ladder page display team name
ogres: "Azul"
@ -1329,7 +1329,7 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
months: "Meses"
purchase_total: "Total"
purchase_button: "Enviar Adquisición"
your_codes: "Tus Códigos:" # {change}
your_codes: "Tus Códigos:"
redeem_codes: "Reclamar un Código de Suscripción"
prepaid_code: "Código Prepagado"
lookup_code: "Buscar código prepagado"
@ -1408,8 +1408,8 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
user_polls_record: "Historia de Visitas de Encuestas"
course: "Curso"
courses: "Cursos"
# course_instance: "Course Instance"
# course_instances: "Course Instances"
course_instance: "Muestra del Curso"
course_instances: "Muestras del Curso"
classroom: "Salón"
classrooms: "Salones"
clan: "Clan"
@ -1516,8 +1516,8 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
nutshell_title: "En una palabra"
nutshell_description: "Cualquier recurso que te proveamos en el Editor de Niveles es gratis de usar como te plazca para la creación de Niveles. Sin embargo, nos reservamos el derecho de restringir la distribución de los niveles por sí mismos (aquellos creados en codecombat.com) para así poder cobrar por ellos en el futuro, si es que eso es lo que termina pasando."
canonical: "La versión en inglés de este documento es la versión canónica y definitiva. Si hay alguna discrepancia entre las traducciones, la versión en inglés toma precedencia."
# third_party_title: "Third Party Services"
# third_party_description: "CodeCombat uses the following third party services (among others):"
third_party_title: "Servicios de Terceros"
third_party_description: "CodeCombat utiliza los siguientes servicios de terceros (entre otros):"
ladder_prizes:
title: "Premios de Torneos" # This section was for an old tournament and doesn't need new translations now.

View file

@ -908,7 +908,7 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi
next_course: "Следующий курс"
coming_soon1: "Скоро появится"
# coming_soon2: "We are hard at work making more courses for you!"
# available_levels: "Available Levels"
available_levels: "Доступные уровни"
welcome_to_courses: "Искатели приключений, добро пожаловать на курсы!"
ready_to_play: "Готовы приступить к игре?"
start_new_game: "Начать новую игру"
@ -930,19 +930,19 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi
view_class: "смотреть класс"
view_levels: "смотреть уровни"
join_class: "Присоединиться к классу"
# ask_teacher_for_code: "Ask your teacher if you have a CodeCombat class code! If so, enter it below:"
# enter_c_code: "<Enter Class Code>"
# join: "Присоединиться"
ask_teacher_for_code: "Спросите у вашего учителя код класса для CodeCombat! Введите его ниже:"
enter_c_code: "<Введите Код Класса>"
join: "Присоединиться"
# joining: "Joining class"
course_complete: "Курс завершён"
play_arena: "Играть Арену"
# start: "Старт"
# last_level: "Последний уровень"
start: "Старт"
last_level: "Последний уровень"
welcome_to_hoc: "Искатели приключений, добро пожаловать на Час кода!"
# logged_in_as: "Logged in as:"
# not_you: "Не вы?"
# welcome_back: "Привет, искатель приключений, добро пожаловать!"
# continue_playing: "Continue Playing"
logged_in_as: "Вошли как:"
not_you: "Не вы?"
welcome_back: "Привет, искатель приключений, добро пожаловать!"
continue_playing: "Играть Дальше"
more_options: "Другие варианты:"
option1_header: "Вариант 1: Пригласить учеников по email"
# option1_body: "Students will automatically be sent an invitation to join this class, and will need to create an account with a username and password."
@ -952,7 +952,7 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi
# option3_body: "Give students the following passcode to enter along with an email address, username and password when they create an account."
# thank_you_pref: "Thank you for your purchase! You can now assign"
# thank_you_suff: "more students to paid courses."
# return_to_class: "Return to classroom"
return_to_class: "Вернуться в класс"
return_to_course_man: "Вернуться к управлению курсом."
# students_not_enrolled: "students not enrolled"
total_all_classes: "Общее по всем классам"
@ -968,7 +968,7 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi
# removing_user: "Removing user"
# to_join_ask: "To join a class, ask your teacher for an unlock code."
# join_this_class: "Join Class"
# enter_here: "<Ввести здесь код разблокировки>"
enter_here: "<Ввести здесь код разблокировки>"
# successfully_joined: "Successfully joined"
# click_to_start: "Click here to start taking"
my_courses: "Мои курсы"
@ -976,7 +976,7 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi
# use_school_email: "use your school email if you have one"
# unique_name: "a unique name no one has chosen"
# pick_something: "pick something you can remember"
# class_code: "Class Code"
class_code: "Код класса"
optional_ask: "Как вариант - попросите учителя дать вам какой-нибудь!"
optional_school: "Не обязательное - в какую школу вы ходите?"
start_playing: "Начать играть"
@ -1000,17 +1000,17 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi
# additional_resources_4_mid: "Schools Page"
# additional_resources_4_suff: "to learn more about CodeCombat's classroom offerings."
your_classes: "Ваши классы"
# no_classes: "No classes yet!"
no_classes: "Ещё нет классов!"
create_new_class1: "создать новый класс"
# available_courses: "Available Courses"
available_courses: "Доступные курсы"
# unused_enrollments: "Unused enrollments available:"
# students_access: "All students get access to Introduction to Computer Science for free. One enrollment per student is required to assign them to paid CodeCombat courses. A single student does not need multiple enrollments to access all paid courses."
# active_courses: "active courses"
active_courses: "активные курсы"
no_students: "Ещё нет учеников!"
add_students1: "добавить учеников"
view_edit: "смотреть/редактировать"
students_enrolled: "учеников зачислено"
# length: "Length:"
length: "Длительность:"
classes:
archmage_title: "Архимаг"
@ -1256,9 +1256,9 @@ module.exports = nativeDescription: "русский", englishDescription: "Russi
league: "Лига"
red_ai: "CPU красного" # "Red AI Wins", at end of multiplayer match playback
blue_ai: "CPU синего"
wins: "Победы" # At end of multiplayer match playback
humans: "Красный" # Ladder page display team name
ogres: "Синий"
wins: "Побеждает" # At end of multiplayer match playback
humans: "Красных" # Ladder page display team name
ogres: "Синих"
user:
stats: "Характеристики"

View file

@ -8,23 +8,23 @@ module.exports = nativeDescription: "српски", englishDescription: "Serbian
# old_browser: "Uh oh, your browser is too old to run CodeCombat. Sorry!" # Warning that shows up on really old Firefox/Chrome/Safari
# old_browser_suffix: "You can try anyway, but it probably won't work."
# ipad_browser: "Bad news: CodeCombat doesn't run on iPad in the browser. Good news: our native iPad app is awaiting Apple approval."
# campaign: "Campaign"
# for_beginners: "For Beginners"
# multiplayer: "Multiplayer" # Not currently shown on home page
# for_developers: "For Developers" # Not currently shown on home page.
# or_ipad: "Or download for iPad"
campaign: "Кампања"
for_beginners: "За почетнике"
multiplayer: "Мултиплејер" # Not currently shown on home page
for_developers: "За Девелопере" # Not currently shown on home page.
or_ipad: "Или скини за iPad"
nav:
play: "Нивои" # The top nav bar entry where players choose which levels to play
# community: "Community"
# courses: "Courses"
community: "Заједница"
courses: "Курсеви"
editor: "Уређивач"
blog: "Блог"
forum: "Форум"
# account: "Account"
# profile: "Profile"
# stats: "Stats"
# code: "Code"
account: "Налог"
profile: "Профил"
stats: "Статистика"
code: "Код"
admin: "Админ" # Only shows up when you are an admin
home: "Почетна"
contribute: "Допринеси"
@ -32,8 +32,8 @@ module.exports = nativeDescription: "српски", englishDescription: "Serbian
about: "О нама"
contact: "Контакт"
twitter_follow: "Прати"
# teachers: "Teachers"
# careers: "Careers"
teachers: "Учитељи"
careers: "Каријере"
modal:
close: "Затвори"
@ -51,29 +51,29 @@ module.exports = nativeDescription: "српски", englishDescription: "Serbian
subscribe_as_diplomat: "Претплати се као Дипломата"
play:
# play_as: "Play As" # Ladder page
# compete: "Compete!" # Course details page
# spectate: "Spectate" # Ladder page
# players: "players" # Hover over a level on /play
# hours_played: "hours played" # Hover over a level on /play
# items: "Items" # Tooltip on item shop button from /play
# unlock: "Unlock" # For purchasing items and heroes
# confirm: "Confirm"
# owned: "Owned" # For items you own
# locked: "Locked"
# purchasable: "Purchasable" # For a hero you unlocked but haven't purchased
# available: "Available"
# skills_granted: "Skills Granted" # Property documentation details
# heroes: "Heroes" # Tooltip on hero shop button from /play
# achievements: "Achievements" # Tooltip on achievement list button from /play
# account: "Account" # Tooltip on account button from /play
# settings: "Settings" # Tooltip on settings button from /play
# poll: "Poll" # Tooltip on poll button from /play
# next: "Next" # Go from choose hero to choose inventory before playing a level
# change_hero: "Change Hero" # Go back from choose inventory to choose hero
# buy_gems: "Buy Gems"
# subscription_required: "Subscription Required"
# anonymous: "Anonymous Player"
play_as: "Играј као" # Ladder page
compete: "Такмичи се!" # Course details page
spectate: "Посматрај" # Ladder page
players: "играчи" # Hover over a level on /play
hours_played: "потребно сати играња" # Hover over a level on /play
items: "Ствари" # Tooltip on item shop button from /play
unlock: "Откључај" # For purchasing items and heroes
confirm: "Потврди"
owned: "У поседу" # For items you own
locked: "Закључани"
purchasable: "Могуће купити" # For a hero you unlocked but haven't purchased
available: "Доступни"
skills_granted: "Обезбеђени скилови" # Property documentation details
heroes: "Хероји" # Tooltip on hero shop button from /play
achievements: "Достигнућа" # Tooltip on achievement list button from /play
account: "Налог" # Tooltip on account button from /play
settings: "Подешавања" # Tooltip on settings button from /play
poll: "Покрени" # Tooltip on poll button from /play
next: "Следећи" # Go from choose hero to choose inventory before playing a level
change_hero: "Промени Хероја" # Go back from choose inventory to choose hero
buy_gems: "Купи драгуље"
subscription_required: "Потребна пријава"
anonymous: "Анонимни играч"
level_difficulty: "Тежина: "
# play_classroom_version: "Play Classroom Version" # Choose a level in campaign version that you also can play in one of your courses
campaign_beginner: "Почетничка кампања"
@ -97,72 +97,72 @@ module.exports = nativeDescription: "српски", englishDescription: "Serbian
login:
sign_up: "Направи Налог"
log_in: "Улогуј Се"
# logging_in: "Logging In"
logging_in: "Логовање"
log_out: "Излогуј Се"
# forgot_password: "Forgot your password?"
forgot_password: "Да ли си заборавио шифру?"
# authenticate_gplus: "Authenticate G+"
# load_profile: "Load G+ Profile"
# finishing: "Finishing"
# sign_in_with_facebook: "Sign in with Facebook"
# sign_in_with_gplus: "Sign in with G+"
# signup_switch: "Want to create an account?"
finishing: "Завршавање"
sign_in_with_facebook: "Учлани се преко Фејсбука"
sign_in_with_gplus: "Учлани се преко Гугл +"
signup_switch: "Да ли желиш да направиш налог?"
signup:
email_announcements: "Примај обавештења на мејл"
creating: "Прављење налога..."
sign_up: "Упиши се"
log_in: "улогуј се са шифром"
# required: "You need to log in before you can go that way."
# login_switch: "Already have an account?"
# school_name: "School Name and City"
# optional: "optional"
required: "Мораш да се улогујеш пре него што наставиш"
login_switch: "Већ имаш налог?"
school_name: "Име школе и града"
optional: "опционо"
# school_name_placeholder: "Example High School, Springfield, IL"
recover:
recover_account_title: "Поврати налог"
# send_password: "Send Recovery Password"
# recovery_sent: "Recovery email sent."
send_password: "Пошаљи помоћну шифру"
recovery_sent: "Послат мејл за потврду опоравка."
# items:
# primary: "Primary"
# secondary: "Secondary"
# armor: "Armor"
# accessories: "Accessories"
# misc: "Misc"
# books: "Books"
items:
primary: "Примарни"
secondary: "Секундарни"
armor: "Оклоп"
accessories: "Опрема"
misc: "Остало"
books: "Књиге"
common:
# back: "Back" # When used as an action verb, like "Navigate backward"
back: "Уназад" # When used as an action verb, like "Navigate backward"
# continue: "Continue" # When used as an action verb, like "Continue forward"
loading: "Учитавање"
saving: "Чување..."
sending: "Шаље се..."
# send: "Send"
send: "Пошаљи"
cancel: "Откажи"
# save: "Save"
# publish: "Publish"
# create: "Create"
save: "Сачувај"
publish: "Објави"
create: "Створи"
# fork: "Fork"
play: "Нивои" # When used as an action verb, like "Play next level"
# retry: "Retry"
# actions: "Actions"
# info: "Info"
# help: "Help"
# watch: "Watch"
# unwatch: "Unwatch"
# submit_patch: "Submit Patch"
# submit_changes: "Submit Changes"
# save_changes: "Save Changes"
info: "Инфо"
help: "Помоћ"
watch: "Одгледај"
unwatch: "Не гледај"
submit_patch: "Потврди закрпу"
submit_changes: "Потврди измене"
save_changes: "Сачувај измене"
general:
# and: "and"
name: "Име"
# date: "Date"
# body: "Body"
# version: "Version"
# pending: "Pending"
# accepted: "Accepted"
# rejected: "Rejected"
date: "Датум"
body: "Тело"
version: "Верзија"
pending: "Учитавање"
accepted: "Прихваћен"
rejected: "Одбијен"
# withdrawn: "Withdrawn"
# accept: "Accept"
# reject: "Reject"
@ -178,103 +178,103 @@ module.exports = nativeDescription: "српски", englishDescription: "Serbian
# redo_prefix: "Redo"
# redo_shortcut: "(Ctrl+Shift+Z)"
# play_preview: "Play preview of current level"
# result: "Result"
# results: "Results"
# description: "Description"
result: "Резултат"
results: "Резултати"
description: "Опис"
or: "или"
# subject: "Subject"
subject: "Субјекат"
email: "Мејл"
# password: "Password"
password: "Шифра"
message: "Порука"
# code: "Code"
code: "Код"
# ladder: "Ladder"
# when: "When"
# opponent: "Opponent"
# rank: "Rank"
# score: "Score"
# win: "Win"
# loss: "Loss"
# tie: "Tie"
# easy: "Easy"
# medium: "Medium"
# hard: "Hard"
# player: "Player"
# player_level: "Level" # Like player level 5, not like level: Dungeons of Kithgard
# warrior: "Warrior"
# ranger: "Ranger"
# wizard: "Wizard"
opponent: "Противник"
rank: "Чин"
score: "Поен"
win: "Победа"
loss: "Пораз"
tie: "Нерешено"
easy: "Лако"
medium: "Средње"
hard: "Тешко"
player: "Играч"
player_level: "Ранг играча" # Like player level 5, not like level: Dungeons of Kithgard
warrior: "Ратник"
ranger: "Извиђач"
wizard: "Маг"
# units:
# second: "second"
# seconds: "seconds"
# minute: "minute"
# minutes: "minutes"
# hour: "hour"
# hours: "hours"
# day: "day"
# days: "days"
# week: "week"
# weeks: "weeks"
# month: "month"
# months: "months"
# year: "year"
# years: "years"
units:
second: "секунда"
seconds: "секунде"
minute: "минут"
minutes: "минути"
hour: "сат"
hours: "сати"
day: "дан"
days: "дани"
week: "недеља"
weeks: "недеље"
month: "месец"
months: "месеци"
year: "година"
years: "године"
play_level:
# completed_level: "Completed Level:"
# course: "Course:"
completed_level: "Завршен ниво:"
course: "Курс:"
done: "Урађено"
# next_level: "Next Level:"
# next_game: "Next game"
# show_menu: "Show game menu"
next_level: "Следећи ниво:"
next_game: "Следећа игра"
show_menu: "Види мени игре"
home: "Почетна" # Not used any more, will be removed soon.
# level: "Level" # Like "Level: Dungeons of Kithgard"
# skip: "Skip"
# game_menu: "Game Menu"
level: "Ниво" # Like "Level: Dungeons of Kithgard"
skip: "Прескочи"
game_menu: "Мени игре"
guide: "Водич"
restart: "Поновно учитавање"
goals: "Циљеви"
# goal: "Goal"
# running: "Running..."
# success: "Success!"
# incomplete: "Incomplete"
# timed_out: "Ran out of time"
# failing: "Failing"
# control_bar_multiplayer: "Multiplayer"
# control_bar_join_game: "Join Game"
# reload: "Reload"
goal: "Циљ"
running: "Покретање..."
success: "Успех!"
incomplete: "Недовољно"
timed_out: "Истекло времe"
failing: "Губљење"
control_bar_multiplayer: "Мултиплејер"
control_bar_join_game: "Прикључи се игри"
reload: "Поновно учитавање"
reload_title: "Поновно учитавање целог кода?"
reload_really: "Да ли сте сигурни да желите да кренете ниво испочетка?"
reload_confirm: "Поновно учитавање свега"
# victory: "Victory"
# victory_title_prefix: ""
victory: "Победа"
victory_title_prefix: "Урааа победааа!"
victory_title_suffix: " Завршено"
victory_sign_up: "Пријави се за новости"
victory_sign_up_poke: "Желиш ли да примаш најновије вести на мејл? Направи бесплатан налог и ми ћемо те обавештавати!"
victory_rate_the_level: "Оцени ниво: " # {change}
# victory_return_to_ladder: "Return to Ladder"
# victory_saving_progress: "Saving Progress"
victory_return_to_ladder: "Врати се на лествицу"
victory_saving_progress: "Чување напретка"
victory_go_home: "Иди на почетну"
victory_review: "Реци нам више!"
# victory_review_placeholder: "How was the level?"
victory_review_placeholder: "Колико је био тежак ниво?"
victory_hour_of_code_done: "Јеси ли завршио?"
victory_hour_of_code_done_yes: "Да, завршио сам свој Сат Кода!"
# victory_experience_gained: "XP Gained"
# victory_gems_gained: "Gems Gained"
# victory_new_item: "New Item"
victory_experience_gained: "Добијено искуство"
victory_gems_gained: "Добијени драгуљи"
victory_new_item: "Нови Итем"
# 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: "Постани Викинг"
guide_title: "Водич"
# tome_cast_button_run: "Run"
# tome_cast_button_running: "Running"
# tome_cast_button_ran: "Ran"
# tome_submit_button: "Submit"
tome_submit_button: "Потврди"
# tome_reload_method: "Reload original code for this method" # Title text for individual method reload button.
# tome_select_method: "Select a Method"
# tome_see_all_methods: "See all methods you can edit" # Title text for method list selector (shown when there are multiple programmable methods).
tome_select_a_thang: "Изабери неког за "
tome_available_spells: "Доступне чини"
# tome_your_skills: "Your Skills"
tome_your_skills: "Твоје вештине"
# tome_current_method: "Current Method"
# code_saved: "Code Saved"
# skip_tutorial: "Skip (esc)"
@ -361,30 +361,30 @@ module.exports = nativeDescription: "српски", englishDescription: "Serbian
# multiplayer_caption: "Play with friends!"
# auth_caption: "Save your progress."
# leaderboard:
# view_other_solutions: "View Leaderboards"
# scores: "Scores"
# top_players: "Top Players by"
# day: "Today"
# week: "This Week"
# all: "All-Time"
# time: "Time"
# damage_taken: "Damage Taken"
# damage_dealt: "Damage Dealt"
# difficulty: "Difficulty"
# gold_collected: "Gold Collected"
leaderboard:
view_other_solutions: "Види табелу напредовања"
scores: "Резултати"
top_players: "Рангирање играча по"
day: "Данас"
week: "Ове недеље"
all: "Све-време"
time: "Време"
damage_taken: "Претпљена штета"
damage_dealt: "Нанета штета"
difficulty: "Тежина"
gold_collected: "Сакупљено злата"
# inventory:
# equipped_item: "Equipped"
# required_purchase_title: "Required"
# available_item: "Available"
# restricted_title: "Restricted"
# should_equip: "(double-click to equip)"
# equipped: "(equipped)"
inventory:
equipped_item: "Опремљен"
required_purchase_title: "Потребно"
available_item: "Доступно"
restricted_title: "Забрањено"
should_equip: "(Дупли-клик за опремање)"
equipped: "(опремљен/а)"
# locked: "(locked)"
# restricted: "(restricted in this level)"
# equip: "Equip"
# unequip: "Unequip"
equip: "Опреми"
unequip: "Скини"
# buy_gems:
# few_gems: "A few gems"
@ -458,12 +458,12 @@ module.exports = nativeDescription: "српски", englishDescription: "Serbian
# subscribe_prepaid: "Click Subscribe to use prepaid code"
# using_prepaid: "Using prepaid code for monthly subscription"
# choose_hero:
# choose_hero: "Choose Your Hero"
# programming_language: "Programming Language"
# programming_language_description: "Which programming language do you want to use?"
choose_hero:
choose_hero: "Изабери свог хероја"
programming_language: "Програмски језик"
programming_language_description: "Који програмски језик желиш да користиш у игри?"
# default: "Default"
# experimental: "Experimental"
experimental: "Експеро+иментални"
# python_blurb: "Simple yet powerful, great for beginners and experts."
# javascript_blurb: "The language of the web. (Not the same as Java.)"
# coffeescript_blurb: "Nicer JavaScript syntax."

View file

@ -28,6 +28,10 @@ module.exports = class SuperModel extends Backbone.Model
unfinished
loadModel: (model, name, fetchOptions, value=1) ->
# Deprecating name. Handle if name is not included
value = fetchOptions if _.isNumber(fetchOptions)
fetchOptions = name if _.isObject(name)
# hero-ladder levels need remote opponent_session for latest session data (e.g. code)
# Can't apply to everything since other features rely on cached models being more recent (E.g. level_session)
# E.g.#2 heroConfig isn't necessarily saved to db in world map inventory modal, so we need to load the cached session on level start
@ -48,6 +52,10 @@ module.exports = class SuperModel extends Backbone.Model
return res
loadCollection: (collection, name, fetchOptions, value=1) ->
# Deprecating name. Handle if name is not included
value = fetchOptions if _.isNumber(fetchOptions)
fetchOptions = name if _.isObject(name)
url = collection.getURL()
if cachedCollection = @collections[url]
console.debug 'Collection cache hit', url, 'already loaded', cachedCollection.loaded
@ -132,9 +140,13 @@ module.exports = class SuperModel extends Backbone.Model
# Tracking resources being loaded for this supermodel
finished: ->
return @progress is 1.0 or not @denom
return (@progress is 1.0) or (not @denom) or @failed
addModelResource: (modelOrCollection, name, fetchOptions, value=1) ->
# Deprecating name. Handle if name is not included
value = fetchOptions if _.isNumber(fetchOptions)
fetchOptions = name if _.isObject(name)
modelOrCollection.saveBackups = modelOrCollection.saveBackups or @shouldSaveBackups(modelOrCollection)
@checkName(name)
res = new ModelResource(modelOrCollection, name, fetchOptions, value)
@ -145,20 +157,25 @@ module.exports = class SuperModel extends Backbone.Model
@removeResource _.find(@resources, (resource) -> resource?.model is modelOrCollection)
addRequestResource: (name, jqxhrOptions, value=1) ->
# Deprecating name. Handle if name is not included
value = jqxhrOptions if _.isNumber(jqxhrOptions)
jqxhrOptions = name if _.isObject(name)
@checkName(name)
res = new RequestResource(name, jqxhrOptions, value)
@storeResource(res, value)
return res
addSomethingResource: (name, value=1) ->
value = name if _.isNumber(name)
@checkName(name)
res = new SomethingResource(name, value)
@storeResource(res, value)
return res
checkName: (name) ->
if not name
throw new Error('Resource name should not be empty.')
if _.isString(name)
console.warn("SuperModel name property deprecated. Remove '#{name}' from code.")
storeResource: (resource, value) ->
@rid++
@ -186,6 +203,7 @@ module.exports = class SuperModel extends Backbone.Model
onResourceFailed: (r) ->
return unless @resources[r.rid]
@failed = true
@trigger('failed', resource: r)
r.clean()

View file

@ -5,3 +5,17 @@ module.exports = class TrialRequest extends CocoModel
@className: 'TrialRequest'
@schema: schema
urlRoot: '/db/trial.request'
nameString: ->
props = @get('properties')
values = _.filter(_.at(props, 'name', 'email'))
return values.join(' / ')
locationString: ->
props = @get('properties')
values = _.filter(_.at(props, 'city', 'state', 'country'))
return values.join(' ')
educationLevelString: ->
levels = @get('properties').educationLevel or []
return levels.join(', ')

View file

@ -118,6 +118,9 @@ _.extend CampaignSchema.properties, {
campaign: c.shortString title: 'Campaign', description: 'Which campaign this level is part of (like "desert").', format: 'hidden' # Automatically set by campaign editor.
campaignIndex: c.int title: 'Campaign Index', description: 'The 0-based index of this level in its campaign.', format: 'hidden' # Automatically set by campaign editor.
scoreTypes: c.array {title: 'Score Types', description: 'What metric to show leaderboards for.', uniqueItems: true},
c.shortString(title: 'Score Type', 'enum': ['time', 'damage-taken', 'damage-dealt', 'gold-collected', 'difficulty']) # TODO: good version of LoC; total gear value.
tasks: c.array {title: 'Tasks', description: 'Tasks to be completed for this level.'}, c.task
concepts: c.array {title: 'Programming Concepts', description: 'Which programming concepts this level covers.'}, c.concept

View file

@ -254,6 +254,7 @@ LevelSchema = c.object {
'default':
name: 'Ineffable Wizardry'
description: 'This level is indescribably flarmy.'
tasks: (name: t, complete: false for t in defaultTasks)
documentation: {}
scripts: []
thangs: []

View file

@ -0,0 +1,15 @@
#loading-error
padding: 20px
.btn
margin-top: 20px
.login-btn
margin-right: 10px
#not-found-img
max-width: 20%
margin: 20px 0
#links-row
margin-top: 50px

View file

@ -0,0 +1,3 @@
#artisan-guide-modal
.centered-stack
text-align: center

View file

@ -0,0 +1,19 @@
#editor-level-tasks-tab-view
td
cursor: pointer
.task-check
width: 5em
.task-check, .task-check *
margin: auto
text-align: center
.edit-cell
width: 5em
.edit-cell, .edit-cell *
margin: auto
text-align: center
.task-name
margin: auto
.start-edit
cursor: pointer
.no-article
color: rgba(160, 0, 0, 1)

View file

@ -280,7 +280,7 @@ $gameControlMargin: 30px
opacity: 1
padding: 3px 9px
&.complete
&.shows-leaderboard
.start-level, .view-solutions
min-width: calc(50% - 5px)
display: inline-block

View file

@ -0,0 +1,33 @@
#request-quote-view
label
margin-bottom: 2px
.row
margin: 10px 0
.help-block
margin: 0
p
margin: 0 0 20px
hr
margin: 30px 0
.checkbox, .checkbox-inline
margin: 0
#anything-else-row
margin: 50px 0 20px
#other-education-level-input
display: inline-block
width: 200px
margin-left: 5px
#submit-request-btn
margin-left: 10px
#login-btn
margin-right: 10px

View file

@ -18,9 +18,9 @@ block content
th Applicant
th School
th Location
th Age
th Age / Level
th Students
th How Found
th How Found / Notes
th Status
tbody
- var numReviewed = 0
@ -35,13 +35,14 @@ block content
td.reviewed
if trialRequest.get('reviewDate')
span= trialRequest.get('reviewDate').substring(0, 10)
- var props = trialRequest.get('properties')
td
a(href="/user/#{trialRequest.get('applicant')}")= trialRequest.get('properties').email
td= trialRequest.get('properties').school
td= trialRequest.get('properties').location
td= trialRequest.get('properties').age
td= trialRequest.get('properties').numStudents
td= trialRequest.get('properties').heardAbout
a(href="/user/#{trialRequest.get('applicant')}")= trialRequest.nameString()
td= props.school || props.organization
td= props.location || trialRequest.locationString()
td= props.age || trialRequest.educationLevelString()
td= props.numStudents
td= props.heardAbout || props.notes
td.status-cell
if trialRequest.get('status') === 'submitted'
button.btn.btn-xs.btn-success.btn-approve(data-trial-request-id=trialRequest.id) Approve

View file

@ -50,7 +50,7 @@
| :
.input-border
if me.get('name')
input#name.input-large.form-control(name="name", type="text", value="#{me.get('name')}")
input#name.input-large.form-control(name="name", type="text", value=me.get('name'))
else
input#name.input-large.form-control(name="name", type="text", value="", placeholder="e.g. Alex W the Skater")
.col-md-6
@ -62,7 +62,7 @@
span(data-i18n="signup.optional") optional
| ):
.input-border
input#school-input.input-large.form-control(name="schoolName", data-i18n="[placeholder]signup.school_name_placeholder")
input#school-input.input-large.form-control(name="schoolName", data-i18n="[placeholder]signup.school_name_placeholder", value=formValues.schoolName || '')
.form-group.checkbox
label.control-label(for="subscribe")
.input-border

View file

@ -1,28 +1,97 @@
.alert.alert-danger.loading-error-alert
span(data-i18n="loading_error.could_not_load") Error loading from server
span (
span(data-i18n="resources.#{name}")
span )
if !responseText
strong(data-i18n="loading_error.connection_failure") Connection failed.
else if status === 401
strong(data-i18n="loading_error.unauthorized") You need to be signed in. Do you have cookies disabled?
else if status === 403
strong(data-i18n="loading_error.forbidden") You do not have the permissions.
else if status === 404
strong(data-i18n="loading_error.not_found") Not found.
else if status === 405
strong(data-i18n="loading_error.not_allowed") Method not allowed.
else if status === 408
strong(data-i18n="loading_error.timeout") Server timeout.
else if status === 409
strong(data-i18n="loading_error.conflict") Resource conflict.
else if status === 422
strong(data-i18n="loading_error.bad_input") Bad input.
else if status >= 500
strong(data-i18n="loading_error.server_error") Server error.
else
strong(data-i18n="loading_error.unknown") Unknown error.
#loading-error.text-center
if jqxhr.status === 401
h1
span.spr 401:
span(data-i18n="loading_error.login_required")
p(data-i18n="loading_error.login_required_desc")
button.login-btn.btn.btn-primary(data-i18n="login.log_in")
button#create-account-btn.btn.btn-primary(data-i18n="login.sign_up")
button.btn.btn-xs.retry-loading-resource(data-i18n="common.retry", data-resource-index=resourceIndex) Retry
button.btn.btn-xs.skip-loading-resource(data-i18n="play_level.skip", data-resource-index=resourceIndex) Skip
// 402 currently not in use. TODO: Set it up
else if jqxhr.status === 402
h2 402: Payment Required
else if jqxhr.status === 403
h1
span.spr 403:
span(data-i18n="loading_error.forbidden") Forbidden
p(data-i18n="loading_error.forbidden_desc")
// this should make no diff... but sometimes the server returns 403 when it should return 401
if !me.isAnonymous()
button#logout-btn.btn.btn-primary(data-i18n="login.log_out")
else if jqxhr.status === 404
h1
span.spr 404:
span(data-i18n="loading_error.not_found")
- var num = Math.floor(Math.random() * 3) + 1;
img#not-found-img(src="/images/pages/not_found/404_#{num}.png")
p(data-i18n="loading_error.not_found_desc")
else if !jqxhr.status
h1(data-i18n="loading_error.connection_failure")
p(data-i18n="loading_error.connection_failure_desc")
else
if jqxhr.status === 408
h1
span.spr 408:
span(data-i18n="loading_error.timeout")
else if jqxhr.status >= 500 && jqxhr.status <= 599
h1
span.spr #{jqxhr.status}:
span(data-i18n="loading_error.server_error")
else
h1(data-i18n="loading_error.unknown")
p(data-i18n="loading_error.general_desc")
#links-row.row
.col-sm-3
ul.list-unstyled
li
strong(data-i18n="common.help")
li
a(href="/", data-i18n="nav.home")
li
a(href=view.forumLink(), data-i18n="nav.forum")
li
a(tabindex=-1, data-toggle="coco-modal", data-target="core/ContactModal", data-i18n="nav.contact")
li
a(href='/community', data-i18n="nav.community")
.col-sm-3
ul.list-unstyled
li
strong(data-i18n="courses.students")
li
a(href="/courses/students", data-i18n="nav.learn_to_code")
if me.isAnonymous()
li
a.login-btn(data-i18n="login.log_in")
li
a(href="/courses", data-i18n="courses.join_class")
.col-sm-3
ul.list-unstyled
li
strong(data-i18n="nav.teachers")
li
a(href="/schools", data-i18n="about.why_codecombat")
if me.isAnonymous()
li
a.login-btn(data-i18n="login.log_in")
li
a(href="/courses/teachers", data-i18n="nav.create_a_class")
.col-sm-3
ul.list-unstyled
li
strong(data-i18n="nav.other")
li
a(href="http://blog.codecombat.com/", data-i18n="nav.blog")
li
a(href="https://www.facebook.com/codecombat", data-i18n="nav.facebook")
li
a(href="https://twitter.com/codecombat", data-i18n="nav.twitter")

View file

@ -43,7 +43,7 @@ block content
span.spl(data-i18n="courses.educator_wiki_suff")
li
span.spr(data-i18n="courses.additional_resources_2_pref")
a(href='/teachers/freetrial', data-i18n="teachers_survey.title")
a(href='/teachers/quote', data-i18n="teachers_quote.name")
span.spl(data-i18n="courses.additional_resources_2_suff")
li
span.spr(data-i18n="courses.additional_resources_3_pref")

View file

@ -27,6 +27,8 @@ block header
a(href="#editor-level-components-tab-view", data-toggle="tab", data-i18n="editor.level_tab_components")#components-tab Components
li
a(href="#systems-tab-view", data-toggle="tab", data-i18n="editor.level_tab_systems") Systems
li
a(href="#editor-level-tasks-tab-view", data-toggle="tab", data-i18n="editor.level_tab_tasks")#tasks-tab= "Tasks" + " " + view.getTaskCompletionRatio()
li
a(href="#editor-level-patches", data-toggle="tab")#patches-tab
span(data-i18n="resources.patches").spr Patches
@ -50,6 +52,9 @@ block header
li#redo-button
a
span.glyphicon-arrow-right.glyphicon
li#artisan-guide-button
a
span.glyphicon-book.glyphicon
if authorized
li#commit-level-start-button
a
@ -125,6 +130,8 @@ block outer_content
div.tab-pane#systems-tab-view
div.tab-pane#editor-level-tasks-tab-view
div.tab-pane#editor-level-patches
.patches-view

View file

@ -0,0 +1,42 @@
extends /templates/core/modal-base
block modal-header-content
h3 Artisan Compendium
block modal-body-content
p
| Welcome to the Artisan Compendium. Below you will find a series of helpful guides and tutorials for getting your levels to Master Artisan quality
if view.creator === view.meID
|, as well as a way to submit your level for official Artisan review
|! If you have any feedback on the Level Editor, please contact us at:
a(href='mailto:artisans@codecombat.com') artisans@codecombat.com
div.centered-stack
div
a(href='https://github.com/codecombat/codecombat/wiki/Artisan-Home', target='_blank') Wiki Homepage
div
a(href='https://github.com/codecombat/codecombat/wiki/Artisan-How-To-Index', target='_blank') Basic How-tos
div
a(href='http://direct.codecombat.com/community', target='_blank') Artisan Rankings
if view.creator === view.meID
h4 Level Submission
p
| Do you want your level to be added to the campaign? Please take a moment to fill out the questions below! Dont worry, this isnt a timed quiz. It is just a way for the artisans at CodeCombat HQ to get a feel for the purpose of this level. If it doesnt quite yet meet our standards for release we will give you feedback to help polish it further!
.form
.form-group
label.control-label(for='credit-name') How would you like to be credited?
input#credit-name.form-control(name='creditName')
.form-group
label.control-label(for='level-purpose') What is the purpose of this level?
textarea#level-purpose.form-control(name='levelPurpose', rows=4)
.form-group
label.control-label(for='level-inspiration') What was the inspiration for the level?
textarea#level-inspiration.form-control(name='levelInspiration', rows=4)
.form-group
label.control-label(for='level-location') Where in the campaign do you think this level belongs?
textarea#level-location.form-control(name='levelLocation', rows=4)
block modal-footer-content
div
a(href='#', data-dismiss="modal", aria-hidden="true").btn Close
if view.creator === view.meID
button.btn.btn-primary#level-submit Submit

View file

@ -0,0 +1,44 @@
mixin task-row(cid)
- var task = view.getTaskByCID(cid)
- var taskName = task.get('name');
- var isComplete = task.get('complete')
- var taskLink = view.defaultTaskLinks[taskName]
tr.task-row(data-task-cid=cid)
td.task-check
div.checkbox
input(type='checkbox', checked=(isComplete || false)).task-input
if task.get('curEdit') == true
td.edit-cell
td.task-name
input(type="input", value=taskName)#cur-edit
else
td.edit-cell
span.glyphicon.glyphicon-edit.start-edit
td.task-name
if taskLink
if taskLink === './'
a.no-article(href='https://github.com/codecombat/codecombat/wiki/Artisan-Home', target='blank')= taskName
else
a(href=taskLink, target='_blank')= taskName
else
span= taskName
block
table.table.table-striped.table-hover
tr
th.task-check Complete
th.edit-cell Edit
th Incomplete Tasks
for task in (view.taskArray() || [])
if task.get('revert').complete !== true
+task-row(task.cid)
tr
th.task-check
th.edit-cell
th Completed Tasks
for task in (view.taskArray() || [])
if task.get('revert').complete === true
+task-row(task.cid)
button#create-task.btn.btn-primary Add Task
if view.missingDefaults().length !== 0
button#add-default-tasks.btn.btn-default Add Default Tasks

View file

@ -30,7 +30,9 @@ if campaign
- var playCount = levelPlayCountMap[level.slug]
.progress.progress-striped.active.hide
.progress-bar(style="width: 100%")
div(class="level-info " + (levelStatusMap[level.slug] || "") + (level.requiresSubscription ? " premium" : ""))
- var showsLeaderboard = levelStatusMap[level.slug] === 'complete' && ((level.scoreTypes && level.scoreTypes.length) || ['hero-ladder', 'course-ladder'].indexOf(level.type) !== -1);
div(class="level-info " + (levelStatusMap[level.slug] || "") + (level.requiresSubscription ? " premium" : "") + (showsLeaderboard ? " shows-leaderboard" : ""))
.level-status
h3= i18n(level, 'name') + (level.disabled ? " (Coming soon!)" : (level.locked ? " (Locked)" : ""))
- var description = i18n(level, 'description') || level.description || ""
@ -53,7 +55,7 @@ if campaign
span(data-i18n="play.players") players
span.spr , #{Math.round(playCount.playtime / 3600)}
span(data-i18n="play.hours_played") hours played
if levelStatusMap[level.slug] === 'complete'
if showsLeaderboard
button.btn.btn-warning.btn.btn-lg.btn-illustrated.view-solutions(data-level-slug=level.slug)
span(data-i18n="leaderboard.scores")
button.btn.btn-success.btn.btn-lg.btn-illustrated.start-level(data-i18n="common.play") Play

View file

@ -0,0 +1,150 @@
extends /templates/base
block content
form.form(class=view.trialRequest.isNew() ? '' : 'hide')
h1.text-center(data-i18n="teachers_quote.title")
p.text-center(data-i18n="teachers_quote.subtitle")
.row
.col-sm-offset-2.col-sm-4
.form-group
label.control-label(data-i18n="general.name")
input.form-control(name="name")
.col-sm-4
.form-group
label.control-label(data-i18n="general.email")
input.form-control(name="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
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
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
.checkbox-inline
label.control-label
input#other-education-level-checkbox(type="checkbox")
span(data-i18n="nav.other")
br
span(data-i18n="teachers_quote.please_explain")
input#other-education-level-input.form-control
.row
.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
.col-sm-offset-2.col-sm-8
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' : '')
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
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

@ -7,9 +7,9 @@ block content
br
br
.text-right
button.btn-contact-us(href='/teachers/freetrial')
button.btn-contact-us(href='/teachers/quote')
img(src='/images/pages/sales/chat_icon.png')
div contact us for pricing and a free trial
div contact us for a quote
table
tr
@ -216,5 +216,5 @@ block content
br
p.text-center
button.btn-contact-us contact us for a free trial
button.btn-contact-us contact us for a quote
br

View file

@ -6,10 +6,17 @@ ol.breadcrumb
a(href=path.url)= path.name
li.active= currentFolder
.well.pull-left#test-wrapper
#test-wrapper.well.pull-left
#demo-area
#testing-area
.nav.nav-pills.nav-stacked.pull-right.well#test-nav
if view.demosOn
button#hide-demos-btn.btn.btn-danger.btn-block Hide Demos
else
button#show-demos-btn.btn.btn-info.btn-block Show Demos
hr
for child in children
li(class=child.type)
a(href=child.url).small

View file

@ -0,0 +1,96 @@
RootView = require 'views/core/RootView'
forms = require 'core/forms'
TrialRequest = require 'models/TrialRequest'
TrialRequests = require 'collections/TrialRequests'
AuthModal = require 'views/core/AuthModal'
formSchema = {
type: 'object'
required: ['name', 'email', 'organization', 'role', 'numStudents']
properties:
name: { type: 'string', minLength: 1 }
email: { type: 'string', format: 'email' }
phoneNumber: { type: 'string' }
role: { type: 'string' }
organization: { type: 'string' }
city: { type: 'string' }
state: { type: 'string' }
country: { type: 'string' }
numStudents: { type: 'string' }
educationLevel: {
type: 'array'
items: { type: 'string' }
}
notes: { type: 'string' }
}
module.exports = class RequestQuoteView extends RootView
id: 'request-quote-view'
template: require 'templates/request-quote-view'
events:
'submit form': 'onSubmitForm'
'click #login-btn': 'onClickLoginButton'
'click #signup-btn': 'onClickSignupButton'
initialize: ->
@trialRequest = new TrialRequest()
@trialRequests = new TrialRequests()
@trialRequests.fetchOwn()
@supermodel.loadCollection(@trialRequests)
onLoaded: ->
if @trialRequests.size()
@trialRequest = @trialRequests.first()
super()
onSubmitForm: (e) ->
e.preventDefault()
form = @$('form')
attrs = forms.formToObject(form)
if @$('#other-education-level-checkbox').is(':checked')
attrs.educationLevel.push(@$('#other-education-level-input').val())
forms.clearFormAlerts(form)
result = tv4.validateMultiple(attrs, formSchema)
if not result.valid
return forms.applyErrorsToForm(form, result.errors)
if not /^.+@.+\..+$/.test(attrs.email)
return forms.setErrorToProperty(form, 'email', 'Invalid email.')
if not _.size(attrs.educationLevel)
return forms.setErrorToProperty(form, 'educationLevel', 'Check at least one.')
@trialRequest = new TrialRequest({
type: 'course'
properties: attrs
})
@$('#submit-request-btn').text('Sending').attr('disabled', true)
@trialRequest.save()
@trialRequest.on 'sync', @onTrialRequestSubmit, @
@trialRequest.on 'error', @onTrialRequestError, @
onTrialRequestError: ->
@$('#submit-request-btn').text('Submit').attr('disabled', false)
onTrialRequestSubmit: ->
@$('form, #form-submit-success').toggleClass('hide')
onClickLoginButton: ->
modal = new AuthModal({
mode: 'login'
initialValues: { email: @trialRequest.get('properties')?.email }
})
@openModalView(modal)
window.nextURL = '/courses/teachers' unless @trialRequest.isNew()
onClickSignupButton: ->
props = @trialRequest.get('properties') or {}
me.set('name', props.name)
modal = new AuthModal({
mode: 'signup'
initialValues: {
email: props.email
schoolName: props.organization
}
})
@openModalView(modal)
window.nextURL = '/courses/teachers' unless @trialRequest.isNew()

View file

@ -17,7 +17,7 @@ module.exports = class SalesView extends RootView
'CodeCombat'
onClickContactUs: (e) ->
app.router.navigate '/teachers/freetrial', trigger: true
app.router.navigate '/teachers/quote', trigger: true
onClickLogin: (e) ->
@openModalView new AuthModal(mode: 'login') if me.get('anonymous')

View file

@ -1,6 +1,7 @@
RootView = require 'views/core/RootView'
template = require 'templates/test-view'
requireUtils = require 'lib/requireUtils'
storage = require 'core/storage'
require 'vendor/jasmine-bundle'
require 'tests'
@ -14,18 +15,32 @@ module.exports = TestView = class TestView extends RootView
reloadOnClose: true
loadedFileIDs: []
events:
'click #show-demos-btn': 'onClickShowDemosButton'
'click #hide-demos-btn': 'onClickHideDemosButton'
# INITIALIZE
constructor: (options, @subPath='') ->
super(options)
initialize: (options, @subPath='') ->
@subPath = @subPath[1..] if @subPath[0] is '/'
@demosOn = storage.load('demos-on')
afterInsert: ->
@initSpecFiles()
@render()
TestView.runTests(@specFiles)
TestView.runTests(@specFiles, @demosOn)
window.runJasmine()
# EVENTS
onClickShowDemosButton: ->
storage.save('demos-on', true)
document.location.reload()
onClickHideDemosButton: ->
storage.remove('demos-on')
document.location.reload()
# RENDER DATA
getRenderData: ->
@ -44,8 +59,22 @@ module.exports = TestView = class TestView extends RootView
prefix = TEST_REQUIRE_PREFIX + @subPath
@specFiles = (f for f in @specFiles when _.string.startsWith f, prefix)
@runTests: (specFiles) ->
@runTests: (specFiles, demosOn=false) ->
specFiles ?= @getAllSpecFiles()
if demosOn
jasmine.demoEl = ($el) ->
$el.css({
'border': '2px solid black'
'background': 'white'
'padding': '20px'
})
$('#demo-area').append($el)
jasmine.demoModal = _.once (modal) ->
currentView.openModalView(modal)
else
jasmine.demoEl = _.noop
jasmine.demoModal = _.noop
describe 'CodeCombat Client', =>
jasmine.Ajax.install()
beforeEach ->

View file

@ -30,6 +30,7 @@ module.exports = class AuthModal extends ModalView
@onNameChange = _.debounce @checkNameExists, 500
super options
@mode = options.mode if options.mode
@previousFormInputs = options.initialValues or {}
getRenderData: ->
c = super()

View file

@ -3,6 +3,7 @@ utils = require 'core/utils'
CocoClass = require 'core/CocoClass'
loadingScreenTemplate = require 'templates/core/loading'
loadingErrorTemplate = require 'templates/core/loading-error'
auth = require 'core/auth'
lastToggleModalCall = 0
visibleModal = null
@ -16,8 +17,9 @@ module.exports = class CocoView extends Backbone.View
template: -> ''
events:
'click .retry-loading-resource': 'onRetryResource'
'click .skip-loading-resource': 'onSkipResource'
'click #loading-error .login-btn': 'onClickLoadingErrorLoginButton'
'click #loading-error #create-account-btn': 'onClickLoadingErrorCreateAccountButton'
'click #loading-error #logout-btn': 'onClickLoadingErrorLogoutButton'
subscriptions: {}
shortcuts: {}
@ -156,44 +158,27 @@ module.exports = class CocoView extends Backbone.View
# Error handling for loading
onResourceLoadFailed: (e) ->
r = e.resource
@stopListening @supermodel
return if r.jqxhr?.status is 402 # payment-required failures are handled separately
if r.jqxhr?.status is 0
r.retries ?= 0
r.retries += 1
if r.retries > 20
msg = 'Your computer or our servers appear to be offline. Please try refreshing.'
noty text: msg, layout: 'center', type: 'error', killer: true
return
else
@warnConnectionError()
return _.delay (=> r.load()), 3000
@$el.find('.loading-container .errors').append(loadingErrorTemplate({
status: r.jqxhr?.status
name: r.name
resourceIndex: r.rid,
responseText: r.jqxhr?.responseText
})).i18n()
@$el.find('.progress').hide()
@showError(r.jqxhr)
warnConnectionError: ->
msg = $.i18n.t 'loading_error.connection_failure', defaultValue: 'Connection failed.'
noty text: msg, layout: 'center', type: 'error', killer: true, timeout: 3000
onRetryResource: (e) ->
res = @supermodel.getResource($(e.target).data('resource-index'))
# different views may respond to this call, and not all have the resource to reload
return unless res and res.isFailed
res.load()
@$el.find('.progress').show()
$(e.target).closest('.loading-error-alert').remove()
onClickLoadingErrorLoginButton: (e) ->
e.stopPropagation() # Backbone subviews and superviews will handle this call repeatedly otherwise
AuthModal = require 'views/core/AuthModal'
@openModalView(new AuthModal({mode: 'login'}))
onSkipResource: (e) ->
res = @supermodel.getResource($(e.target).data('resource-index'))
return unless res and res.isFailed
res.markLoaded()
@$el.find('.progress').show()
$(e.target).closest('.loading-error-alert').remove()
onClickLoadingErrorCreateAccountButton: (e) ->
e.stopPropagation()
AuthModal = require 'views/core/AuthModal'
@openModalView(new AuthModal({mode: 'signup'}))
onClickLoadingErrorLogoutButton: (e) ->
e.stopPropagation()
auth.logoutUser()
# Modals
@ -255,6 +240,23 @@ module.exports = class CocoView extends Backbone.View
@_lastLoading.find('>').removeClass('hidden')
@_lastLoading = null
showError: (jqxhr) ->
return unless @_lastLoading?
context = {
jqxhr: jqxhr
view: @
me: me
}
@_lastLoading.find('.loading-screen').replaceWith((loadingErrorTemplate(context)))
@_lastLoading.i18n()
forumLink: ->
link = 'http://discourse.codecombat.com/'
lang = (me.get('preferredLanguage') or 'en-US').split('-')[0]
if lang in ['zh', 'ru', 'es', 'fr', 'pt', 'de', 'nl', 'lt']
link += "c/other-languages/#{lang}"
link
showReadOnly: ->
return if me.isAdmin() or me.isArtisan()
warning = $.i18n.t 'editor.read_only_warning2', defaultValue: 'Note: you can\'t save any edits here, because you\'re not logged in.'

View file

@ -100,13 +100,6 @@ module.exports = class RootView extends CocoView
c.usesSocialMedia = @usesSocialMedia
c
forumLink: ->
link = 'http://discourse.codecombat.com/'
lang = (me.get('preferredLanguage') or 'en-US').split('-')[0]
if lang in ['zh', 'ru', 'es', 'fr', 'pt', 'de', 'nl', 'lt']
link += "c/other-languages/#{lang}"
link
afterRender: ->
if @$el.find('#site-nav').length # hack...
@$el.addClass('site-chrome')

View file

@ -32,23 +32,23 @@ module.exports = class ClassroomView extends RootView
initialize: (options, classroomID) ->
return if me.isAnonymous()
@classroom = new Classroom({_id: classroomID})
@supermodel.loadModel @classroom, 'classroom'
@supermodel.loadModel @classroom
@courses = new CocoCollection([], { url: "/db/course", model: Course})
@courses.comparator = '_id'
@supermodel.loadCollection(@courses, 'courses')
@supermodel.loadCollection(@courses)
@campaigns = new CocoCollection([], { url: "/db/campaign", model: Campaign })
@courses.comparator = '_id'
@supermodel.loadCollection(@campaigns, 'campaigns', { data: { type: 'course' }})
@supermodel.loadCollection(@campaigns, { data: { type: 'course' }})
@courseInstances = new CocoCollection([], { url: "/db/course_instance", model: CourseInstance})
@courseInstances.comparator = 'courseID'
@supermodel.loadCollection(@courseInstances, 'course_instances', { data: { classroomID: classroomID } })
@supermodel.loadCollection(@courseInstances, { data: { classroomID: classroomID } })
@prepaids = new Prepaids()
@prepaids.comparator = '_id'
@prepaids.fetchByCreator(me.id)
@supermodel.loadCollection(@prepaids, 'prepaids')
@supermodel.loadCollection(@prepaids)
@users = new CocoCollection([], { url: "/db/classroom/#{classroomID}/members", model: User })
@users.comparator = (user) => user.broadName().toLowerCase()
@supermodel.loadCollection(@users, 'users')
@supermodel.loadCollection(@users)
@listenToOnce @courseInstances, 'sync', @onCourseInstancesSync
@sessions = new CocoCollection([], { model: LevelSession })
@ -56,7 +56,7 @@ module.exports = class ClassroomView extends RootView
@sessions = new CocoCollection([], { model: LevelSession })
for courseInstance in @courseInstances.models
sessions = new CocoCollection([], { url: "/db/course_instance/#{courseInstance.id}/level_sessions", model: LevelSession })
@supermodel.loadCollection(sessions, 'sessions', { data: { project: ['level', 'playtime', 'creator', 'changed', 'state.complete'].join(' ') } })
@supermodel.loadCollection(sessions, { data: { project: ['level', 'playtime', 'creator', 'changed', 'state.complete'].join(' ') } })
courseInstance.sessions = sessions
sessions.courseInstance = courseInstance
courseInstance.sessionsByUser = {}

View file

@ -31,13 +31,13 @@ module.exports = class CoursesView extends RootView
@courseInstances = new CocoCollection([], { url: "/db/user/#{me.id}/course_instances", model: CourseInstance})
@courseInstances.comparator = (ci) -> return ci.get('classroomID') + ci.get('courseID')
@listenToOnce @courseInstances, 'sync', @onCourseInstancesLoaded
@supermodel.loadCollection(@courseInstances, 'course_instances')
@supermodel.loadCollection(@courseInstances)
@classrooms = new CocoCollection([], { url: "/db/classroom", model: Classroom })
@supermodel.loadCollection(@classrooms, 'classrooms', { data: {memberID: me.id} })
@supermodel.loadCollection(@classrooms, { data: {memberID: me.id} })
@courses = new CocoCollection([], { url: "/db/course", model: Course})
@supermodel.loadCollection(@courses, 'courses')
@supermodel.loadCollection(@courses)
@campaigns = new CocoCollection([], { url: "/db/campaign", model: Campaign })
@supermodel.loadCollection(@campaigns, 'campaigns', { data: { type: 'course' }})
@supermodel.loadCollection(@campaigns, { data: { type: 'course' }})
onCourseInstancesLoaded: ->
map = {}
@ -51,7 +51,7 @@ module.exports = class CoursesView extends RootView
model: LevelSession
})
courseInstance.sessions.comparator = 'changed'
@supermodel.loadCollection(courseInstance.sessions, 'sessions', { data: { project: 'state.complete level.original playtime changed' }})
@supermodel.loadCollection(courseInstance.sessions, { data: { project: 'state.complete level.original playtime changed' }})
@hocCourseInstance = @courseInstances.findWhere({hourOfCode: true})
if @hocCourseInstance

View file

@ -15,7 +15,9 @@ SettingsTabView = require './settings/SettingsTabView'
ScriptsTabView = require './scripts/ScriptsTabView'
ComponentsTabView = require './components/ComponentsTabView'
SystemsTabView = require './systems/SystemsTabView'
TasksTabView = require './tasks/TasksTabView'
SaveLevelModal = require './modals/SaveLevelModal'
ArtisanGuideModal = require './modals/ArtisanGuideModal'
ForkModal = require 'views/editor/ForkModal'
SaveVersionModal = require 'views/editor/modal/SaveVersionModal'
PatchesView = require 'views/editor/PatchesView'
@ -56,6 +58,7 @@ module.exports = class LevelEditView extends RootView
'mouseenter #redo-button': 'showRedoDescription'
'click #patches-tab': -> @patchesView.load()
'click #components-tab': -> @subviews.editor_level_components_tab_view.refreshLevelThangsTreema @level.get('thangs')
'click #artisan-guide-button': 'showArtisanGuide'
'click #level-patch-button': 'startPatchingLevel'
'click #level-watch-button': 'toggleWatchLevel'
'click li:not(.disabled) > #pop-level-i18n-button': 'onPopulateI18N'
@ -105,11 +108,13 @@ module.exports = class LevelEditView extends RootView
@insertSubView new ScriptsTabView world: @world, supermodel: @supermodel, files: @files
@insertSubView new ComponentsTabView supermodel: @supermodel
@insertSubView new SystemsTabView supermodel: @supermodel, world: @world
@insertSubView new TasksTabView world: @world, supermodel: @supermodel, level: @level
@insertSubView new RelatedAchievementsView supermodel: @supermodel, level: @level
@insertSubView new ComponentsDocumentationView lazy: true # Don't give it the supermodel, it'll pollute it!
@insertSubView new SystemsDocumentationView lazy: true # Don't give it the supermodel, it'll pollute it!
@insertSubView new LevelFeedbackView level: @level
Backbone.Mediator.publish 'editor:level-loaded', level: @level
@showReadOnly() if me.get('anonymous')
@patchesView = @insertSubView(new PatchesView(@level), @$el.find('.patches-view'))
@ -170,6 +175,10 @@ module.exports = class LevelEditView extends RootView
@openModalView new SaveLevelModal level: @level, supermodel: @supermodel, buildTime: @levelBuildTime
Backbone.Mediator.publish 'editor:view-switched', {}
showArtisanGuide: (e) ->
@openModalView new ArtisanGuideModal level: @level
Backbone.Mediator.publish 'editor:view-switched', {}
startForking: (e) ->
@openModalView new ForkModal model: @level, editorPath: 'level'
Backbone.Mediator.publish 'editor:view-switched', {}
@ -210,3 +219,9 @@ module.exports = class LevelEditView extends RootView
return if application.userIsIdle
@levelBuildTime ?= @level.get('buildTime') ? 0
++@levelBuildTime
getTaskCompletionRatio: ->
if not @level.get('tasks')?
return '0/0'
else
return _.filter(@level.get('tasks'), (_elem) -> return _elem.complete).length + '/' + @level.get('tasks').length

View file

@ -0,0 +1,48 @@
ModalView = require 'views/core/ModalView'
template = require 'templates/editor/level/modal/artisan-guide-modal'
forms = require 'core/forms'
{sendContactMessage} = require 'core/contact'
contactSchema =
additionalProperties: false
required: ['creditName', 'levelPurpose', 'levelInspiration', 'levelLocation']
properties:
creditName:
type: 'string'
levelPurpose:
type: 'string'
levelInspiration:
type: 'string'
levelLocation:
type: 'string'
module.exports = class ArtisanGuideModal extends ModalView
id: 'artisan-guide-modal'
template: template
events:
'click #level-submit': 'levelSubmit'
initialize: (options) ->
@level = options.level
@options = level: @level.get 'name'
@creator = @level.get 'creator'
@meID = me.id
levelSubmit: ->
@playSound 'menu-button-click'
forms.clearFormAlerts @$el
contactMessage = forms.formToObject @$el
res = tv4.validateMultiple contactMessage, contactSchema
return forms.applyErrorsToForm @$el, res.errors unless res.valid
@populateBrowserData contactMessage
contactMessage = _.merge contactMessage, @options
contactMessage.country = me.get('country')
sendContactMessage contactMessage, @$el
$.post "/db/user/#{me.id}/track/contact_codecombat"
populateBrowserData: (context) ->
if $.browser
context.browser = "#{$.browser.platform} #{$.browser.name} #{$.browser.versionNumber}"
context.screenSize = "#{screen?.width ? $(window).width()} x #{screen?.height ? $(window).height()}"
context.screenshotURL = @screenshotURL

View file

@ -15,7 +15,7 @@ module.exports = class SettingsTabView extends CocoView
editableSettings: [
'name', 'description', 'documentation', 'nextLevel', 'background', 'victory', 'i18n', 'icon', 'goals',
'type', 'terrain', 'showsGuide', 'banner', 'employerDescription', 'loadingTip', 'requiresSubscription',
'tasks', 'helpVideos', 'replayable', 'scoreTypes', 'concepts'
'helpVideos', 'replayable', 'scoreTypes', 'concepts'
]
subscriptions:

View file

@ -0,0 +1,183 @@
CocoView = require 'views/core/CocoView'
template = require 'templates/editor/level/tasks-tab'
Level = require 'models/Level'
module.exports = class TasksTabView extends CocoView
id: 'editor-level-tasks-tab-view'
className: 'tab-pane'
template: template
events:
'click .task-row': 'onClickTaskRow'
'click .task-input': 'onClickTaskInput'
'click .start-edit': 'onClickStartEdit'
'click #create-task': 'onClickCreateTask'
'keydown #cur-edit': 'onKeyDownCurEdit'
'blur #cur-edit': 'onBlurCurEdit'
'click #add-default-tasks': 'onClickAddDefaultTasks'
subscriptions:
'editor:level-loaded': 'onLevelLoaded'
defaultTaskLinks:
# Order doesn't matter.
'Name the level.':'./'
'Create a Referee stub, if needed.':'./'
'Build the level.':'./'
'Set up goals.':'./'
'Choose the Existence System lifespan and frame rate.':'./'
'Choose the UI System paths and coordinate hover if needed.':'./'
'Choose the AI System pathfinding and Vision System line of sight.':'./'
'Write the sample code.':'./'
'Do basic set decoration.':'./'
'Adjust script camera bounds.':'./'
'Choose music file in Introduction script.':'./'
'Choose autoplay in Introduction script.':'./'
'Add to a campaign.':'./'
'Publish.':'./'
'Choose level options like required/restricted gear.':'./'
'Create achievements, including unlocking next level.':'./'
'Choose leaderboard score types.':'./'
'Playtest with a slow/tough hero.':'./'
'Playtest with a fast/weak hero.':'./'
'Playtest with a couple random seeds.':'./'
'Make sure the level ends promptly on success and failure.':'./'
'Remove/simplify unnecessary doodad collision.':'./'
'Release to adventurers via MailChimp.':'./'
'Write the description.':'./'
'Add i18n field for the sample code comments.':'./'
'Add Clojure/Lua/CoffeeScript.':'./'
'Write the guide.':'./'
'Write a loading tip, if needed.':'./'
'Click the Populate i18n button.':'./'
'Add programming concepts covered.':'./'
'Mark whether it requires a subscription.':'./'
'Release to everyone via MailChimp.':'./'
'Check completion/engagement/problem analytics.':'./'
'Do thorough set decoration.':'./'
'Add a walkthrough video.':'./'
missingDefaults: ->
missingTasks = []
if @level
for task in @level.schema().properties.tasks.default
unless _.findIndex(@level.get('tasks'), {name: task.name}) isnt -1
missingTasks.push task
return missingTasks
onClickAddDefaultTasks: ->
results = @missingDefaults()
for result in results
@tasks.add
name: result.name
complete: result.complete
curEdit: false
revert:
name: result.name
complete: false
@pushTasks()
@render()
applyTaskName: (_task, _input) ->
name = _input.value
potentialTask = @tasks.findWhere({'name':_input})
if potentialTask and potentialTask isnt _task
noty
timeout: 5000
text: 'Task with name already exists!'
type: 'error'
layout: 'topCenter'
_input.focus()
else if name is ''
@tasks.remove _task
@pushTasks()
@render()
else
_task.set 'name', name
_task.set 'curEdit', false
@pushTasks()
@render()
focusEditInput: ->
editInput = @$el.find('#cur-edit')[0]
if editInput
editInput.focus()
len = editInput.value.length * 2
editInput.setSelectionRange len, len
getTaskByCID: (_cid) ->
return @tasks.get _cid
taskMap: ->
return @tasks?.map((_obj) -> return (name: _obj.get('name'), complete: (_obj.get('complete') || false)))
taskArray: ->
return @tasks?.toArray()
onLevelLoaded: (e) ->
@level = e.level
Task = Backbone.Model.extend({
initialize: ->
# We want to keep track of the revertAttributes easily without digging back into the level every time.
# So per TaskModel we check to see if there is a revertAttribute associated with the task's name.
# If there is a reversion available, we use it, otherwise (e.g. new tasks without a reversion) we just use the Task's current name/completion status.
if e?.level?._revertAttributes?.tasks?
if _.find(e.level._revertAttributes.tasks, {name:arguments[0].name})
@set 'revert', _.find(e.level._revertAttributes.tasks, {name:arguments[0].name})
else
@set 'revert', arguments[0]
else
@set 'revert', arguments[0]
})
TaskList = Backbone.Collection.extend({
model: Task
})
@tasks = new TaskList(@level.get 'tasks')
@render()
pushTasks: ->
@level.set 'tasks', @taskMap()
onClickTaskRow: (e) ->
if not @$el.find(e.target).is('input') and not @$el.find(e.target).is('a') and not @$el.find(e.target).hasClass('start-edit') and @$el.find('#cur-edit').length is 0
task = @tasks.get @$el.find(e.target).closest('tr').data('task-cid')
checkbox = @$el.find(e.currentTarget).find('.task-input')[0]
if task.get 'complete'
task.set 'complete', false
else
task.set 'complete', true
checkbox.checked = task.get 'complete'
@pushTasks()
onClickTaskInput: (e) ->
task = @tasks.get @$el.find(e.target).closest('tr').data('task-cid')
task.set 'complete', e.currentTarget.checked
@pushTasks()
onClickStartEdit: (e) ->
if @$el.find('#cur-edit').length is 0
task = @tasks.get @$el.find(e.target).closest('tr').data('task-cid')
task.set 'curEdit', true
@render()
@focusEditInput()
onKeyDownCurEdit: (e) ->
if e.keyCode is 13
editInput = @$el.find('#cur-edit')[0]
editInput.blur()
onBlurCurEdit: (e) ->
editInput = @$el.find('#cur-edit')[0]
task = @tasks.get @$el.find(e.target).closest('tr').data('task-cid')
@applyTaskName(task, editInput)
onClickCreateTask: (e) ->
if @$el.find('#cur-edit').length is 0
@tasks.add
name: ''
complete: false
curEdit: true
revert:
name: 'null'
complete: false
@render()
@focusEditInput()

View file

@ -22,6 +22,8 @@ module.exports = class NewModelModal extends ModalView
model = new @modelClass
name = @$el.find('#name').val()
model.set('name', name)
if @modelClass.name is 'Level'
model.set('tasks', @modelClass.schema.default.tasks)
if model.schema().properties.permissions
model.set 'permissions', [{access: 'owner', target: me.id}]
model.set(key, prop) for key, prop of @properties if @properties?

View file

@ -0,0 +1,150 @@
CocoView = require 'views/core/CocoView'
User = require 'models/User'
BlandView = class BlandView extends CocoView
template: ->
return if @specialMessage then '<div id="content">custom message</div>' else '<div id="content">normal message</div>'
initialize: ->
@user1 = new User({_id: _.uniqueId()})
@supermodel.loadModel(@user1)
@user2 = new User({_id: _.uniqueId()})
@supermodel.loadModel(@user2)
onResourceLoadFailed: (e) ->
resource = e.resource
if resource.jqxhr.status is 400 and resource.model is @user1
@specialMessage = true
@render()
else
super(arguments...)
describe 'CocoView', ->
describe 'network error handling', ->
view = null
respond = (code, index=0) ->
view.render()
requests = jasmine.Ajax.requests.all()
requests[index].respondWith({status: code, responseText: JSON.stringify({})})
beforeEach ->
view = new BlandView()
describe 'when the view overrides onResourceLoadFailed', ->
beforeEach ->
view.render()
expect(view.$('#content').hasClass('hidden')).toBe(true)
respond(400)
it 'can show a custom message for a given error and model', ->
expect(view.$('#content').hasClass('hidden')).toBe(false)
expect(view.$('#content').text()).toBe('custom message')
respond(200, 1)
expect(view.$('#content').hasClass('hidden')).toBe(false)
expect(view.$('#content').text()).toBe('custom message')
it '(demo)', -> jasmine.demoEl(view.$el)
describe 'when the server returns 401', ->
beforeEach ->
me.set('anonymous', true)
respond(401)
it 'shows a login button which opens the AuthModal', ->
button = view.$el.find('.login-btn')
expect(button.length).toBe(3) # including the two in the links section
spyOn(view, 'openModalView').and.callFake (modal) -> expect(modal.mode).toBe('login')
button.click()
expect(view.openModalView).toHaveBeenCalled()
it 'shows a create account button which opens the AuthModal', ->
button = view.$el.find('#create-account-btn')
expect(button.length).toBe(1)
spyOn(view, 'openModalView').and.callFake (modal) -> expect(modal.mode).toBe('signup')
button.click()
expect(view.openModalView).toHaveBeenCalled()
it 'says "Login Required"', ->
expect(view.$('[data-i18n="loading_error.login_required"]').length).toBeTruthy()
it '(demo)', -> jasmine.demoEl(view.$el)
describe 'when the server returns 402', ->
beforeEach -> respond(402)
it 'does nothing, because it is up to the view to handle payment next steps'
describe 'when the server returns 403', ->
beforeEach ->
me.set('anonymous', false)
respond(403)
it 'includes a logout button which logs out the account', ->
button = view.$el.find('#logout-btn')
expect(button.length).toBe(1)
button.click()
request = jasmine.Ajax.requests.mostRecent()
expect(request.url).toBe('/auth/logout')
it '(demo)', -> jasmine.demoEl(view.$el)
describe 'when the server returns 404', ->
beforeEach -> respond(404)
it 'includes one of the 404 images', ->
img = view.$el.find('#not-found-img')
expect(img.length).toBe(1)
it '(demo)', -> jasmine.demoEl(view.$el)
describe 'when the server returns 408', ->
beforeEach -> respond(408)
it 'includes "Server Timeout" in the header', ->
expect(view.$('[data-i18n="loading_error.timeout"]').length).toBeTruthy()
it 'shows a message encouraging refreshing the page or following links', ->
expect(view.$('[data-i18n="loading_error.general_desc"]').length).toBeTruthy()
it '(demo)', -> jasmine.demoEl(view.$el)
describe 'when no connection is made', ->
beforeEach ->
respond()
it 'shows "Connection Failed"', ->
expect(view.$('[data-i18n="loading_error.connection_failure"]').length).toBeTruthy()
it '(demo)', -> jasmine.demoEl(view.$el)
describe 'when the server returns any other number >= 400', ->
beforeEach -> respond(9001)
it 'includes "Unknown Error" in the header', ->
expect(view.$('[data-i18n="loading_error.unknown"]').length).toBeTruthy()
it 'shows a message encouraging refreshing the page or following links', ->
expect(view.$('[data-i18n="loading_error.general_desc"]').length).toBeTruthy()
it '(demo)', -> jasmine.demoEl(view.$el)

View file

@ -51,7 +51,7 @@ describe 'CourseVictoryModal', ->
expect(_.size(modal.views)).toBe(1)
expect(modal.views[0] instanceof ProgressView).toBe(true)
xit '(demo)', -> currentView.openModalView(modal)
it '(demo)', -> jasmine.demoModal(modal)
describe 'its ProgressView', ->
it 'has a next level button which navigates to the next level on click', ->
@ -93,7 +93,7 @@ describe 'CourseVictoryModal', ->
button.click()
expect(application.router.navigate).toHaveBeenCalled()
xit '(demo)', -> currentView.openModalView(modal)
it '(demo)', -> jasmine.demoModal(modal)
describe 'given a course level with a new item', ->
@ -121,4 +121,4 @@ describe 'CourseVictoryModal', ->
modal.$el.find('#continue-btn').click()
expect(modal.currentView instanceof ProgressView).toBe(true)
xit '(demo)', -> currentView.openModalView(modal)
it '(demo)', -> jasmine.demoModal(modal)