mirror of
https://github.com/codeninjasllc/codecombat.git
synced 2024-11-24 08:08:15 -05:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
66650452b2
14 changed files with 224 additions and 172 deletions
|
@ -96,6 +96,8 @@ module.exports = class CocoRouter extends Backbone.Router
|
||||||
|
|
||||||
'github/*path': 'routeToServer'
|
'github/*path': 'routeToServer'
|
||||||
|
|
||||||
|
'hoc': go('courses/CoursesView')
|
||||||
|
|
||||||
'i18n': go('i18n/I18NHomeView')
|
'i18n': go('i18n/I18NHomeView')
|
||||||
'i18n/thang/:handle': go('i18n/I18NEditThangTypeView')
|
'i18n/thang/:handle': go('i18n/I18NEditThangTypeView')
|
||||||
'i18n/component/:handle': go('i18n/I18NEditComponentView')
|
'i18n/component/:handle': go('i18n/I18NEditComponentView')
|
||||||
|
|
|
@ -913,7 +913,7 @@
|
||||||
see_the: "See the"
|
see_the: "See the"
|
||||||
more_info: "for more information."
|
more_info: "for more information."
|
||||||
choose_course: "Choose Your Course:"
|
choose_course: "Choose Your Course:"
|
||||||
enter_code: "Enter an unlock code"
|
enter_code: "Enter an unlock code to join an existing class" # {change}
|
||||||
enter_code1: "Enter unlock code"
|
enter_code1: "Enter unlock code"
|
||||||
enroll: "Enroll"
|
enroll: "Enroll"
|
||||||
pick_from_classes: "Pick from your current classes"
|
pick_from_classes: "Pick from your current classes"
|
||||||
|
|
|
@ -304,7 +304,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
|
||||||
tip_morale_improves: "在士气提升之前会一直进行加载。"
|
tip_morale_improves: "在士气提升之前会一直进行加载。"
|
||||||
tip_all_species: "我们相信每一个人都有同等的机会学习编程"
|
tip_all_species: "我们相信每一个人都有同等的机会学习编程"
|
||||||
tip_reticulating: "网格状锯齿。(指Maxis开发的许多游戏,如《模拟城市》、《孢子》中,加载进程中跑动时出现的卡顿现象)"
|
tip_reticulating: "网格状锯齿。(指Maxis开发的许多游戏,如《模拟城市》、《孢子》中,加载进程中跑动时出现的卡顿现象)"
|
||||||
tip_harry: "巫师, "
|
tip_harry: "你是一名巫师, "
|
||||||
tip_great_responsibility: "更强的编程技巧也意味着有更高的责任来进行调试。"
|
tip_great_responsibility: "更强的编程技巧也意味着有更高的责任来进行调试。"
|
||||||
tip_munchkin: "如果您不吃掉您的蔬菜, 一个小矮人将在您睡着之后来找您。"
|
tip_munchkin: "如果您不吃掉您的蔬菜, 一个小矮人将在您睡着之后来找您。"
|
||||||
tip_binary: "这个世界上只有10种人: 那些懂二进制的, 还有那些不懂二进制的。"
|
tip_binary: "这个世界上只有10种人: 那些懂二进制的, 还有那些不懂二进制的。"
|
||||||
|
@ -464,7 +464,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
|
||||||
was_free_until: "您有过一个免费订阅,直到"
|
was_free_until: "您有过一个免费订阅,直到"
|
||||||
managed_subs: "管理订阅"
|
managed_subs: "管理订阅"
|
||||||
managed_subs_desc: "为其他玩家(学生、儿童等)添加订阅。"
|
managed_subs_desc: "为其他玩家(学生、儿童等)添加订阅。"
|
||||||
managed_subs_desc_2: "收件人必须有一个与您提供的电子邮件地址相关联的codecombat帐户。"
|
managed_subs_desc_2: "收件人必须有一个与您提供的电子邮件地址相关联的CodeCombat帐户。"
|
||||||
group_discounts: "团购价"
|
group_discounts: "团购价"
|
||||||
group_discounts_1: "我们还为批量订阅提供团购价"
|
group_discounts_1: "我们还为批量订阅提供团购价"
|
||||||
group_discounts_1st: "1个订阅"
|
group_discounts_1st: "1个订阅"
|
||||||
|
@ -673,7 +673,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
|
||||||
under: "低于"
|
under: "低于"
|
||||||
other: "其他:"
|
other: "其他:"
|
||||||
amount_students: "请问您有多少学生需要教导?"
|
amount_students: "请问您有多少学生需要教导?"
|
||||||
hear_about: "您是怎么知道CodeComabat的?"
|
hear_about: "您是怎么知道CodeCombat的?"
|
||||||
fill_fields: "请填写所有问题。"
|
fill_fields: "请填写所有问题。"
|
||||||
thanks: "非常感谢!我们会很快寄给您设置说明。"
|
thanks: "非常感谢!我们会很快寄给您设置说明。"
|
||||||
|
|
||||||
|
@ -1207,7 +1207,7 @@ module.exports = nativeDescription: "简体中文", englishDescription: "Chinese
|
||||||
recently_played: "最近玩过的关卡"
|
recently_played: "最近玩过的关卡"
|
||||||
no_recent_games: "最近两个星期没有玩过游戏。"
|
no_recent_games: "最近两个星期没有玩过游戏。"
|
||||||
payments: "支付方式"
|
payments: "支付方式"
|
||||||
# prepaid: "Prepaid"
|
prepaid: "预付费"
|
||||||
purchased: "已购买"
|
purchased: "已购买"
|
||||||
sale: "促销"
|
sale: "促销"
|
||||||
subscription: "订阅"
|
subscription: "订阅"
|
||||||
|
|
|
@ -602,7 +602,7 @@ module.exports = nativeDescription: "繁體中文", englishDescription: "Chinese
|
||||||
intro_2: "無需經驗!"
|
intro_2: "無需經驗!"
|
||||||
free_title: "要多少錢?"
|
free_title: "要多少錢?"
|
||||||
cost_china: "CodeCombat的前5個關卡在中國是免費的,在這之後需花費每月9.99美元來訪問我們架設在中國專屬服務器上的190多個關卡。" # Deprecated
|
cost_china: "CodeCombat的前5個關卡在中國是免費的,在這之後需花費每月9.99美元來訪問我們架設在中國專屬服務器上的190多個關卡。" # Deprecated
|
||||||
# cost_premium_server: "CodeCombat is free for the first five levels, after which it costs $9.99 USD per month for access to our other 190+ levels on our exclusive country-specific servers."
|
cost_premium_server: "CodeCombat的前5個關卡在中國是免費的,在這之後需花費每月9.99美元來訪問我們架設在中國專屬服務器上的190多個關卡。"
|
||||||
free_1: "有110多個覆蓋了所有理論的免費關卡。"
|
free_1: "有110多個覆蓋了所有理論的免費關卡。"
|
||||||
free_2: "包月訂閱可以訪問視頻教程和額外的練習關卡。"
|
free_2: "包月訂閱可以訪問視頻教程和額外的練習關卡。"
|
||||||
teacher_subs_title: "教師可免費訂閱!"
|
teacher_subs_title: "教師可免費訂閱!"
|
||||||
|
@ -673,7 +673,7 @@ module.exports = nativeDescription: "繁體中文", englishDescription: "Chinese
|
||||||
under: "低於"
|
under: "低於"
|
||||||
other: "其他:"
|
other: "其他:"
|
||||||
amount_students: "請問您有多少學生需要教導?"
|
amount_students: "請問您有多少學生需要教導?"
|
||||||
hear_about: "您是怎麼知道CodeComabat的?"
|
hear_about: "您是怎麼知道CodeCombat的?"
|
||||||
fill_fields: "請填寫所有問題。"
|
fill_fields: "請填寫所有問題。"
|
||||||
thanks: "非常感謝!我們會很快寄給您設置說明。"
|
thanks: "非常感謝!我們會很快寄給您設置說明。"
|
||||||
|
|
||||||
|
@ -835,93 +835,94 @@ module.exports = nativeDescription: "繁體中文", englishDescription: "Chinese
|
||||||
last_played: "最後玩了"
|
last_played: "最後玩了"
|
||||||
leagues_explanation: "在部落裡與其他成員組成聯盟一起參加下面的多人競技場。"
|
leagues_explanation: "在部落裡與其他成員組成聯盟一起參加下面的多人競技場。"
|
||||||
|
|
||||||
# courses:
|
|
||||||
# course: "Course"
|
courses:
|
||||||
# courses: "courses"
|
course: "課程"
|
||||||
# not_enrolled: "You are not enrolled in this course."
|
courses: "課程"
|
||||||
# visit_pref: "Please visit the"
|
not_enrolled: "您没有註冊這一節課。"
|
||||||
# visit_suf: "page to enroll."
|
visit_pref: "請到這個"
|
||||||
# select_class: "Select one of your classes"
|
visit_suf: "網頁註冊。"
|
||||||
# unnamed: "*unnamed*"
|
select_class: "請選其中一門課堂"
|
||||||
# select: "Select"
|
unnamed: "*未命名*"
|
||||||
# unnamed_class: "Unnamed Class"
|
select: "選擇"
|
||||||
# edit_settings: "edit class settings"
|
unnamed_class: "課堂未命名"
|
||||||
# edit_settings1: "Edit Class Settings"
|
edit_settings: "編輯課堂設定"
|
||||||
# progress: "Class Progress"
|
edit_settings1: "編輯課堂設定"
|
||||||
# add_students: "Add Students"
|
progress: "課堂進度"
|
||||||
# stats: "Statistics"
|
add_students: "添加學生"
|
||||||
# total_students: "Total students:"
|
stats: "統計"
|
||||||
# average_time: "Average level play time:"
|
total_students: "學生人數:"
|
||||||
# total_time: "Total play time:"
|
average_time: "平均遊戲時間:"
|
||||||
# average_levels: "Average levels completed:"
|
total_time: "總計遊戲時間:"
|
||||||
# total_levels: "Total levels completed:"
|
average_levels: "平均完成關卡:"
|
||||||
# furthest_level: "Furthest level completed:"
|
total_levels: "總共完成關卡:"
|
||||||
# concepts_covered: "Concepts Covered"
|
furthest_level: "最高關卡完成:"
|
||||||
# students: "Students"
|
concepts_covered: "課目覆蓋"
|
||||||
# students1: "students"
|
students: "學生"
|
||||||
# expand_details: "Expand details"
|
students1: "個學生。"
|
||||||
# concepts: "Concepts"
|
expand_details: "展開細節"
|
||||||
# levels: "levels"
|
concepts: "課目"
|
||||||
# played: "Played"
|
levels: "關卡"
|
||||||
# play_time: "Play time:"
|
played: "已通關"
|
||||||
# completed: "Completed:"
|
play_time: "遊戲時間:"
|
||||||
# invite_students: "Invite students to join this class."
|
completed: "遊戲時間:"
|
||||||
# invite_link_header: "Link to join course"
|
invite_students: "邀請學生加入此課堂。"
|
||||||
# invite_link_p_1: "Give this link to students you would like to have join the course."
|
invite_link_header: "參與課堂的縺結"
|
||||||
# invite_link_p_2: "Or have us email them directly:"
|
invite_link_p_1: "把這個參與課堂的連結發給你認可的學生。" # there has few problem of my translation
|
||||||
# capacity_used: "Course slots used:"
|
invite_link_p_2: "或讓我們代你直接發送電郵:"
|
||||||
# enter_emails: "Enter student emails to invite, one per line"
|
capacity_used: "Course slots used:"
|
||||||
# send_invites: "Send Invites"
|
enter_emails: "輸入學生電郵地址來邀請,每行一個"
|
||||||
# title: "Title"
|
send_invites: "發送邀請"
|
||||||
# description: "Description"
|
title: "發送邀請"
|
||||||
# languages_available: "Select programming languages available to the class:"
|
description: "描述"
|
||||||
# all_lang: "All Languages"
|
languages_available: "選擇編程語言:"
|
||||||
# show_progress: "Show student progress to everyone in the class"
|
all_lang: "所有編程語言"
|
||||||
# creating_class: "Creating class..."
|
show_progress: "向所有該課堂的人展示學生的進度"
|
||||||
# purchasing_course: "Purchasing course..."
|
creating_class: "課堂創建中···"
|
||||||
# buy_course: "Buy Course"
|
purchasing_course: "購買課程中···"
|
||||||
# buy_course1: "Buy this course"
|
buy_course: "購買課程"
|
||||||
# create_class: "Create Class"
|
buy_course1: "購買這個課程"
|
||||||
# select_all_courses: "Select 'All Courses' for a 50% discount!"
|
create_class: "創建課堂"
|
||||||
# all_courses: "All Courses"
|
select_all_courses: "可半價一次購買所有課程!"
|
||||||
# number_students: "Number of students"
|
all_courses: "所有課程"
|
||||||
# enter_number_students: "Enter the number of students you need for this class."
|
number_students: "學生人數"
|
||||||
# name_class: "Name your class"
|
enter_number_students: "輪入該課堂的學生上限人數"
|
||||||
# displayed_course_page: "This will be displayed on the course page for you and your students. It can be changed later."
|
name_class: "命名您的課堂"
|
||||||
# buy: "Buy"
|
displayed_course_page: "這將會在課程頁面顯示,可被修改。"
|
||||||
# purchasing_for: "You are purchasing a license for"
|
buy: "購買"
|
||||||
# creating_for: "You are creating a class for"
|
purchasing_for: "你正在購買許可證,課程為"
|
||||||
# for: "for" # Like in 'for 30 students'
|
creating_for: "您正在創建一個課程為"
|
||||||
# receive_code: "Afterwards you will receive an unlock code to distribute to your students, which they can use to enroll in your class."
|
for: ",人數上限為" # Like in 'for 30 students'
|
||||||
# free_trial: "Free trial for teachers!"
|
receive_code: "然後您會收到一個解鎖碼,把它分發給你的學生用來註冊你的課堂。"
|
||||||
# get_access: "to get individual access to all courses for evalutaion purposes."
|
free_trial: "老師可免費試用!"
|
||||||
# questions: "Questions?"
|
get_access: "獲得個人使用權在評估目的下來使用所有課程。"
|
||||||
# faq: "Courses FAQ"
|
questions: "有疑問?"
|
||||||
# question: "Q:" # Like in 'Question'
|
faq: "課程FAQ"
|
||||||
# question1: "What's the difference between these courses and the single player game?"
|
question: "問:" # Like in 'Question'
|
||||||
# answer: "A:" # Like in 'Answer'
|
question1: "這些課程和單人遊戲之間的有什麼區別?"
|
||||||
# answer1: "The single player game is designed for individuals, while the courses are designed for classes."
|
answer: "答:" # Like in 'Answer'
|
||||||
# answer2: "The single player game has items, gems, hero selection, leveling up, and in-app purchases. Courses have classroom management features and streamlined student-focused level pacing."
|
answer1: "單人遊戲是專為個人而設,而課程是專為課堂而設。"
|
||||||
# teachers_click: "Teachers Click Here"
|
answer2: "在單人遊戲中有物品、寶石、英雄選擇、練級、和內購應用。課程有課堂管理功能,和老師可根據學生的水平而調整教學進度。"
|
||||||
# students_click: "Students Click Here"
|
teachers_click: "老師點擊這裡"
|
||||||
# courses_on_coco: "Courses on CodeCombat"
|
students_click: "學生點擊這裡"
|
||||||
# designed_to: "Courses are designed to introduce computer science concepts using CodeCombat's fun and engaging environment. CodeCombat levels are organized around key topics to encourage progressive learning, over the course of 5 hours."
|
courses_on_coco: "CodeCombat上的課程"
|
||||||
# more_in_less: "Learn more in less time"
|
designed_to: "CodeCombat課程的宗旨是在使用CodeCombat生動有趣的環境下教授計算機科學的課目。整個CodeCombat的關卡是圍繞著計算機科學的重點並激勵學生們自主向上學習在5小時的過程。"
|
||||||
# no_experience: "No coding experience necesssary"
|
more_in_less: "以最少的時間學習最多的知識"
|
||||||
# easy_monitor: "Easily monitor student progress"
|
no_experience: "無需編程經驗"
|
||||||
# purchase_for_class: "Purchase a course for your entire class. It's easy to sign up your students!"
|
easy_monitor: "容易管理學生的進程"
|
||||||
# see_the: "See the"
|
purchase_for_class: "為你的班級購買CodeCombat課程,讓簽到和管理變得更容易!"
|
||||||
# more_info: "for more information."
|
see_the: "詳細資訊請看"
|
||||||
# choose_course: "Choose Your Course:"
|
more_info: "。"
|
||||||
# enter_code: "Enter an unlock code"
|
choose_course: "選擇您的課程:"
|
||||||
# enter_code1: "Enter unlock code"
|
enter_code: "輸入一個解銷碼"
|
||||||
# enroll: "Enroll"
|
enter_code1: "輸入解銷碼"
|
||||||
# pick_from_classes: "Pick from your current classes"
|
enroll: "註冊"
|
||||||
# enter: "Enter"
|
pick_from_classes: "從目前的課程選擇"
|
||||||
# or: "Or"
|
enter: "輪入"
|
||||||
# topics: "Topics"
|
or: "或"
|
||||||
# hours_content: "Hours of content:"
|
topics: "題目"
|
||||||
# get_free: "Get FREE course"
|
hours_content: "內容時間:"
|
||||||
|
get_free: "取得免費課程!"
|
||||||
|
|
||||||
classes:
|
classes:
|
||||||
archmage_title: "大法師"
|
archmage_title: "大法師"
|
||||||
|
@ -1207,7 +1208,7 @@ module.exports = nativeDescription: "繁體中文", englishDescription: "Chinese
|
||||||
recently_played: "最近玩過"
|
recently_played: "最近玩過"
|
||||||
no_recent_games: "在過去兩個星期沒有玩過遊戲。"
|
no_recent_games: "在過去兩個星期沒有玩過遊戲。"
|
||||||
payments: "付款"
|
payments: "付款"
|
||||||
# prepaid: "Prepaid"
|
prepaid: "充值"
|
||||||
purchased: "已購買"
|
purchased: "已購買"
|
||||||
sale: "促銷"
|
sale: "促銷"
|
||||||
subscription: "訂閱"
|
subscription: "訂閱"
|
||||||
|
@ -1238,13 +1239,13 @@ module.exports = nativeDescription: "繁體中文", englishDescription: "Chinese
|
||||||
retrying: "服務器錯誤,重試中。"
|
retrying: "服務器錯誤,重試中。"
|
||||||
success: "支付成功。謝謝!"
|
success: "支付成功。謝謝!"
|
||||||
|
|
||||||
# account_prepaid:
|
account_prepaid:
|
||||||
# purchase_code: "Purchase a Subscription Code"
|
purchase_code: "購買訂閱碼"
|
||||||
# purchase_amount: "Amount"
|
purchase_amount: "數量"
|
||||||
# purchase_total: "Total"
|
purchase_total: "總共"
|
||||||
# purchase_button: "Submit Purchase"
|
purchase_button: "提交購買"
|
||||||
# your_codes: "Your Codes:"
|
your_codes: "你的訂閱碼:"
|
||||||
# redeem_codes: "Redeem a Subscription Code"
|
redeem_codes: "兌換訂閱碼"
|
||||||
|
|
||||||
loading_error:
|
loading_error:
|
||||||
could_not_load: "從伺服器載入失敗"
|
could_not_load: "從伺服器載入失敗"
|
||||||
|
@ -1258,7 +1259,7 @@ module.exports = nativeDescription: "繁體中文", englishDescription: "Chinese
|
||||||
bad_input: "錯誤輸入。"
|
bad_input: "錯誤輸入。"
|
||||||
server_error: "伺服器錯誤。"
|
server_error: "伺服器錯誤。"
|
||||||
unknown: "未知錯誤。"
|
unknown: "未知錯誤。"
|
||||||
# error: "ERROR"
|
error: "錯誤"
|
||||||
|
|
||||||
resources:
|
resources:
|
||||||
sessions: "會話"
|
sessions: "會話"
|
||||||
|
|
|
@ -25,9 +25,6 @@
|
||||||
margin-bottom: 20px
|
margin-bottom: 20px
|
||||||
font-size: 14pt
|
font-size: 14pt
|
||||||
|
|
||||||
.btn-enroll
|
|
||||||
margin-top: 20px
|
|
||||||
|
|
||||||
.center
|
.center
|
||||||
text-align: center
|
text-align: center
|
||||||
|
|
||||||
|
|
|
@ -15,24 +15,54 @@ block content
|
||||||
if state === 'unknown_error'
|
if state === 'unknown_error'
|
||||||
.alert.alert-danger.alert-dismissible= stateMessage
|
.alert.alert-danger.alert-dismissible= stateMessage
|
||||||
|
|
||||||
if studentMode
|
if hocLandingPage
|
||||||
+student-main
|
+hoc-landing
|
||||||
else
|
else
|
||||||
+teacher-main
|
if studentMode
|
||||||
.container-fluid
|
+student-main
|
||||||
- var i = 0
|
else
|
||||||
while i < courses.length
|
if hocMode
|
||||||
.row
|
+teacher-hoc
|
||||||
+course-block(courses[i], instances)
|
else
|
||||||
- i++
|
+teacher-main
|
||||||
if i < courses.length
|
.container-fluid
|
||||||
|
- var i = 0
|
||||||
|
while i < courses.length
|
||||||
|
.row
|
||||||
+course-block(courses[i], instances)
|
+course-block(courses[i], instances)
|
||||||
- i++
|
- i++
|
||||||
|
if i < courses.length
|
||||||
|
+course-block(courses[i], instances)
|
||||||
|
- i++
|
||||||
|
|
||||||
|
mixin hoc-landing
|
||||||
|
h1.center Welcome Hour of Code!
|
||||||
|
br
|
||||||
|
.container-fluid
|
||||||
|
.row
|
||||||
|
.col-md-6.center
|
||||||
|
button.btn.btn-lg.btn-success.btn-student(data-i18n="courses.students_click")
|
||||||
|
.col-md-6.center
|
||||||
|
button.btn.btn-lg.btn-default.btn-teacher(data-i18n="courses.teachers_click")
|
||||||
|
|
||||||
mixin student-main
|
mixin student-main
|
||||||
button.btn.btn-warning.btn-teacher(data-i18n="courses.teachers_click")
|
button.btn.btn-warning.btn-teacher(data-i18n="courses.teachers_click")
|
||||||
h1.center(data-i18n="courses.courses_on_coco")
|
h1.center(data-i18n="courses.courses_on_coco")
|
||||||
|
|
||||||
|
mixin teacher-hoc
|
||||||
|
button.btn.btn-warning.btn-student(data-i18n="courses.students_click")
|
||||||
|
h1.center Welcome Hour of Code!
|
||||||
|
p
|
||||||
|
strong How to use CodeCombat with your students:
|
||||||
|
ol
|
||||||
|
li Click the green 'Get FREE course' button below
|
||||||
|
li Follow the enrollment instructions
|
||||||
|
li Add students via the 'Add Students' tab
|
||||||
|
p
|
||||||
|
span.spr If you have any problems, please email
|
||||||
|
a(href='mailto:team@codecombat.com') team@codecombat.com
|
||||||
|
br
|
||||||
|
|
||||||
mixin teacher-main
|
mixin teacher-main
|
||||||
button.btn.btn-warning.btn-student(data-i18n="courses.students_click")
|
button.btn.btn-warning.btn-student(data-i18n="courses.students_click")
|
||||||
h1.center(data-i18n="courses.courses_on_coco")
|
h1.center(data-i18n="courses.courses_on_coco")
|
||||||
|
@ -87,6 +117,14 @@ mixin student-dialog(course)
|
||||||
input.code-input(type='text', data-course-id="#{course.id}", data-i18n="[placeholder]courses.enter_code1", placeholder="Enter unlock code")
|
input.code-input(type='text', data-course-id="#{course.id}", data-i18n="[placeholder]courses.enter_code1", placeholder="Enter unlock code")
|
||||||
.col-md-4
|
.col-md-4
|
||||||
button.btn.btn-success.btn-enroll(data-course-id="#{course.id}", data-i18n="courses.enroll")
|
button.btn.btn-success.btn-enroll(data-course-id="#{course.id}", data-i18n="courses.enroll")
|
||||||
|
if hocMode && course.get('pricePerSeat') === 0
|
||||||
|
.row.button-row.center.row-pick-class
|
||||||
|
.col-md-12
|
||||||
|
br
|
||||||
|
div.or(data-i18n="courses.or")
|
||||||
|
.row.button-row.center
|
||||||
|
.col-md-12
|
||||||
|
button.btn.btn-success.btn-lg.btn-hoc-student-continue(data-course-id="#{course.id}") Continue by yourself
|
||||||
|
|
||||||
mixin teacher-dialog(course)
|
mixin teacher-dialog(course)
|
||||||
.modal.continue-dialog(id="continueModal#{course.id}")
|
.modal.continue-dialog(id="continueModal#{course.id}")
|
||||||
|
|
|
@ -2,37 +2,24 @@ extends /templates/base
|
||||||
|
|
||||||
block content
|
block content
|
||||||
|
|
||||||
h2(style='color:#CC0000;') Try CodeCombat Courses!
|
h2 Hour of Code(Combat)
|
||||||
p
|
p
|
||||||
strong What are CodeCombat Courses?
|
strong Hi Teachers!
|
||||||
|
p We're excited to participate in Hour of Code this year!
|
||||||
|
p We've set up an Introduction to Computer Science course, just for you.
|
||||||
p
|
p
|
||||||
a.spr(href='/courses') Courses
|
strong How to use CodeCombat with your students:
|
||||||
span organize the same great levels into groups. They make it easier for you to manage a class of students and monitor their progress.
|
|
||||||
p
|
|
||||||
strong How to use them:
|
|
||||||
ol
|
ol
|
||||||
li
|
li
|
||||||
span.spr Navigate to the
|
span.spr Navigate to the
|
||||||
a.spr(href='/courses') Courses
|
a.spr(href='/courses/teachers?hoc=true') Courses
|
||||||
span page
|
span page
|
||||||
li Click the green 'Get FREE course' button
|
li Click the green 'Get FREE course' button under Introduction to Computer Science
|
||||||
li Follow the enrollment instructions
|
li Follow the enrollment instructions
|
||||||
li Add students via the 'Add Students' tab
|
li Add students via the 'Add Students' tab
|
||||||
p
|
p
|
||||||
strong We Need Your Help!
|
span.spr If you have any problems, please email
|
||||||
p Courses are still in early development, and we need your feedback to make them great for the classroom.
|
|
||||||
p
|
|
||||||
strong How you can help:
|
|
||||||
ul
|
|
||||||
li
|
|
||||||
spa.spr Spend 5 minutes checking out
|
|
||||||
a.spr(href='/courses') Courses
|
|
||||||
li Enroll in a course and add a student
|
|
||||||
li Monitor a group of students working through the first course
|
|
||||||
p
|
|
||||||
span.spr Send your feedback to
|
|
||||||
a(href='mailto:team@codecombat.com') team@codecombat.com
|
a(href='mailto:team@codecombat.com') team@codecombat.com
|
||||||
p Thanks!
|
|
||||||
br
|
br
|
||||||
|
|
||||||
h2 More Info for Teachers
|
h2 More Info for Teachers
|
||||||
|
|
|
@ -37,10 +37,7 @@ module.exports = class PrepaidView extends RootView
|
||||||
@updateTotal()
|
@updateTotal()
|
||||||
|
|
||||||
@codes = new CocoCollection([], { url: '/db/user/'+me.id+'/prepaid_codes', model: Prepaid })
|
@codes = new CocoCollection([], { url: '/db/user/'+me.id+'/prepaid_codes', model: Prepaid })
|
||||||
@codes.on 'add', (code) =>
|
@codes.on 'sync', (code) => @render?()
|
||||||
@render?()
|
|
||||||
@codes.on 'sync', (code) =>
|
|
||||||
@render?()
|
|
||||||
@supermodel.loadCollection(@codes, 'prepaid', {cache: false})
|
@supermodel.loadCollection(@codes, 'prepaid', {cache: false})
|
||||||
|
|
||||||
@ppc = utils.getQueryVariable('_ppc') ? ''
|
@ppc = utils.getQueryVariable('_ppc') ? ''
|
||||||
|
|
|
@ -30,7 +30,7 @@ module.exports = class TrialRequestsView extends RootView
|
||||||
-1
|
-1
|
||||||
else
|
else
|
||||||
1
|
1
|
||||||
@trialRequests = new CocoCollection([], { url: '/db/trial.request', model: TrialRequest, comparator: sortRequests })
|
@trialRequests = new CocoCollection([], { url: '/db/trial.request?conditions[sort]=-_id&conditions[limit]=500', model: TrialRequest, comparator: sortRequests })
|
||||||
@supermodel.loadCollection(@trialRequests, 'trial-requests', {cache: false})
|
@supermodel.loadCollection(@trialRequests, 'trial-requests', {cache: false})
|
||||||
|
|
||||||
getRenderData: ->
|
getRenderData: ->
|
||||||
|
|
|
@ -7,6 +7,8 @@ RootView = require 'views/core/RootView'
|
||||||
template = require 'templates/courses/courses'
|
template = require 'templates/courses/courses'
|
||||||
utils = require 'core/utils'
|
utils = require 'core/utils'
|
||||||
|
|
||||||
|
# TODO: Hour of Code (HoC) integration is a mess
|
||||||
|
|
||||||
module.exports = class CoursesView extends RootView
|
module.exports = class CoursesView extends RootView
|
||||||
id: 'courses-view'
|
id: 'courses-view'
|
||||||
template: template
|
template: template
|
||||||
|
@ -15,12 +17,15 @@ module.exports = class CoursesView extends RootView
|
||||||
'click .btn-buy': 'onClickBuy'
|
'click .btn-buy': 'onClickBuy'
|
||||||
'click .btn-enroll': 'onClickEnroll'
|
'click .btn-enroll': 'onClickEnroll'
|
||||||
'click .btn-enter': 'onClickEnter'
|
'click .btn-enter': 'onClickEnter'
|
||||||
|
'click .btn-hoc-student-continue': 'onClickHocStudentContinue'
|
||||||
'click .btn-student': 'onClickStudent'
|
'click .btn-student': 'onClickStudent'
|
||||||
'click .btn-teacher': 'onClickTeacher'
|
'click .btn-teacher': 'onClickTeacher'
|
||||||
|
|
||||||
constructor: (options) ->
|
constructor: (options) ->
|
||||||
super(options)
|
super(options)
|
||||||
@praise = utils.getCoursePraise()
|
@praise = utils.getCoursePraise()
|
||||||
|
@hocLandingPage = Backbone.history.getFragment()?.indexOf('hoc') >= 0
|
||||||
|
@hocMode = utils.getQueryVariable('hoc', false)
|
||||||
@studentMode = Backbone.history.getFragment()?.indexOf('courses/students') >= 0
|
@studentMode = Backbone.history.getFragment()?.indexOf('courses/students') >= 0
|
||||||
@courses = new CocoCollection([], { url: "/db/course", model: Course})
|
@courses = new CocoCollection([], { url: "/db/course", model: Course})
|
||||||
@supermodel.loadCollection(@courses, 'courses')
|
@supermodel.loadCollection(@courses, 'courses')
|
||||||
|
@ -38,6 +43,8 @@ module.exports = class CoursesView extends RootView
|
||||||
context = super()
|
context = super()
|
||||||
context.courses = @courses.models ? []
|
context.courses = @courses.models ? []
|
||||||
context.enrolledCourses = @enrolledCourses ? {}
|
context.enrolledCourses = @enrolledCourses ? {}
|
||||||
|
context.hocLandingPage = @hocLandingPage
|
||||||
|
context.hocMode = @hocMode
|
||||||
context.instances = @courseInstances.models ? []
|
context.instances = @courseInstances.models ? []
|
||||||
context.praise = @praise
|
context.praise = @praise
|
||||||
context.state = @state
|
context.state = @state
|
||||||
|
@ -95,14 +102,58 @@ module.exports = class CoursesView extends RootView
|
||||||
navigationEvent = route: route, viewClass: viewClass, viewArgs: viewArgs
|
navigationEvent = route: route, viewClass: viewClass, viewArgs: viewArgs
|
||||||
Backbone.Mediator.publish 'router:navigate', navigationEvent
|
Backbone.Mediator.publish 'router:navigate', navigationEvent
|
||||||
|
|
||||||
|
onClickHocStudentContinue: (e) ->
|
||||||
|
$('.continue-dialog').modal('hide')
|
||||||
|
return @openModalView new AuthModal() if me.isAnonymous()
|
||||||
|
courseID = $(e.target).data('course-id')
|
||||||
|
|
||||||
|
@state = 'enrolling'
|
||||||
|
@stateMessage = undefined
|
||||||
|
@render?()
|
||||||
|
|
||||||
|
# TODO: Copied from CourseEnrollView
|
||||||
|
|
||||||
|
data =
|
||||||
|
name: 'Single Player'
|
||||||
|
seats: 9999
|
||||||
|
courseID: courseID
|
||||||
|
jqxhr = $.post('/db/course_instance/-/create', data)
|
||||||
|
jqxhr.done (data, textStatus, jqXHR) =>
|
||||||
|
application.tracker?.trackEvent 'Finished HoC student course creation', {courseID: courseID}
|
||||||
|
# TODO: handle fetch errors
|
||||||
|
me.fetch(cache: false).always =>
|
||||||
|
courseID = courseID
|
||||||
|
route = "/courses/#{courseID}"
|
||||||
|
viewArgs = [{}, courseID]
|
||||||
|
if data?.length > 0
|
||||||
|
courseInstanceID = data[0]._id
|
||||||
|
route += "/#{courseInstanceID}"
|
||||||
|
viewArgs[0].courseInstanceID = courseInstanceID
|
||||||
|
Backbone.Mediator.publish 'router:navigate',
|
||||||
|
route: route
|
||||||
|
viewClass: 'views/courses/CourseDetailsView'
|
||||||
|
viewArgs: viewArgs
|
||||||
|
jqxhr.fail (xhr, textStatus, errorThrown) =>
|
||||||
|
console.error 'Got an error purchasing a course:', textStatus, errorThrown
|
||||||
|
application.tracker?.trackEvent 'Failed HoC student course creation', status: textStatus
|
||||||
|
if xhr.status is 402
|
||||||
|
@state = 'declined'
|
||||||
|
@stateMessage = arguments[2]
|
||||||
|
else
|
||||||
|
@state = 'unknown_error'
|
||||||
|
@stateMessage = "#{xhr.status}: #{xhr.responseText}"
|
||||||
|
@render?()
|
||||||
|
|
||||||
onClickStudent: (e) ->
|
onClickStudent: (e) ->
|
||||||
route = "/courses/students"
|
route = "/courses/students"
|
||||||
|
route += "?hoc=true" if @hocLandingPage or @hocMode
|
||||||
viewClass = require 'views/courses/CoursesView'
|
viewClass = require 'views/courses/CoursesView'
|
||||||
navigationEvent = route: route, viewClass: viewClass, viewArgs: []
|
navigationEvent = route: route, viewClass: viewClass, viewArgs: []
|
||||||
Backbone.Mediator.publish 'router:navigate', navigationEvent
|
Backbone.Mediator.publish 'router:navigate', navigationEvent
|
||||||
|
|
||||||
onClickTeacher: (e) ->
|
onClickTeacher: (e) ->
|
||||||
route = "/courses/teachers"
|
route = "/courses/teachers"
|
||||||
|
route += "?hoc=true" if @hocLandingPage or @hocMode
|
||||||
viewClass = require 'views/courses/CoursesView'
|
viewClass = require 'views/courses/CoursesView'
|
||||||
navigationEvent = route: route, viewClass: viewClass, viewArgs: []
|
navigationEvent = route: route, viewClass: viewClass, viewArgs: []
|
||||||
Backbone.Mediator.publish 'router:navigate', navigationEvent
|
Backbone.Mediator.publish 'router:navigate', navigationEvent
|
||||||
|
|
|
@ -179,21 +179,18 @@ module.exports = class Handler
|
||||||
# if it's not a text search but the user is an admin, let him try stuff anyway
|
# if it's not a text search but the user is an admin, let him try stuff anyway
|
||||||
else if req.user?.isAdmin()
|
else if req.user?.isAdmin()
|
||||||
# admins can send any sort of query down the wire
|
# admins can send any sort of query down the wire
|
||||||
|
# Example URL: http://localhost:3000/db/user?filter[anonymous]=true
|
||||||
filter = {}
|
filter = {}
|
||||||
filter[key] = (val for own key, val of req.query.filter when key not in specialParameters) if 'filter' of req.query
|
filter[key] = JSON.parse(val) for own key, val of req.query.filter when key not in specialParameters if 'filter' of req.query
|
||||||
|
|
||||||
query = @modelClass.find(filter)
|
query = @modelClass.find(filter)
|
||||||
|
|
||||||
# Conditions are chained query functions, for example: query.find().limit(20).sort('-dateCreated')
|
# Conditions are chained query functions, for example: query.find().limit(20).sort('-dateCreated')
|
||||||
conditions = JSON.parse(req.query.conditions || '[]')
|
# Example URL: http://localhost:3000/db/user?conditions[limit]=20&conditions[sort]=-dateCreated
|
||||||
hasLimit = false
|
hasLimit = false
|
||||||
try
|
try
|
||||||
for condition in conditions
|
for own key, val of req.query.conditions
|
||||||
name = condition[0]
|
query = query[key](val)
|
||||||
f = query[name]
|
hasLimit ||= key is 'limit'
|
||||||
args = condition[1..]
|
|
||||||
query = query[name](args...)
|
|
||||||
hasLimit ||= f is 'limit'
|
|
||||||
catch e
|
catch e
|
||||||
return @sendError(res, 422, 'Badly formed conditions.')
|
return @sendError(res, 422, 'Badly formed conditions.')
|
||||||
query.limit(2000) unless hasLimit
|
query.limit(2000) unless hasLimit
|
||||||
|
|
|
@ -53,7 +53,6 @@ config.mail =
|
||||||
username: process.env.COCO_MAIL_SERVICE_USERNAME or ''
|
username: process.env.COCO_MAIL_SERVICE_USERNAME or ''
|
||||||
supportPrimary: process.env.COCO_MAIL_SUPPORT_PRIMARY or ''
|
supportPrimary: process.env.COCO_MAIL_SUPPORT_PRIMARY or ''
|
||||||
supportPremium: process.env.COCO_MAIL_SUPPORT_PREMIUM or ''
|
supportPremium: process.env.COCO_MAIL_SUPPORT_PREMIUM or ''
|
||||||
username: process.env.COCO_MAIL_SERVICE_USERNAME or ''
|
|
||||||
mailchimpAPIKey: process.env.COCO_MAILCHIMP_API_KEY or ''
|
mailchimpAPIKey: process.env.COCO_MAILCHIMP_API_KEY or ''
|
||||||
mailchimpWebhook: process.env.COCO_MAILCHIMP_WEBHOOK or '/mail/webhook'
|
mailchimpWebhook: process.env.COCO_MAILCHIMP_WEBHOOK or '/mail/webhook'
|
||||||
sendwithusAPIKey: process.env.COCO_SENDWITHUS_API_KEY or ''
|
sendwithusAPIKey: process.env.COCO_SENDWITHUS_API_KEY or ''
|
||||||
|
|
|
@ -86,7 +86,6 @@ setupCountryRedirectMiddleware = (app, country="china", countryCode="CN", langua
|
||||||
ip = req.headers['x-forwarded-for'] or req.connection.remoteAddress
|
ip = req.headers['x-forwarded-for'] or req.connection.remoteAddress
|
||||||
ip = ip?.split(/,? /)[0] # If there are two IP addresses, say because of CloudFlare, we just take the first.
|
ip = ip?.split(/,? /)[0] # If there are two IP addresses, say because of CloudFlare, we just take the first.
|
||||||
geo = geoip.lookup(ip)
|
geo = geoip.lookup(ip)
|
||||||
geo = country: 'CN'
|
|
||||||
#if speaksLanguage or geo?.country is countryCode
|
#if speaksLanguage or geo?.country is countryCode
|
||||||
# log.info("Should we redirect to #{serverID} server? speaksLanguage: #{speaksLanguage}, firstLanguage: #{firstLanguage}, ip: #{ip}, geo: #{geo} -- so redirecting? #{geo?.country is 'CN' and speaksLanguage}")
|
# log.info("Should we redirect to #{serverID} server? speaksLanguage: #{speaksLanguage}, firstLanguage: #{firstLanguage}, ip: #{ip}, geo: #{geo} -- so redirecting? #{geo?.country is 'CN' and speaksLanguage}")
|
||||||
return geo?.country is countryCode and speaksLanguage
|
return geo?.country is countryCode and speaksLanguage
|
||||||
|
|
|
@ -269,20 +269,10 @@ describe 'GET /db/user', ->
|
||||||
expect(body.type).toBeDefined()
|
expect(body.type).toBeDefined()
|
||||||
done()
|
done()
|
||||||
|
|
||||||
it 'is able to do a sweet query', (done) ->
|
it 'is able to do a semi-sweet query', (done) ->
|
||||||
conditions = [
|
|
||||||
['limit', 20]
|
|
||||||
['where', 'email']
|
|
||||||
['equals', 'admin@afc.com']
|
|
||||||
['sort', '-dateCreated']
|
|
||||||
]
|
|
||||||
options = {
|
options = {
|
||||||
url: getURL(urlUser)
|
url: getURL(urlUser) + "?conditions[limit]=20&conditions[sort]=-dateCreated"
|
||||||
qs: {
|
|
||||||
conditions: JSON.stringify(conditions)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
req = request.get(options, (error, response) ->
|
req = request.get(options, (error, response) ->
|
||||||
expect(response.statusCode).toBe(200)
|
expect(response.statusCode).toBe(200)
|
||||||
res = JSON.parse(response.body)
|
res = JSON.parse(response.body)
|
||||||
|
@ -291,14 +281,8 @@ describe 'GET /db/user', ->
|
||||||
)
|
)
|
||||||
|
|
||||||
it 'rejects bad conditions', (done) ->
|
it 'rejects bad conditions', (done) ->
|
||||||
conditions = [
|
|
||||||
['lime', 20]
|
|
||||||
]
|
|
||||||
options = {
|
options = {
|
||||||
url: getURL(urlUser)
|
url: getURL(urlUser) + "?conditions[lime]=20&conditions[sort]=-dateCreated"
|
||||||
qs: {
|
|
||||||
conditions: JSON.stringify(conditions)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
req = request.get(options, (error, response) ->
|
req = request.get(options, (error, response) ->
|
||||||
|
|
Loading…
Reference in a new issue